/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
static PRBool IsValidNetAddrLen(const PRNetAddr* addr, PRInt32 addr_len) { /* * The definition of the length of a Unix domain socket address * is not uniform, so we don't check it.
*/ if ((addr != NULL) # ifdefined(XP_UNIX)
&& (addr->raw.family != AF_UNIX) # endif
&& (PR_NETADDR_SIZE(addr) != addr_len)) { # ifdefined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1 /* * In glibc 2.1, struct sockaddr_in6 is 24 bytes. In glibc 2.2 * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id * field and is 28 bytes. It is possible for socket functions * to return an addr_len greater than sizeof(struct sockaddr_in6). * We need to allow that. (Bugzilla bug #77264)
*/ if ((PR_AF_INET6 == addr->raw.family) && (sizeof(addr->ipv6) == addr_len)) { return PR_TRUE;
} # endif /* * The accept(), getsockname(), etc. calls on some platforms * do not set the actual socket address length on return. * In this case, we verifiy addr_len is still the value we * passed in (i.e., sizeof(PRNetAddr)).
*/ # ifdefined(QNX) if (sizeof(PRNetAddr) == addr_len) { return PR_TRUE;
} # endif return PR_FALSE;
} return PR_TRUE;
}
#endif/* DEBUG */
static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc* fd, const PRIOVec* iov,
PRInt32 iov_size,
PRIntervalTime timeout) {
PRThread* me = _PR_MD_CURRENT_THREAD(); int w = 0; const PRIOVec* tmp_iov; #define LOCAL_MAXIOV 8
PRIOVec local_iov[LOCAL_MAXIOV];
PRIOVec* iov_copy = NULL; int tmp_out; int index, iov_cnt; int count = 0, sz = 0; /* 'count' is the return value. */
if (_PR_PENDING_INTERRUPT(me)) {
me->flags &= ~_PR_INTERRUPT;
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1;
} if (_PR_IO_PENDING(me)) {
PR_SetError(PR_IO_PENDING_ERROR, 0); return -1;
}
/* * Assume the first writev will succeed. Copy iov's only on * failure.
*/
tmp_iov = iov; for (index = 0; index < iov_size; index++) {
sz += iov[index].iov_len;
}
iov_cnt = iov_size;
while (sz > 0) {
w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout); if (w < 0) {
count = -1; break;
}
count += w; if (fd->secret->nonblocking) { break;
}
sz -= w;
if (sz > 0) { /* find the next unwritten vector */ for (index = 0, tmp_out = count; tmp_out >= iov[index].iov_len;
tmp_out -= iov[index].iov_len, index++) {
;
} /* nothing to execute */
if (tmp_iov == iov) { /* * The first writev failed so we * must copy iov's around. * Avoid calloc/free if there * are few enough iov's.
*/ if (iov_size - index <= LOCAL_MAXIOV) {
iov_copy = local_iov;
} elseif ((iov_copy = (PRIOVec*)PR_CALLOC((iov_size - index) * sizeof *iov_copy)) == NULL) {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return -1;
}
tmp_iov = iov_copy;
}
PR_ASSERT(tmp_iov == iov_copy);
/* fill in the first partial read */
iov_copy[0].iov_base = &(((char*)iov[index].iov_base)[tmp_out]);
iov_copy[0].iov_len = iov[index].iov_len - tmp_out;
index++;
/* copy the remaining vectors */ for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) {
iov_copy[iov_cnt].iov_base = iov[index].iov_base;
iov_copy[iov_cnt].iov_len = iov[index].iov_len;
}
}
}
if (iov_copy != local_iov) {
PR_DELETE(iov_copy);
} return count;
}
if (!_pr_initialized) {
_PR_ImplicitInitialization();
}
fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods()); if (fd != NULL) {
_PR_MD_MAKE_NONBLOCK(fd);
_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE); #ifdef _PR_NEED_SECRET_AF /* this means we can only import IPv4 sockets here. * but this is what the function in ptio.c does. * We need a way to import IPv6 sockets, too.
*/
fd->secret->af = AF_INET; #endif
} else {
_PR_MD_CLOSE_SOCKET(osfd);
} return (fd);
}
if (out_flags & PR_POLL_EXCEPT) { int len = sizeof(err); if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char*)&err, &len) ==
SOCKET_ERROR) {
_PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); return PR_FAILURE;
} if (err != 0) {
_PR_MD_MAP_CONNECT_ERROR(err);
} else { # ifdefined(_WIN64) if (fd->secret->overlappedActive) {
PRInt32 rvSent; if (GetOverlappedResult((HANDLE)osfd, &fd->secret->ol, &rvSent, FALSE) == FALSE) {
err = WSAGetLastError();
PR_LOG(
_pr_io_lm, PR_LOG_MIN,
("SocketConnectContinue GetOverlappedResult failed %d\n", err)); if (err != ERROR_IO_INCOMPLETE) {
_PR_MD_MAP_CONNECT_ERROR(err);
fd->secret->overlappedActive = PR_FALSE;
}
}
} if (err == 0) {
PR_SetError(PR_UNKNOWN_ERROR, 0);
} # else
PR_SetError(PR_UNKNOWN_ERROR, 0); # endif
} return PR_FAILURE;
}
PR_ASSERT(out_flags & PR_POLL_WRITE);
# ifdefined(_WIN64) if (fd->secret->alreadyConnected) {
fd->secret->alreadyConnected = PR_FALSE;
} /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped * input/output.
* To get result we need to use GetOverlappedResult. */ if (fd->secret->overlappedActive) {
PR_ASSERT(fd->secret->nonblocking);
PRInt32 rvSent; if (GetOverlappedResult((HANDLE)osfd, &fd->secret->ol, &rvSent, FALSE) == TRUE) {
fd->secret->overlappedActive = PR_FALSE;
PR_LOG(_pr_io_lm, PR_LOG_MIN,
("SocketConnectContinue GetOverlappedResult succeeded\n")); /* When ConnectEx is used, all previously set socket options and * property are not enabled and to enable them
* SO_UPDATE_CONNECT_CONTEXT option need to be set. */ if (setsockopt((SOCKET)osfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL,
0) != 0) {
err = WSAGetLastError();
PR_LOG(_pr_io_lm, PR_LOG_MIN,
("SocketConnectContinue setting SO_UPDATE_CONNECT_CONTEXT " "failed %d\n",
err));
_PR_MD_MAP_SETSOCKOPT_ERROR(err); return PR_FAILURE;
} return PR_SUCCESS;
} else {
err = WSAGetLastError();
PR_LOG(_pr_io_lm, PR_LOG_MIN,
("SocketConnectContinue GetOverlappedResult failed %d\n", err)); if (err != ERROR_IO_INCOMPLETE) {
_PR_MD_MAP_CONNECT_ERROR(err);
fd->secret->overlappedActive = PR_FALSE; return PR_FAILURE;
} else {
PR_SetError(PR_IN_PROGRESS_ERROR, 0); return PR_FAILURE;
}
}
} # endif
fd2->secret->nonblocking = fd->secret->nonblocking;
fd2->secret->inheritable = fd->secret->inheritable; #ifdef WINNT if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) { /* * The new socket has been associated with an I/O * completion port. There is no going back.
*/
fd2->secret->md.io_model_committed = PR_TRUE;
}
PR_ASSERT(al == PR_NETADDR_SIZE(addr));
fd2->secret->md.accepted_socket = PR_TRUE;
memcpy(&fd2->secret->md.peer_addr, addr, al); #endif
/* * On some platforms, the new socket created by accept() * inherits the nonblocking (or overlapped io) attribute * of the listening socket. As an optimization, these * platforms can skip the following _PR_MD_MAKE_NONBLOCK * call.
*/ #if !defined(SOLARIS) && !defined(WINNT)
_PR_MD_MAKE_NONBLOCK(fd2); #endif
if (fd->secret->state == _PR_FILEDESC_OPEN) { #ifdefined(_WIN64) && defined(WIN95) /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped * input/output. Before closing such a socket we must cancelIO.
*/ if (fd->secret->overlappedActive) {
PR_ASSERT(fd->secret->nonblocking); if (CancelIo((HANDLE)fd->secret->md.osfd) == TRUE) {
PR_LOG(_pr_io_lm, PR_LOG_MIN, ("SocketClose - CancelIo succeeded\n"));
} else {
DWORD err = WSAGetLastError();
PR_LOG(_pr_io_lm, PR_LOG_MIN,
("SocketClose - CancelIo failed err=%x\n", err));
}
if (fd->secret->overlappedActive && _fd_waiting_for_overlapped_done_lock) { // Put osfd into the list to be checked later.
PRFileDescList* forWaiting = PR_NEW(PRFileDescList); if (!forWaiting) {
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return PR_FAILURE;
}
forWaiting->fd = fd;
if (_PR_PENDING_INTERRUPT(me)) {
me->flags &= ~_PR_INTERRUPT;
PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); return -1;
} if (_PR_IO_PENDING(me)) {
PR_SetError(PR_IO_PENDING_ERROR, 0); return -1;
} /* The socket must be in blocking mode. */ if (sd->secret->nonblocking) {
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return -1;
} #ifdefined(WINNT)
rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout); if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) { /* * This should be kept the same as SocketClose, except * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should * not be called because the socket will be recycled.
*/
PR_FreeFileDesc(sd);
} #else
rv = PR_EmulateSendFile(sd, sfd, flags, timeout); #endif/* WINNT */
f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods()); if (!f[0]) {
_PR_MD_CLOSE_SOCKET(osfd[0]);
_PR_MD_CLOSE_SOCKET(osfd[1]); /* PR_AllocFileDesc() has invoked PR_SetError(). */ return PR_FAILURE;
}
f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods()); if (!f[1]) {
PR_Close(f[0]);
_PR_MD_CLOSE_SOCKET(osfd[1]); /* PR_AllocFileDesc() has invoked PR_SetError(). */ return PR_FAILURE;
}
_PR_MD_MAKE_NONBLOCK(f[0]);
_PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
_PR_MD_MAKE_NONBLOCK(f[1]);
_PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE); return PR_SUCCESS; #elifdefined(WINNT) /* * A socket pair is often used for interprocess communication, * so we need to make sure neither socket is associated with * the I/O completion port; otherwise it can't be used by a * child process. * * The default implementation below cannot be used for NT * because PR_Accept would have associated the I/O completion * port with the listening and accepted sockets.
*/
SOCKET listenSock;
SOCKET osfd[2]; struct sockaddr_in selfAddr, peerAddr; int addrLen;
if (!_pr_initialized) {
_PR_ImplicitInitialization();
}
/* * Only a thread is used to do the connect and accept. * I am relying on the fact that connect returns * successfully as soon as the connect request is put * into the listen queue (but before accept is called). * This is the behavior of the BSD socket code. If * connect does not return until accept is called, we * will need to create another thread to call connect.
*/ if (connect(osfd[0], (struct sockaddr*)&selfAddr, addrLen) == SOCKET_ERROR) { goto failed;
} /* * A malicious local process may connect to the listening * socket, so we need to verify that the accepted connection * is made from our own socket osfd[0].
*/ if (getsockname(osfd[0], (struct sockaddr*)&selfAddr, &addrLen) ==
SOCKET_ERROR) { goto failed;
}
osfd[1] = accept(listenSock, (struct sockaddr*)&peerAddr, &addrLen); if (osfd[1] == INVALID_SOCKET) { goto failed;
} if (peerAddr.sin_port != selfAddr.sin_port) { /* the connection we accepted is not from osfd[0] */
PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); goto failed;
}
closesocket(listenSock);
failed: if (listenSock != INVALID_SOCKET) {
closesocket(listenSock);
} if (osfd[0] != INVALID_SOCKET) {
closesocket(osfd[0]);
} if (osfd[1] != INVALID_SOCKET) {
closesocket(osfd[1]);
} return PR_FAILURE; #else/* not Unix or NT */ /* * default implementation
*/
PRFileDesc* listenSock;
PRNetAddr selfAddr, peerAddr;
PRUint16 port;
f[0] = f[1] = NULL;
listenSock = PR_NewTCPSocket(); if (listenSock == NULL) { goto failed;
}
PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */ if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) { goto failed;
} if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) { goto failed;
}
port = ntohs(selfAddr.inet.port); if (PR_Listen(listenSock, 5) == PR_FAILURE) { goto failed;
}
f[0] = PR_NewTCPSocket(); if (f[0] == NULL) { goto failed;
} # ifdef _PR_CONNECT_DOES_NOT_BIND /* * If connect does not implicitly bind the socket (e.g., on * BeOS), we have to bind the socket so that we can get its * port with getsockname later.
*/
PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) { goto failed;
} # endif
PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
/* * Only a thread is used to do the connect and accept. * I am relying on the fact that PR_Connect returns * successfully as soon as the connect request is put * into the listen queue (but before PR_Accept is called). * This is the behavior of the BSD socket code. If * connect does not return until accept is called, we * will need to create another thread to call connect.
*/ if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { goto failed;
} /* * A malicious local process may connect to the listening * socket, so we need to verify that the accepted connection * is made from our own socket f[0].
*/ if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) { goto failed;
}
f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT); if (f[1] == NULL) { goto failed;
} if (peerAddr.inet.port != selfAddr.inet.port) { /* the connection we accepted is not from f[0] */
PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0); goto failed;
}
PR_Close(listenSock); return PR_SUCCESS;
failed: if (listenSock) {
PR_Close(listenSock);
} if (f[0]) {
PR_Close(f[0]);
} if (f[1]) {
PR_Close(f[1]);
} return PR_FAILURE; #endif
}
PR_IMPLEMENT(PRInt32)
PR_Select(PRInt32 unused, PR_fd_set* pr_rd, PR_fd_set* pr_wr, PR_fd_set* pr_ex,
PRIntervalTime timeout) { #if !defined(NEED_SELECT)
PRInt32 npds = 0; /* ** Find out how many fds are represented in the three lists. ** Then allocate a polling descriptor for the logical union ** (there can't be any overlapping) and call PR_Poll().
*/
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.