nsprpub/pr/src/io/prsocket.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/nsprpub/pr/src/io/prsocket.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1794 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "primpl.h"
    1.10 +
    1.11 +#include <string.h>
    1.12 +
    1.13 +/************************************************************************/
    1.14 +
    1.15 +/* These two functions are only used in assertions. */
    1.16 +#if defined(DEBUG)
    1.17 +
    1.18 +PRBool IsValidNetAddr(const PRNetAddr *addr)
    1.19 +{
    1.20 +    if ((addr != NULL)
    1.21 +#if defined(XP_UNIX) || defined(XP_OS2)
    1.22 +	    && (addr->raw.family != PR_AF_LOCAL)
    1.23 +#endif
    1.24 +	    && (addr->raw.family != PR_AF_INET6)
    1.25 +	    && (addr->raw.family != PR_AF_INET)) {
    1.26 +        return PR_FALSE;
    1.27 +    }
    1.28 +    return PR_TRUE;
    1.29 +}
    1.30 +
    1.31 +static PRBool IsValidNetAddrLen(const PRNetAddr *addr, PRInt32 addr_len)
    1.32 +{
    1.33 +    /*
    1.34 +     * The definition of the length of a Unix domain socket address
    1.35 +     * is not uniform, so we don't check it.
    1.36 +     */
    1.37 +    if ((addr != NULL)
    1.38 +#if defined(XP_UNIX) || defined(XP_OS2)
    1.39 +            && (addr->raw.family != AF_UNIX)
    1.40 +#endif
    1.41 +            && (PR_NETADDR_SIZE(addr) != addr_len)) {
    1.42 +#if defined(LINUX) && __GLIBC__ == 2 && __GLIBC_MINOR__ == 1
    1.43 +        /*
    1.44 +         * In glibc 2.1, struct sockaddr_in6 is 24 bytes.  In glibc 2.2
    1.45 +         * and in the 2.4 kernel, struct sockaddr_in6 has the scope_id
    1.46 +         * field and is 28 bytes.  It is possible for socket functions
    1.47 +         * to return an addr_len greater than sizeof(struct sockaddr_in6).
    1.48 +         * We need to allow that.  (Bugzilla bug #77264)
    1.49 +         */
    1.50 +        if ((PR_AF_INET6 == addr->raw.family)
    1.51 +                && (sizeof(addr->ipv6) == addr_len)) {
    1.52 +            return PR_TRUE;
    1.53 +        }
    1.54 +#endif
    1.55 +        /*
    1.56 +         * The accept(), getsockname(), etc. calls on some platforms
    1.57 +         * do not set the actual socket address length on return.
    1.58 +         * In this case, we verifiy addr_len is still the value we
    1.59 +         * passed in (i.e., sizeof(PRNetAddr)).
    1.60 +         */
    1.61 +#if defined(QNX)
    1.62 +        if (sizeof(PRNetAddr) == addr_len) {
    1.63 +            return PR_TRUE;
    1.64 +        }
    1.65 +#endif
    1.66 +        return PR_FALSE;
    1.67 +    }
    1.68 +    return PR_TRUE;
    1.69 +}
    1.70 +
    1.71 +#endif /* DEBUG */
    1.72 +
    1.73 +static PRInt32 PR_CALLBACK SocketWritev(PRFileDesc *fd, const PRIOVec *iov,
    1.74 +PRInt32 iov_size, PRIntervalTime timeout)
    1.75 +{
    1.76 +	PRThread *me = _PR_MD_CURRENT_THREAD();
    1.77 +	int w = 0;
    1.78 +	const PRIOVec *tmp_iov;
    1.79 +#define LOCAL_MAXIOV    8
    1.80 +	PRIOVec local_iov[LOCAL_MAXIOV];
    1.81 +	PRIOVec *iov_copy = NULL;
    1.82 +	int tmp_out;
    1.83 +	int index, iov_cnt;
    1.84 +	int count=0, sz = 0;    /* 'count' is the return value. */
    1.85 +
    1.86 +	if (_PR_PENDING_INTERRUPT(me)) {
    1.87 +		me->flags &= ~_PR_INTERRUPT;
    1.88 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
    1.89 +		return -1;
    1.90 +	}
    1.91 +	if (_PR_IO_PENDING(me)) {
    1.92 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
    1.93 +		return -1;
    1.94 +	}
    1.95 +
    1.96 +    /*
    1.97 +     * Assume the first writev will succeed.  Copy iov's only on
    1.98 +     * failure.
    1.99 +     */
   1.100 +    tmp_iov = iov;
   1.101 +    for (index = 0; index < iov_size; index++)
   1.102 +        sz += iov[index].iov_len;
   1.103 +
   1.104 +	iov_cnt = iov_size;
   1.105 +
   1.106 +	while (sz > 0) {
   1.107 +
   1.108 +		w = _PR_MD_WRITEV(fd, tmp_iov, iov_cnt, timeout);
   1.109 +		if (w < 0) {
   1.110 +			count = -1;
   1.111 +			break;
   1.112 +		}
   1.113 +		count += w;
   1.114 +		if (fd->secret->nonblocking) {
   1.115 +			break;
   1.116 +		}
   1.117 +		sz -= w;
   1.118 +
   1.119 +		if (sz > 0) {
   1.120 +			/* find the next unwritten vector */
   1.121 +			for ( index = 0, tmp_out = count;
   1.122 +				tmp_out >= iov[index].iov_len;
   1.123 +				tmp_out -= iov[index].iov_len, index++){;} /* nothing to execute */
   1.124 +
   1.125 +			if (tmp_iov == iov) {
   1.126 +				/*
   1.127 +				 * The first writev failed so we
   1.128 +				 * must copy iov's around.
   1.129 +				 * Avoid calloc/free if there
   1.130 +				 * are few enough iov's.
   1.131 +				 */
   1.132 +				if (iov_size - index <= LOCAL_MAXIOV)
   1.133 +					iov_copy = local_iov;
   1.134 +				else if ((iov_copy = (PRIOVec *) PR_CALLOC((iov_size - index) *
   1.135 +					sizeof *iov_copy)) == NULL) {
   1.136 +					PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.137 +					return -1;
   1.138 +				}
   1.139 +				tmp_iov = iov_copy;
   1.140 +			}
   1.141 +
   1.142 +			PR_ASSERT(tmp_iov == iov_copy);
   1.143 +
   1.144 +			/* fill in the first partial read */
   1.145 +			iov_copy[0].iov_base = &(((char *)iov[index].iov_base)[tmp_out]);
   1.146 +			iov_copy[0].iov_len = iov[index].iov_len - tmp_out;
   1.147 +			index++;
   1.148 +
   1.149 +			/* copy the remaining vectors */
   1.150 +			for (iov_cnt=1; index<iov_size; iov_cnt++, index++) {
   1.151 +				iov_copy[iov_cnt].iov_base = iov[index].iov_base;
   1.152 +				iov_copy[iov_cnt].iov_len = iov[index].iov_len;
   1.153 +			}
   1.154 +		}
   1.155 +	}
   1.156 +
   1.157 +	if (iov_copy != local_iov)
   1.158 +		PR_DELETE(iov_copy);
   1.159 +	return count;
   1.160 +}
   1.161 +
   1.162 +/************************************************************************/
   1.163 +
   1.164 +PR_IMPLEMENT(PRFileDesc *) PR_ImportTCPSocket(PROsfd osfd)
   1.165 +{
   1.166 +PRFileDesc *fd;
   1.167 +
   1.168 +	if (!_pr_initialized) _PR_ImplicitInitialization();
   1.169 +	fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
   1.170 +	if (fd != NULL) {
   1.171 +		_PR_MD_MAKE_NONBLOCK(fd);
   1.172 +		_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
   1.173 +#ifdef _PR_NEED_SECRET_AF
   1.174 +		/* this means we can only import IPv4 sockets here.
   1.175 +		 * but this is what the function in ptio.c does.
   1.176 +		 * We need a way to import IPv6 sockets, too.
   1.177 +		 */
   1.178 +		fd->secret->af = AF_INET;
   1.179 +#endif
   1.180 +	} else
   1.181 +		_PR_MD_CLOSE_SOCKET(osfd);
   1.182 +	return(fd);
   1.183 +}
   1.184 +
   1.185 +PR_IMPLEMENT(PRFileDesc *) PR_ImportUDPSocket(PROsfd osfd)
   1.186 +{
   1.187 +PRFileDesc *fd;
   1.188 +
   1.189 +	if (!_pr_initialized) _PR_ImplicitInitialization();
   1.190 +	fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
   1.191 +	if (fd != NULL) {
   1.192 +		_PR_MD_MAKE_NONBLOCK(fd);
   1.193 +		_PR_MD_INIT_FD_INHERITABLE(fd, PR_TRUE);
   1.194 +	} else
   1.195 +		_PR_MD_CLOSE_SOCKET(osfd);
   1.196 +	return(fd);
   1.197 +}
   1.198 +
   1.199 +
   1.200 +static const PRIOMethods* PR_GetSocketPollFdMethods(void);
   1.201 +
   1.202 +PR_IMPLEMENT(PRFileDesc*) PR_CreateSocketPollFd(PROsfd osfd)
   1.203 +{
   1.204 +    PRFileDesc *fd;
   1.205 +
   1.206 +    if (!_pr_initialized) _PR_ImplicitInitialization();
   1.207 +
   1.208 +    fd = _PR_Getfd();
   1.209 +
   1.210 +    if (fd == NULL) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.211 +    else
   1.212 +    {
   1.213 +        fd->secret->md.osfd = osfd;
   1.214 +        fd->secret->inheritable = _PR_TRI_FALSE;
   1.215 +    	fd->secret->state = _PR_FILEDESC_OPEN;
   1.216 +        fd->methods = PR_GetSocketPollFdMethods();
   1.217 +    }
   1.218 +
   1.219 +    return fd;
   1.220 +}  /* PR_CreateSocketPollFD */
   1.221 +
   1.222 +PR_IMPLEMENT(PRStatus) PR_DestroySocketPollFd(PRFileDesc *fd)
   1.223 +{
   1.224 +    if (NULL == fd)
   1.225 +    {
   1.226 +        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
   1.227 +        return PR_FAILURE;
   1.228 +    }
   1.229 +    fd->secret->state = _PR_FILEDESC_CLOSED;
   1.230 +    _PR_Putfd(fd);
   1.231 +    return PR_SUCCESS;
   1.232 +}  /* PR_DestroySocketPollFd */
   1.233 +
   1.234 +static PRStatus PR_CALLBACK SocketConnect(
   1.235 +    PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
   1.236 +{
   1.237 +	PRInt32 rv;    /* Return value of _PR_MD_CONNECT */
   1.238 +    const PRNetAddr *addrp = addr;
   1.239 +#if defined(_PR_INET6)
   1.240 +	PRNetAddr addrCopy;
   1.241 +#endif
   1.242 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.243 +
   1.244 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.245 +		me->flags &= ~_PR_INTERRUPT;
   1.246 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.247 +		return PR_FAILURE;
   1.248 +	}
   1.249 +#if defined(_PR_INET6)
   1.250 +	if (addr->raw.family == PR_AF_INET6) {
   1.251 +		addrCopy = *addr;
   1.252 +		addrCopy.raw.family = AF_INET6;
   1.253 +		addrp = &addrCopy;
   1.254 +	}
   1.255 +#endif
   1.256 +
   1.257 +	rv = _PR_MD_CONNECT(fd, addrp, PR_NETADDR_SIZE(addr), timeout);
   1.258 +	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("connect -> %d", rv));
   1.259 +	if (rv == 0)
   1.260 +		return PR_SUCCESS;
   1.261 +	else
   1.262 +		return PR_FAILURE;
   1.263 +}
   1.264 +
   1.265 +static PRStatus PR_CALLBACK SocketConnectContinue(
   1.266 +    PRFileDesc *fd, PRInt16 out_flags)
   1.267 +{
   1.268 +    PROsfd osfd;
   1.269 +    int err;
   1.270 +
   1.271 +    if (out_flags & PR_POLL_NVAL) {
   1.272 +        PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
   1.273 +        return PR_FAILURE;
   1.274 +    }
   1.275 +    if ((out_flags & (PR_POLL_WRITE | PR_POLL_EXCEPT | PR_POLL_ERR)) == 0) {
   1.276 +        PR_ASSERT(out_flags == 0);
   1.277 +        PR_SetError(PR_IN_PROGRESS_ERROR, 0);
   1.278 +        return PR_FAILURE;
   1.279 +    }
   1.280 +
   1.281 +    osfd = fd->secret->md.osfd;
   1.282 +
   1.283 +#if defined(XP_UNIX)
   1.284 +
   1.285 +    err = _MD_unix_get_nonblocking_connect_error(osfd);
   1.286 +    if (err != 0) {
   1.287 +        _PR_MD_MAP_CONNECT_ERROR(err);
   1.288 +        return PR_FAILURE;
   1.289 +    }
   1.290 +    return PR_SUCCESS;
   1.291 +
   1.292 +#elif defined(WIN32) || defined(WIN16)
   1.293 +
   1.294 +    if (out_flags & PR_POLL_EXCEPT) {
   1.295 +        int len = sizeof(err);
   1.296 +        if (getsockopt(osfd, (int)SOL_SOCKET, SO_ERROR, (char *) &err, &len)
   1.297 +                == SOCKET_ERROR) {
   1.298 +            _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
   1.299 +            return PR_FAILURE;
   1.300 +        }
   1.301 +        if (err != 0) {
   1.302 +            _PR_MD_MAP_CONNECT_ERROR(err);
   1.303 +        } else {
   1.304 +            PR_SetError(PR_UNKNOWN_ERROR, 0);
   1.305 +        }
   1.306 +        return PR_FAILURE;
   1.307 +    }
   1.308 +
   1.309 +    PR_ASSERT(out_flags & PR_POLL_WRITE);
   1.310 +    return PR_SUCCESS;
   1.311 +
   1.312 +#elif defined(XP_OS2)
   1.313 +
   1.314 +    err = _MD_os2_get_nonblocking_connect_error(osfd);
   1.315 +    if (err != 0) {
   1.316 +        _PR_MD_MAP_CONNECT_ERROR(err);
   1.317 +        return PR_FAILURE;
   1.318 +    }
   1.319 +    return PR_SUCCESS;
   1.320 +
   1.321 +#elif defined(XP_BEOS)
   1.322 +
   1.323 +#ifdef BONE_VERSION  /* bug 122364 */
   1.324 +    /* temporary workaround until getsockopt(SO_ERROR) works in BONE */
   1.325 +    if (out_flags & PR_POLL_EXCEPT) {
   1.326 +        PR_SetError(PR_CONNECT_REFUSED_ERROR, 0);
   1.327 +        return PR_FAILURE;
   1.328 +    }
   1.329 +    PR_ASSERT(out_flags & PR_POLL_WRITE);
   1.330 +    return PR_SUCCESS;
   1.331 +#else
   1.332 +    err = _MD_beos_get_nonblocking_connect_error(fd);
   1.333 +    if( err != 0 ) {
   1.334 +        _PR_MD_MAP_CONNECT_ERROR(err);
   1.335 +        return PR_FAILURE;
   1.336 +    }
   1.337 +    else
   1.338 +        return PR_SUCCESS;
   1.339 +#endif /* BONE_VERSION */
   1.340 +
   1.341 +#else
   1.342 +    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
   1.343 +    return PR_FAILURE;
   1.344 +#endif
   1.345 +}
   1.346 +
   1.347 +PR_IMPLEMENT(PRStatus) PR_GetConnectStatus(const PRPollDesc *pd)
   1.348 +{
   1.349 +    /* Find the NSPR layer and invoke its connectcontinue method */
   1.350 +    PRFileDesc *bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
   1.351 +
   1.352 +    if (NULL == bottom) {
   1.353 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.354 +        return PR_FAILURE;
   1.355 +    }
   1.356 +    return SocketConnectContinue(bottom, pd->out_flags);
   1.357 +}
   1.358 +
   1.359 +static PRFileDesc* PR_CALLBACK SocketAccept(PRFileDesc *fd, PRNetAddr *addr,
   1.360 +PRIntervalTime timeout)
   1.361 +{
   1.362 +	PROsfd osfd;
   1.363 +	PRFileDesc *fd2;
   1.364 +	PRUint32 al;
   1.365 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.366 +#ifdef WINNT
   1.367 +	PRNetAddr addrCopy;
   1.368 +#endif
   1.369 +
   1.370 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.371 +		me->flags &= ~_PR_INTERRUPT;
   1.372 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.373 +		return 0;
   1.374 +	}
   1.375 +	if (_PR_IO_PENDING(me)) {
   1.376 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
   1.377 +		return 0;
   1.378 +	}
   1.379 +
   1.380 +#ifdef WINNT
   1.381 +	if (addr == NULL) {
   1.382 +		addr = &addrCopy;
   1.383 +	}
   1.384 +#endif
   1.385 +	al = sizeof(PRNetAddr);
   1.386 +	osfd = _PR_MD_ACCEPT(fd, addr, &al, timeout);
   1.387 +	if (osfd == -1)
   1.388 +		return 0;
   1.389 +
   1.390 +	fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
   1.391 +	if (!fd2) {
   1.392 +		_PR_MD_CLOSE_SOCKET(osfd);
   1.393 +		return NULL;
   1.394 +	}
   1.395 +
   1.396 +	fd2->secret->nonblocking = fd->secret->nonblocking;
   1.397 +	fd2->secret->inheritable = fd->secret->inheritable;
   1.398 +#ifdef WINNT
   1.399 +	if (!fd2->secret->nonblocking && fd2->secret->inheritable != _PR_TRI_TRUE) {
   1.400 +		/*
   1.401 +		 * The new socket has been associated with an I/O
   1.402 +		 * completion port.  There is no going back.
   1.403 +		 */
   1.404 +		fd2->secret->md.io_model_committed = PR_TRUE;
   1.405 +	}
   1.406 +	PR_ASSERT(al == PR_NETADDR_SIZE(addr));
   1.407 +	fd2->secret->md.accepted_socket = PR_TRUE;
   1.408 +	memcpy(&fd2->secret->md.peer_addr, addr, al);
   1.409 +#endif
   1.410 +
   1.411 +	/*
   1.412 +	 * On some platforms, the new socket created by accept()
   1.413 +	 * inherits the nonblocking (or overlapped io) attribute
   1.414 +	 * of the listening socket.  As an optimization, these
   1.415 +	 * platforms can skip the following _PR_MD_MAKE_NONBLOCK
   1.416 +	 * call.
   1.417 +	 */
   1.418 +#if !defined(SOLARIS) && !defined(IRIX) && !defined(WINNT)
   1.419 +	_PR_MD_MAKE_NONBLOCK(fd2);
   1.420 +#endif
   1.421 +
   1.422 +#ifdef _PR_INET6
   1.423 +	if (addr && (AF_INET6 == addr->raw.family))
   1.424 +        addr->raw.family = PR_AF_INET6;
   1.425 +#endif
   1.426 +	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   1.427 +	PR_ASSERT(IsValidNetAddrLen(addr, al) == PR_TRUE);
   1.428 +
   1.429 +	return fd2;
   1.430 +}
   1.431 +
   1.432 +#ifdef WINNT
   1.433 +PR_IMPLEMENT(PRFileDesc*) PR_NTFast_Accept(PRFileDesc *fd, PRNetAddr *addr,
   1.434 +PRIntervalTime timeout)
   1.435 +{
   1.436 +	PROsfd osfd;
   1.437 +	PRFileDesc *fd2;
   1.438 +	PRIntn al;
   1.439 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.440 +	PRNetAddr addrCopy;
   1.441 +
   1.442 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.443 +		me->flags &= ~_PR_INTERRUPT;
   1.444 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.445 +		return 0;
   1.446 +	}
   1.447 +	if (_PR_IO_PENDING(me)) {
   1.448 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
   1.449 +		return 0;
   1.450 +	}
   1.451 +
   1.452 +		if (addr == NULL) {
   1.453 +			addr = &addrCopy;
   1.454 +		}
   1.455 +		al = PR_NETADDR_SIZE(addr);
   1.456 +		osfd = _PR_MD_FAST_ACCEPT(fd, addr, &al, timeout, PR_TRUE, NULL, NULL);
   1.457 +		if (osfd == -1) {
   1.458 +			return 0;
   1.459 +		}
   1.460 +
   1.461 +	fd2 = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
   1.462 +	if (!fd2) {
   1.463 +		_PR_MD_CLOSE_SOCKET(osfd);
   1.464 +	} else {
   1.465 +		fd2->secret->nonblocking = fd->secret->nonblocking;
   1.466 +		fd2->secret->md.io_model_committed = PR_TRUE;
   1.467 +	        PR_ASSERT(al == PR_NETADDR_SIZE(addr));
   1.468 +        	fd2->secret->md.accepted_socket = PR_TRUE;
   1.469 +        	memcpy(&fd2->secret->md.peer_addr, addr, al);
   1.470 +#ifdef _PR_INET6
   1.471 +		if (AF_INET6 == addr->raw.family)
   1.472 +        	addr->raw.family = PR_AF_INET6;
   1.473 +#endif
   1.474 +#ifdef _PR_NEED_SECRET_AF
   1.475 +		fd2->secret->af = fd->secret->af;
   1.476 +#endif
   1.477 +	}
   1.478 +	return fd2;
   1.479 +}
   1.480 +#endif /* WINNT */
   1.481 +
   1.482 +
   1.483 +static PRStatus PR_CALLBACK SocketBind(PRFileDesc *fd, const PRNetAddr *addr)
   1.484 +{
   1.485 +	PRInt32 result;
   1.486 +    const PRNetAddr *addrp = addr;
   1.487 +#if defined(_PR_INET6)
   1.488 +	PRNetAddr addrCopy;
   1.489 +#endif
   1.490 +
   1.491 +	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   1.492 +
   1.493 +#ifdef XP_UNIX
   1.494 +	if (addr->raw.family == AF_UNIX) {
   1.495 +		/* Disallow relative pathnames */
   1.496 +		if (addr->local.path[0] != '/') {
   1.497 +			PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.498 +			return PR_FAILURE;
   1.499 +		}
   1.500 +	}
   1.501 +#endif /* XP_UNIX */
   1.502 +
   1.503 +#if defined(_PR_INET6)
   1.504 +	if (addr->raw.family == PR_AF_INET6) {
   1.505 +		addrCopy = *addr;
   1.506 +		addrCopy.raw.family = AF_INET6;
   1.507 +		addrp = &addrCopy;
   1.508 +	}
   1.509 +#endif
   1.510 +	result = _PR_MD_BIND(fd, addrp, PR_NETADDR_SIZE(addr));
   1.511 +	if (result < 0) {
   1.512 +		return PR_FAILURE;
   1.513 +	}
   1.514 +	return PR_SUCCESS;
   1.515 +}
   1.516 +
   1.517 +static PRStatus PR_CALLBACK SocketListen(PRFileDesc *fd, PRIntn backlog)
   1.518 +{
   1.519 +	PRInt32 result;
   1.520 +
   1.521 +	result = _PR_MD_LISTEN(fd, backlog);
   1.522 +	if (result < 0) {
   1.523 +		return PR_FAILURE;
   1.524 +	}
   1.525 +	return PR_SUCCESS;
   1.526 +}
   1.527 +
   1.528 +static PRStatus PR_CALLBACK SocketShutdown(PRFileDesc *fd, PRIntn how)
   1.529 +{
   1.530 +	PRInt32 result;
   1.531 +
   1.532 +	result = _PR_MD_SHUTDOWN(fd, how);
   1.533 +	if (result < 0) {
   1.534 +		return PR_FAILURE;
   1.535 +	}
   1.536 +	return PR_SUCCESS;
   1.537 +}
   1.538 +
   1.539 +static PRInt32 PR_CALLBACK SocketRecv(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
   1.540 +PRIntervalTime timeout)
   1.541 +{
   1.542 +	PRInt32 rv;
   1.543 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.544 +
   1.545 +	if ((flags != 0) && (flags != PR_MSG_PEEK)) {
   1.546 +		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.547 +		return -1;
   1.548 +	}
   1.549 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.550 +		me->flags &= ~_PR_INTERRUPT;
   1.551 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.552 +		return -1;
   1.553 +	}
   1.554 +	if (_PR_IO_PENDING(me)) {
   1.555 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
   1.556 +		return -1;
   1.557 +	}
   1.558 +
   1.559 +	PR_LOG(_pr_io_lm, PR_LOG_MAX,
   1.560 +		("recv: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d flags=%d",
   1.561 +		fd, fd->secret->md.osfd, buf, amount, flags));
   1.562 +
   1.563 +#ifdef _PR_HAVE_PEEK_BUFFER
   1.564 +	if (fd->secret->peekBytes != 0) {
   1.565 +		rv = (amount < fd->secret->peekBytes) ?
   1.566 +			amount : fd->secret->peekBytes;
   1.567 +		memcpy(buf, fd->secret->peekBuffer, rv);
   1.568 +		if (flags == 0) {
   1.569 +			/* consume the bytes in the peek buffer */
   1.570 +			fd->secret->peekBytes -= rv;
   1.571 +			if (fd->secret->peekBytes != 0) {
   1.572 +				memmove(fd->secret->peekBuffer,
   1.573 +					fd->secret->peekBuffer + rv,
   1.574 +					fd->secret->peekBytes);
   1.575 +			}
   1.576 +		}
   1.577 +		return rv;
   1.578 +	}
   1.579 +
   1.580 +	/* allocate peek buffer, if necessary */
   1.581 +	if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
   1.582 +		PR_ASSERT(0 == fd->secret->peekBytes);
   1.583 +		/* impose a max size on the peek buffer */
   1.584 +		if (amount > _PR_PEEK_BUFFER_MAX) {
   1.585 +			amount = _PR_PEEK_BUFFER_MAX;
   1.586 +		}
   1.587 +		if (fd->secret->peekBufSize < amount) {
   1.588 +			if (fd->secret->peekBuffer) {
   1.589 +				PR_Free(fd->secret->peekBuffer);
   1.590 +			}
   1.591 +			fd->secret->peekBufSize = amount;
   1.592 +			fd->secret->peekBuffer = PR_Malloc(amount);
   1.593 +			if (NULL == fd->secret->peekBuffer) {
   1.594 +				fd->secret->peekBufSize = 0;
   1.595 +				PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
   1.596 +				return -1;
   1.597 +			}
   1.598 +		}
   1.599 +	}
   1.600 +#endif
   1.601 +
   1.602 +	rv = _PR_MD_RECV(fd, buf, amount, flags, timeout);
   1.603 +	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("recv -> %d, error = %d, os error = %d",
   1.604 +		rv, PR_GetError(), PR_GetOSError()));
   1.605 +
   1.606 +#ifdef _PR_HAVE_PEEK_BUFFER
   1.607 +	if ((PR_MSG_PEEK == flags) && _PR_FD_NEED_EMULATE_MSG_PEEK(fd)) {
   1.608 +		if (rv > 0) {
   1.609 +			memcpy(fd->secret->peekBuffer, buf, rv);
   1.610 +			fd->secret->peekBytes = rv;
   1.611 +		}
   1.612 +	}
   1.613 +#endif
   1.614 +
   1.615 +	return rv;
   1.616 +}
   1.617 +
   1.618 +static PRInt32 PR_CALLBACK SocketRead(PRFileDesc *fd, void *buf, PRInt32 amount)
   1.619 +{
   1.620 +	return SocketRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
   1.621 +}
   1.622 +
   1.623 +static PRInt32 PR_CALLBACK SocketSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
   1.624 +PRIntn flags, PRIntervalTime timeout)
   1.625 +{
   1.626 +	PRInt32 temp, count;
   1.627 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.628 +
   1.629 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.630 +		me->flags &= ~_PR_INTERRUPT;
   1.631 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.632 +		return -1;
   1.633 +	}
   1.634 +	if (_PR_IO_PENDING(me)) {
   1.635 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
   1.636 +		return -1;
   1.637 +	}
   1.638 +
   1.639 +	count = 0;
   1.640 +	while (amount > 0) {
   1.641 +		PR_LOG(_pr_io_lm, PR_LOG_MAX,
   1.642 +		    ("send: fd=%p osfd=%" PR_PRIdOSFD " buf=%p amount=%d",
   1.643 +		    fd, fd->secret->md.osfd, buf, amount));
   1.644 +		temp = _PR_MD_SEND(fd, buf, amount, flags, timeout);
   1.645 +		if (temp < 0) {
   1.646 +					count = -1;
   1.647 +					break;
   1.648 +				}
   1.649 +
   1.650 +		count += temp;
   1.651 +		if (fd->secret->nonblocking) {
   1.652 +			break;
   1.653 +		}
   1.654 +		buf = (const void*) ((const char*)buf + temp);
   1.655 +
   1.656 +		amount -= temp;
   1.657 +	}
   1.658 +	PR_LOG(_pr_io_lm, PR_LOG_MAX, ("send -> %d", count));
   1.659 +	return count;
   1.660 +}
   1.661 +
   1.662 +static PRInt32 PR_CALLBACK SocketWrite(PRFileDesc *fd, const void *buf, PRInt32 amount)
   1.663 +{
   1.664 +	return SocketSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
   1.665 +}
   1.666 +
   1.667 +static PRStatus PR_CALLBACK SocketClose(PRFileDesc *fd)
   1.668 +{
   1.669 +	if (!fd || !fd->secret
   1.670 +			|| (fd->secret->state != _PR_FILEDESC_OPEN
   1.671 +			&& fd->secret->state != _PR_FILEDESC_CLOSED)) {
   1.672 +		PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
   1.673 +		return PR_FAILURE;
   1.674 +	}
   1.675 +
   1.676 +	if (fd->secret->state == _PR_FILEDESC_OPEN) {
   1.677 +		if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) {
   1.678 +			return PR_FAILURE;
   1.679 +		}
   1.680 +		fd->secret->state = _PR_FILEDESC_CLOSED;
   1.681 +	}
   1.682 +
   1.683 +#ifdef _PR_HAVE_PEEK_BUFFER
   1.684 +	if (fd->secret->peekBuffer) {
   1.685 +		PR_ASSERT(fd->secret->peekBufSize > 0);
   1.686 +		PR_DELETE(fd->secret->peekBuffer);
   1.687 +		fd->secret->peekBufSize = 0;
   1.688 +		fd->secret->peekBytes = 0;
   1.689 +	}
   1.690 +#endif
   1.691 +
   1.692 +	PR_FreeFileDesc(fd);
   1.693 +	return PR_SUCCESS;
   1.694 +}
   1.695 +
   1.696 +static PRInt32 PR_CALLBACK SocketAvailable(PRFileDesc *fd)
   1.697 +{
   1.698 +	PRInt32 rv;
   1.699 +#ifdef _PR_HAVE_PEEK_BUFFER
   1.700 +	if (fd->secret->peekBytes != 0) {
   1.701 +		return fd->secret->peekBytes;
   1.702 +	}
   1.703 +#endif
   1.704 +	rv =  _PR_MD_SOCKETAVAILABLE(fd);
   1.705 +	return rv;		
   1.706 +}
   1.707 +
   1.708 +static PRInt64 PR_CALLBACK SocketAvailable64(PRFileDesc *fd)
   1.709 +{
   1.710 +    PRInt64 rv;
   1.711 +#ifdef _PR_HAVE_PEEK_BUFFER
   1.712 +    if (fd->secret->peekBytes != 0) {
   1.713 +        LL_I2L(rv, fd->secret->peekBytes);
   1.714 +        return rv;
   1.715 +    }
   1.716 +#endif
   1.717 +    LL_I2L(rv, _PR_MD_SOCKETAVAILABLE(fd));
   1.718 +	return rv;		
   1.719 +}
   1.720 +
   1.721 +static PRStatus PR_CALLBACK SocketSync(PRFileDesc *fd)
   1.722 +{
   1.723 +	return PR_SUCCESS;
   1.724 +}
   1.725 +
   1.726 +static PRInt32 PR_CALLBACK SocketSendTo(
   1.727 +    PRFileDesc *fd, const void *buf, PRInt32 amount,
   1.728 +    PRIntn flags, const PRNetAddr *addr, PRIntervalTime timeout)
   1.729 +{
   1.730 +	PRInt32 temp, count;
   1.731 +    const PRNetAddr *addrp = addr;
   1.732 +#if defined(_PR_INET6)
   1.733 +	PRNetAddr addrCopy;
   1.734 +#endif
   1.735 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.736 +
   1.737 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.738 +		me->flags &= ~_PR_INTERRUPT;
   1.739 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.740 +		return -1;
   1.741 +	}
   1.742 +	if (_PR_IO_PENDING(me)) {
   1.743 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
   1.744 +		return -1;
   1.745 +	}
   1.746 +
   1.747 +	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
   1.748 +#if defined(_PR_INET6)
   1.749 +	if (addr->raw.family == PR_AF_INET6) {
   1.750 +		addrCopy = *addr;
   1.751 +		addrCopy.raw.family = AF_INET6;
   1.752 +		addrp = &addrCopy;
   1.753 +	}
   1.754 +#endif
   1.755 +
   1.756 +	count = 0;
   1.757 +	while (amount > 0) {
   1.758 +		temp = _PR_MD_SENDTO(fd, buf, amount, flags,
   1.759 +		    addrp, PR_NETADDR_SIZE(addr), timeout);
   1.760 +		if (temp < 0) {
   1.761 +					count = -1;
   1.762 +					break;
   1.763 +				}
   1.764 +		count += temp;
   1.765 +		if (fd->secret->nonblocking) {
   1.766 +			break;
   1.767 +		}
   1.768 +		buf = (const void*) ((const char*)buf + temp);
   1.769 +		amount -= temp;
   1.770 +	}
   1.771 +	return count;
   1.772 +}
   1.773 +
   1.774 +static PRInt32 PR_CALLBACK SocketRecvFrom(PRFileDesc *fd, void *buf, PRInt32 amount,
   1.775 +PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
   1.776 +{
   1.777 +	PRInt32 rv;
   1.778 +	PRUint32 al;
   1.779 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.780 +
   1.781 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.782 +		me->flags &= ~_PR_INTERRUPT;
   1.783 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.784 +		return -1;
   1.785 +	}
   1.786 +	if (_PR_IO_PENDING(me)) {
   1.787 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
   1.788 +		return -1;
   1.789 +	}
   1.790 +
   1.791 +	al = sizeof(PRNetAddr);
   1.792 +	rv = _PR_MD_RECVFROM(fd, buf, amount, flags, addr, &al, timeout);
   1.793 +#ifdef _PR_INET6
   1.794 +	if (addr && (AF_INET6 == addr->raw.family))
   1.795 +        addr->raw.family = PR_AF_INET6;
   1.796 +#endif
   1.797 +	return rv;
   1.798 +}
   1.799 +
   1.800 +static PRInt32 PR_CALLBACK SocketAcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
   1.801 +PRNetAddr **raddr, void *buf, PRInt32 amount,
   1.802 +PRIntervalTime timeout)
   1.803 +{
   1.804 +	PRInt32 rv;
   1.805 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.806 +
   1.807 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.808 +		me->flags &= ~_PR_INTERRUPT;
   1.809 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.810 +		return -1;
   1.811 +	}
   1.812 +	if (_PR_IO_PENDING(me)) {
   1.813 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
   1.814 +		return -1;
   1.815 +	}
   1.816 +	/* The socket must be in blocking mode. */
   1.817 +	if (sd->secret->nonblocking) {
   1.818 +		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.819 +		return -1;
   1.820 +	}
   1.821 +	*nd = NULL;
   1.822 +
   1.823 +#if defined(WINNT)
   1.824 +	{
   1.825 +	PROsfd newSock;
   1.826 +	PRNetAddr *raddrCopy;
   1.827 +
   1.828 +	if (raddr == NULL) {
   1.829 +		raddr = &raddrCopy;
   1.830 +	}
   1.831 +	rv = _PR_MD_ACCEPT_READ(sd, &newSock, raddr, buf, amount, timeout);
   1.832 +	if (rv < 0) {
   1.833 +		rv = -1;
   1.834 +	} else {
   1.835 +		/* Successfully accepted and read; create the new PRFileDesc */
   1.836 +		*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
   1.837 +		if (*nd == 0) {
   1.838 +			_PR_MD_CLOSE_SOCKET(newSock);
   1.839 +			/* PR_AllocFileDesc() has invoked PR_SetError(). */
   1.840 +			rv = -1;
   1.841 +		} else {
   1.842 +			(*nd)->secret->md.io_model_committed = PR_TRUE;
   1.843 +			(*nd)->secret->md.accepted_socket = PR_TRUE;
   1.844 +			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
   1.845 +				PR_NETADDR_SIZE(*raddr));
   1.846 +#ifdef _PR_INET6
   1.847 +			if (AF_INET6 == *raddr->raw.family)
   1.848 +        		*raddr->raw.family = PR_AF_INET6;
   1.849 +#endif
   1.850 +		}
   1.851 +	}
   1.852 +	}
   1.853 +#else
   1.854 +	rv = PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
   1.855 +#endif
   1.856 +	return rv;
   1.857 +}
   1.858 +
   1.859 +#ifdef WINNT
   1.860 +PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead(PRFileDesc *sd, PRFileDesc **nd, 
   1.861 +PRNetAddr **raddr, void *buf, PRInt32 amount,
   1.862 +PRIntervalTime timeout)
   1.863 +{
   1.864 +	PRInt32 rv;
   1.865 +	PROsfd newSock;
   1.866 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.867 +	PRNetAddr *raddrCopy;
   1.868 +
   1.869 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.870 +		me->flags &= ~_PR_INTERRUPT;
   1.871 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.872 +		return -1;
   1.873 +	}
   1.874 +	if (_PR_IO_PENDING(me)) {
   1.875 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
   1.876 +		return -1;
   1.877 +	}
   1.878 +	*nd = NULL;
   1.879 +
   1.880 +	if (raddr == NULL) {
   1.881 +		raddr = &raddrCopy;
   1.882 +	}
   1.883 +	rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount, 
   1.884 +	    timeout, PR_TRUE, NULL, NULL);
   1.885 +	if (rv < 0) {
   1.886 +		rv = -1;
   1.887 +	} else {
   1.888 +		/* Successfully accepted and read; create the new PRFileDesc */
   1.889 +		*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
   1.890 +		if (*nd == 0) {
   1.891 +			_PR_MD_CLOSE_SOCKET(newSock);
   1.892 +			/* PR_AllocFileDesc() has invoked PR_SetError(). */
   1.893 +			rv = -1;
   1.894 +		} else {
   1.895 +			(*nd)->secret->md.io_model_committed = PR_TRUE;
   1.896 +			(*nd)->secret->md.accepted_socket = PR_TRUE;
   1.897 +			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
   1.898 +				PR_NETADDR_SIZE(*raddr));
   1.899 +#ifdef _PR_INET6
   1.900 +			if (AF_INET6 == *raddr->raw.family)
   1.901 +        		*raddr->raw.family = PR_AF_INET6;
   1.902 +#endif
   1.903 +#ifdef _PR_NEED_SECRET_AF
   1.904 +			(*nd)->secret->af = sd->secret->af;
   1.905 +#endif
   1.906 +		}
   1.907 +	}
   1.908 +	return rv;
   1.909 +}
   1.910 +
   1.911 +PR_IMPLEMENT(PRInt32) PR_NTFast_AcceptRead_WithTimeoutCallback(
   1.912 +PRFileDesc *sd, PRFileDesc **nd, 
   1.913 +PRNetAddr **raddr, void *buf, PRInt32 amount,
   1.914 +PRIntervalTime timeout,
   1.915 +_PR_AcceptTimeoutCallback callback,
   1.916 +void *callbackArg)
   1.917 +{
   1.918 +	PRInt32 rv;
   1.919 +	PROsfd newSock;
   1.920 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.921 +	PRNetAddr *raddrCopy;
   1.922 +
   1.923 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.924 +		me->flags &= ~_PR_INTERRUPT;
   1.925 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.926 +		return -1;
   1.927 +	}
   1.928 +	if (_PR_IO_PENDING(me)) {
   1.929 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
   1.930 +		return -1;
   1.931 +	}
   1.932 +	*nd = NULL;
   1.933 +
   1.934 +	if (raddr == NULL) {
   1.935 +		raddr = &raddrCopy;
   1.936 +	}
   1.937 +	rv = _PR_MD_FAST_ACCEPT_READ(sd, &newSock, raddr, buf, amount,
   1.938 +	    timeout, PR_TRUE, callback, callbackArg);
   1.939 +	if (rv < 0) {
   1.940 +		rv = -1;
   1.941 +	} else {
   1.942 +		/* Successfully accepted and read; create the new PRFileDesc */
   1.943 +		*nd = PR_AllocFileDesc(newSock, PR_GetTCPMethods());
   1.944 +		if (*nd == 0) {
   1.945 +			_PR_MD_CLOSE_SOCKET(newSock);
   1.946 +			/* PR_AllocFileDesc() has invoked PR_SetError(). */
   1.947 +			rv = -1;
   1.948 +		} else {
   1.949 +			(*nd)->secret->md.io_model_committed = PR_TRUE;
   1.950 +			(*nd)->secret->md.accepted_socket = PR_TRUE;
   1.951 +			memcpy(&(*nd)->secret->md.peer_addr, *raddr,
   1.952 +				PR_NETADDR_SIZE(*raddr));
   1.953 +#ifdef _PR_INET6
   1.954 +			if (AF_INET6 == *raddr->raw.family)
   1.955 +        		*raddr->raw.family = PR_AF_INET6;
   1.956 +#endif
   1.957 +#ifdef _PR_NEED_SECRET_AF
   1.958 +			(*nd)->secret->af = sd->secret->af;
   1.959 +#endif
   1.960 +		}
   1.961 +	}
   1.962 +	return rv;
   1.963 +}
   1.964 +#endif /* WINNT */
   1.965 +
   1.966 +#ifdef WINNT
   1.967 +PR_IMPLEMENT(void)
   1.968 +PR_NTFast_UpdateAcceptContext(PRFileDesc *socket, PRFileDesc *acceptSocket)
   1.969 +{
   1.970 +	_PR_MD_UPDATE_ACCEPT_CONTEXT(
   1.971 +		socket->secret->md.osfd, acceptSocket->secret->md.osfd);
   1.972 +}
   1.973 +#endif /* WINNT */
   1.974 +
   1.975 +static PRInt32 PR_CALLBACK SocketSendFile(
   1.976 +    PRFileDesc *sd, PRSendFileData *sfd,
   1.977 +    PRTransmitFileFlags flags, PRIntervalTime timeout)
   1.978 +{
   1.979 +	PRInt32 rv;
   1.980 +	PRThread *me = _PR_MD_CURRENT_THREAD();
   1.981 +
   1.982 +	if (_PR_PENDING_INTERRUPT(me)) {
   1.983 +		me->flags &= ~_PR_INTERRUPT;
   1.984 +		PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
   1.985 +		return -1;
   1.986 +	}
   1.987 +	if (_PR_IO_PENDING(me)) {
   1.988 +		PR_SetError(PR_IO_PENDING_ERROR, 0);
   1.989 +		return -1;
   1.990 +	}
   1.991 +	/* The socket must be in blocking mode. */
   1.992 +	if (sd->secret->nonblocking) {
   1.993 +		PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
   1.994 +		return -1;
   1.995 +	}
   1.996 +#if defined(WINNT)
   1.997 +	rv = _PR_MD_SENDFILE(sd, sfd, flags, timeout);
   1.998 +	if ((rv >= 0) && (flags == PR_TRANSMITFILE_CLOSE_SOCKET)) {
   1.999 +		/*
  1.1000 +		 * This should be kept the same as SocketClose, except
  1.1001 +		 * that _PR_MD_CLOSE_SOCKET(sd->secret->md.osfd) should
  1.1002 +		 * not be called because the socket will be recycled.
  1.1003 +		 */
  1.1004 +		PR_FreeFileDesc(sd);
  1.1005 +	}
  1.1006 +#else
  1.1007 +	rv = PR_EmulateSendFile(sd, sfd, flags, timeout);
  1.1008 +#endif	/* WINNT */
  1.1009 +
  1.1010 +	return rv;
  1.1011 +}
  1.1012 +
  1.1013 +static PRInt32 PR_CALLBACK SocketTransmitFile(PRFileDesc *sd, PRFileDesc *fd, 
  1.1014 +const void *headers, PRInt32 hlen, PRTransmitFileFlags flags,
  1.1015 +PRIntervalTime timeout)
  1.1016 +{
  1.1017 +	PRSendFileData sfd;
  1.1018 +
  1.1019 +	sfd.fd = fd;
  1.1020 +	sfd.file_offset = 0;
  1.1021 +	sfd.file_nbytes = 0;
  1.1022 +	sfd.header = headers;
  1.1023 +	sfd.hlen = hlen;
  1.1024 +	sfd.trailer = NULL;
  1.1025 +	sfd.tlen = 0;
  1.1026 +
  1.1027 +	return(SocketSendFile(sd, &sfd, flags, timeout));
  1.1028 +}
  1.1029 +
  1.1030 +static PRStatus PR_CALLBACK SocketGetName(PRFileDesc *fd, PRNetAddr *addr)
  1.1031 +{
  1.1032 +	PRInt32 result;
  1.1033 +	PRUint32 addrlen;
  1.1034 +
  1.1035 +	addrlen = sizeof(PRNetAddr);
  1.1036 +	result = _PR_MD_GETSOCKNAME(fd, addr, &addrlen);
  1.1037 +	if (result < 0) {
  1.1038 +		return PR_FAILURE;
  1.1039 +	}
  1.1040 +#ifdef _PR_INET6
  1.1041 +	if (AF_INET6 == addr->raw.family)
  1.1042 +        addr->raw.family = PR_AF_INET6;
  1.1043 +#endif
  1.1044 +	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1.1045 +	PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
  1.1046 +	return PR_SUCCESS;
  1.1047 +}
  1.1048 +
  1.1049 +static PRStatus PR_CALLBACK SocketGetPeerName(PRFileDesc *fd, PRNetAddr *addr)
  1.1050 +{
  1.1051 +	PRInt32 result;
  1.1052 +	PRUint32 addrlen;
  1.1053 +
  1.1054 +	addrlen = sizeof(PRNetAddr);
  1.1055 +	result = _PR_MD_GETPEERNAME(fd, addr, &addrlen);
  1.1056 +	if (result < 0) {
  1.1057 +		return PR_FAILURE;
  1.1058 +	}
  1.1059 +#ifdef _PR_INET6
  1.1060 +	if (AF_INET6 == addr->raw.family)
  1.1061 +        addr->raw.family = PR_AF_INET6;
  1.1062 +#endif
  1.1063 +	PR_ASSERT(IsValidNetAddr(addr) == PR_TRUE);
  1.1064 +	PR_ASSERT(IsValidNetAddrLen(addr, addrlen) == PR_TRUE);
  1.1065 +	return PR_SUCCESS;
  1.1066 +}
  1.1067 +
  1.1068 +static PRInt16 PR_CALLBACK SocketPoll(
  1.1069 +    PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
  1.1070 +{
  1.1071 +    *out_flags = 0;
  1.1072 +    return in_flags;
  1.1073 +}  /* SocketPoll */
  1.1074 +
  1.1075 +static PRIOMethods tcpMethods = {
  1.1076 +	PR_DESC_SOCKET_TCP,
  1.1077 +	SocketClose,
  1.1078 +	SocketRead,
  1.1079 +	SocketWrite,
  1.1080 +	SocketAvailable,
  1.1081 +	SocketAvailable64,
  1.1082 +	SocketSync,
  1.1083 +	(PRSeekFN)_PR_InvalidInt,
  1.1084 +	(PRSeek64FN)_PR_InvalidInt64,
  1.1085 +	(PRFileInfoFN)_PR_InvalidStatus,
  1.1086 +	(PRFileInfo64FN)_PR_InvalidStatus,
  1.1087 +	SocketWritev,
  1.1088 +	SocketConnect,
  1.1089 +	SocketAccept,
  1.1090 +	SocketBind,
  1.1091 +	SocketListen,
  1.1092 +	SocketShutdown,
  1.1093 +	SocketRecv,
  1.1094 +	SocketSend,
  1.1095 +	(PRRecvfromFN)_PR_InvalidInt,
  1.1096 +	(PRSendtoFN)_PR_InvalidInt,
  1.1097 +	SocketPoll,
  1.1098 +	SocketAcceptRead,
  1.1099 +	SocketTransmitFile,
  1.1100 +	SocketGetName,
  1.1101 +	SocketGetPeerName,
  1.1102 +	(PRReservedFN)_PR_InvalidInt,
  1.1103 +	(PRReservedFN)_PR_InvalidInt,
  1.1104 +	_PR_SocketGetSocketOption,
  1.1105 +	_PR_SocketSetSocketOption,
  1.1106 +    SocketSendFile, 
  1.1107 +    SocketConnectContinue,
  1.1108 +    (PRReservedFN)_PR_InvalidInt, 
  1.1109 +    (PRReservedFN)_PR_InvalidInt, 
  1.1110 +    (PRReservedFN)_PR_InvalidInt, 
  1.1111 +    (PRReservedFN)_PR_InvalidInt
  1.1112 +};
  1.1113 +
  1.1114 +static PRIOMethods udpMethods = {
  1.1115 +	PR_DESC_SOCKET_UDP,
  1.1116 +	SocketClose,
  1.1117 +	SocketRead,
  1.1118 +	SocketWrite,
  1.1119 +	SocketAvailable,
  1.1120 +	SocketAvailable64,
  1.1121 +	SocketSync,
  1.1122 +	(PRSeekFN)_PR_InvalidInt,
  1.1123 +	(PRSeek64FN)_PR_InvalidInt64,
  1.1124 +	(PRFileInfoFN)_PR_InvalidStatus,
  1.1125 +	(PRFileInfo64FN)_PR_InvalidStatus,
  1.1126 +	SocketWritev,
  1.1127 +	SocketConnect,
  1.1128 +	(PRAcceptFN)_PR_InvalidDesc,
  1.1129 +	SocketBind,
  1.1130 +	SocketListen,
  1.1131 +	SocketShutdown,
  1.1132 +	SocketRecv,
  1.1133 +	SocketSend,
  1.1134 +	SocketRecvFrom,
  1.1135 +	SocketSendTo,
  1.1136 +	SocketPoll,
  1.1137 +	(PRAcceptreadFN)_PR_InvalidInt,
  1.1138 +	(PRTransmitfileFN)_PR_InvalidInt,
  1.1139 +	SocketGetName,
  1.1140 +	SocketGetPeerName,
  1.1141 +	(PRReservedFN)_PR_InvalidInt,
  1.1142 +	(PRReservedFN)_PR_InvalidInt,
  1.1143 +	_PR_SocketGetSocketOption,
  1.1144 +	_PR_SocketSetSocketOption,
  1.1145 +    (PRSendfileFN)_PR_InvalidInt, 
  1.1146 +    (PRConnectcontinueFN)_PR_InvalidStatus, 
  1.1147 +    (PRReservedFN)_PR_InvalidInt, 
  1.1148 +    (PRReservedFN)_PR_InvalidInt, 
  1.1149 +    (PRReservedFN)_PR_InvalidInt, 
  1.1150 +    (PRReservedFN)_PR_InvalidInt
  1.1151 +};
  1.1152 +
  1.1153 +
  1.1154 +static PRIOMethods socketpollfdMethods = {
  1.1155 +    (PRDescType) 0,
  1.1156 +    (PRCloseFN)_PR_InvalidStatus,
  1.1157 +    (PRReadFN)_PR_InvalidInt,
  1.1158 +    (PRWriteFN)_PR_InvalidInt,
  1.1159 +    (PRAvailableFN)_PR_InvalidInt,
  1.1160 +    (PRAvailable64FN)_PR_InvalidInt64,
  1.1161 +    (PRFsyncFN)_PR_InvalidStatus,
  1.1162 +    (PRSeekFN)_PR_InvalidInt,
  1.1163 +    (PRSeek64FN)_PR_InvalidInt64,
  1.1164 +    (PRFileInfoFN)_PR_InvalidStatus,
  1.1165 +    (PRFileInfo64FN)_PR_InvalidStatus,
  1.1166 +    (PRWritevFN)_PR_InvalidInt,        
  1.1167 +    (PRConnectFN)_PR_InvalidStatus,        
  1.1168 +    (PRAcceptFN)_PR_InvalidDesc,        
  1.1169 +    (PRBindFN)_PR_InvalidStatus,        
  1.1170 +    (PRListenFN)_PR_InvalidStatus,        
  1.1171 +    (PRShutdownFN)_PR_InvalidStatus,    
  1.1172 +    (PRRecvFN)_PR_InvalidInt,        
  1.1173 +    (PRSendFN)_PR_InvalidInt,        
  1.1174 +    (PRRecvfromFN)_PR_InvalidInt,    
  1.1175 +    (PRSendtoFN)_PR_InvalidInt,        
  1.1176 +	SocketPoll,
  1.1177 +    (PRAcceptreadFN)_PR_InvalidInt,   
  1.1178 +    (PRTransmitfileFN)_PR_InvalidInt, 
  1.1179 +    (PRGetsocknameFN)_PR_InvalidStatus,    
  1.1180 +    (PRGetpeernameFN)_PR_InvalidStatus,    
  1.1181 +    (PRReservedFN)_PR_InvalidInt,    
  1.1182 +    (PRReservedFN)_PR_InvalidInt,    
  1.1183 +    (PRGetsocketoptionFN)_PR_InvalidStatus,
  1.1184 +    (PRSetsocketoptionFN)_PR_InvalidStatus,
  1.1185 +    (PRSendfileFN)_PR_InvalidInt, 
  1.1186 +    (PRConnectcontinueFN)_PR_InvalidStatus, 
  1.1187 +    (PRReservedFN)_PR_InvalidInt, 
  1.1188 +    (PRReservedFN)_PR_InvalidInt, 
  1.1189 +    (PRReservedFN)_PR_InvalidInt, 
  1.1190 +    (PRReservedFN)_PR_InvalidInt
  1.1191 +};
  1.1192 +
  1.1193 +PR_IMPLEMENT(const PRIOMethods*) PR_GetTCPMethods()
  1.1194 +{
  1.1195 +	return &tcpMethods;
  1.1196 +}
  1.1197 +
  1.1198 +PR_IMPLEMENT(const PRIOMethods*) PR_GetUDPMethods()
  1.1199 +{
  1.1200 +	return &udpMethods;
  1.1201 +}
  1.1202 +
  1.1203 +static const PRIOMethods* PR_GetSocketPollFdMethods()
  1.1204 +{
  1.1205 +    return &socketpollfdMethods;
  1.1206 +}  /* PR_GetSocketPollFdMethods */
  1.1207 +
  1.1208 +#if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
  1.1209 +PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
  1.1210 +
  1.1211 +#if defined(_PR_INET6_PROBE)
  1.1212 +
  1.1213 +extern PRBool _pr_ipv6_is_present(void);
  1.1214 +
  1.1215 +PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
  1.1216 +{
  1.1217 +	PROsfd osfd;
  1.1218 +
  1.1219 +	osfd = _PR_MD_SOCKET(AF_INET6, SOCK_STREAM, 0);
  1.1220 +	if (osfd != -1) {
  1.1221 +		_PR_MD_CLOSE_SOCKET(osfd);
  1.1222 +		return PR_TRUE;
  1.1223 +	}
  1.1224 +	return PR_FALSE;
  1.1225 +}
  1.1226 +#endif	/* _PR_INET6_PROBE */
  1.1227 +
  1.1228 +#endif
  1.1229 +
  1.1230 +PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
  1.1231 +{
  1.1232 +	PROsfd osfd;
  1.1233 +	PRFileDesc *fd;
  1.1234 +	PRInt32 tmp_domain = domain;
  1.1235 +
  1.1236 +	if (!_pr_initialized) _PR_ImplicitInitialization();
  1.1237 +	if (PR_AF_INET != domain
  1.1238 +			&& PR_AF_INET6 != domain
  1.1239 +#if defined(XP_UNIX) || defined(XP_OS2)
  1.1240 +			&& PR_AF_LOCAL != domain
  1.1241 +#endif
  1.1242 +			) {
  1.1243 +		PR_SetError(PR_ADDRESS_NOT_SUPPORTED_ERROR, 0);
  1.1244 +		return NULL;
  1.1245 +	}
  1.1246 +
  1.1247 +#if defined(_PR_INET6_PROBE)
  1.1248 +	if (PR_AF_INET6 == domain)
  1.1249 +		domain = _pr_ipv6_is_present() ? AF_INET6 : AF_INET;
  1.1250 +#elif defined(_PR_INET6)
  1.1251 +	if (PR_AF_INET6 == domain)
  1.1252 +		domain = AF_INET6;
  1.1253 +#else
  1.1254 +	if (PR_AF_INET6 == domain)
  1.1255 +		domain = AF_INET;
  1.1256 +#endif	/* _PR_INET6 */
  1.1257 +	osfd = _PR_MD_SOCKET(domain, type, proto);
  1.1258 +	if (osfd == -1) {
  1.1259 +		return 0;
  1.1260 +	}
  1.1261 +	if (type == SOCK_STREAM)
  1.1262 +		fd = PR_AllocFileDesc(osfd, PR_GetTCPMethods());
  1.1263 +	else
  1.1264 +		fd = PR_AllocFileDesc(osfd, PR_GetUDPMethods());
  1.1265 +	/*
  1.1266 +	 * Make the sockets non-blocking
  1.1267 +	 */
  1.1268 +	if (fd != NULL) {
  1.1269 +		_PR_MD_MAKE_NONBLOCK(fd);
  1.1270 +		_PR_MD_INIT_FD_INHERITABLE(fd, PR_FALSE);
  1.1271 +#ifdef _PR_NEED_SECRET_AF
  1.1272 +		fd->secret->af = domain;
  1.1273 +#endif
  1.1274 +#if defined(_PR_INET6_PROBE) || !defined(_PR_INET6)
  1.1275 +		/*
  1.1276 +		 * For platforms with no support for IPv6 
  1.1277 +		 * create layered socket for IPv4-mapped IPv6 addresses
  1.1278 +		 */
  1.1279 +		if (PR_AF_INET6 == tmp_domain && PR_AF_INET == domain) {
  1.1280 +			if (PR_FAILURE == _pr_push_ipv6toipv4_layer(fd)) {
  1.1281 +				PR_Close(fd);
  1.1282 +				fd = NULL;
  1.1283 +			}
  1.1284 +		}
  1.1285 +#endif
  1.1286 +	} else
  1.1287 +		_PR_MD_CLOSE_SOCKET(osfd);
  1.1288 +
  1.1289 +	return fd;
  1.1290 +}
  1.1291 +
  1.1292 +PR_IMPLEMENT(PRFileDesc *) PR_NewTCPSocket(void)
  1.1293 +{
  1.1294 +	PRInt32 domain = AF_INET;
  1.1295 +
  1.1296 +	return PR_Socket(domain, SOCK_STREAM, 0);
  1.1297 +}
  1.1298 +
  1.1299 +PR_IMPLEMENT(PRFileDesc*) PR_NewUDPSocket(void)
  1.1300 +{
  1.1301 +	PRInt32 domain = AF_INET;
  1.1302 +
  1.1303 +	return PR_Socket(domain, SOCK_DGRAM, 0);
  1.1304 +}
  1.1305 +
  1.1306 +PR_IMPLEMENT(PRFileDesc *) PR_OpenTCPSocket(PRIntn af)
  1.1307 +{
  1.1308 +	return PR_Socket(af, SOCK_STREAM, 0);
  1.1309 +}
  1.1310 +
  1.1311 +PR_IMPLEMENT(PRFileDesc*) PR_OpenUDPSocket(PRIntn af)
  1.1312 +{
  1.1313 +	return PR_Socket(af, SOCK_DGRAM, 0);
  1.1314 +}
  1.1315 +
  1.1316 +PR_IMPLEMENT(PRStatus) PR_NewTCPSocketPair(PRFileDesc *f[])
  1.1317 +{
  1.1318 +#ifdef XP_UNIX
  1.1319 +	PRInt32 rv, osfd[2];
  1.1320 +
  1.1321 +	if (!_pr_initialized) _PR_ImplicitInitialization();
  1.1322 +
  1.1323 +	rv = _PR_MD_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, osfd);
  1.1324 +	if (rv == -1) {
  1.1325 +		return PR_FAILURE;
  1.1326 +	}
  1.1327 +
  1.1328 +	f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
  1.1329 +	if (!f[0]) {
  1.1330 +		_PR_MD_CLOSE_SOCKET(osfd[0]);
  1.1331 +		_PR_MD_CLOSE_SOCKET(osfd[1]);
  1.1332 +		/* PR_AllocFileDesc() has invoked PR_SetError(). */
  1.1333 +		return PR_FAILURE;
  1.1334 +	}
  1.1335 +	f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
  1.1336 +	if (!f[1]) {
  1.1337 +		PR_Close(f[0]);
  1.1338 +		_PR_MD_CLOSE_SOCKET(osfd[1]);
  1.1339 +		/* PR_AllocFileDesc() has invoked PR_SetError(). */
  1.1340 +		return PR_FAILURE;
  1.1341 +	}
  1.1342 +	_PR_MD_MAKE_NONBLOCK(f[0]);
  1.1343 +	_PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
  1.1344 +	_PR_MD_MAKE_NONBLOCK(f[1]);
  1.1345 +	_PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
  1.1346 +	return PR_SUCCESS;
  1.1347 +#elif defined(WINNT)
  1.1348 +    /*
  1.1349 +     * A socket pair is often used for interprocess communication,
  1.1350 +     * so we need to make sure neither socket is associated with
  1.1351 +     * the I/O completion port; otherwise it can't be used by a
  1.1352 +     * child process.
  1.1353 +     *
  1.1354 +     * The default implementation below cannot be used for NT
  1.1355 +     * because PR_Accept would have associated the I/O completion
  1.1356 +     * port with the listening and accepted sockets.
  1.1357 +     */
  1.1358 +    SOCKET listenSock;
  1.1359 +    SOCKET osfd[2];
  1.1360 +    struct sockaddr_in selfAddr, peerAddr;
  1.1361 +    int addrLen;
  1.1362 +
  1.1363 +    if (!_pr_initialized) _PR_ImplicitInitialization();
  1.1364 +
  1.1365 +    osfd[0] = osfd[1] = INVALID_SOCKET;
  1.1366 +    listenSock = socket(AF_INET, SOCK_STREAM, 0);
  1.1367 +    if (listenSock == INVALID_SOCKET) {
  1.1368 +        goto failed;
  1.1369 +    }
  1.1370 +    selfAddr.sin_family = AF_INET;
  1.1371 +    selfAddr.sin_port = 0;
  1.1372 +    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* BugZilla: 35408 */
  1.1373 +    addrLen = sizeof(selfAddr);
  1.1374 +    if (bind(listenSock, (struct sockaddr *) &selfAddr,
  1.1375 +            addrLen) == SOCKET_ERROR) {
  1.1376 +        goto failed;
  1.1377 +    }
  1.1378 +    if (getsockname(listenSock, (struct sockaddr *) &selfAddr,
  1.1379 +            &addrLen) == SOCKET_ERROR) {
  1.1380 +        goto failed;
  1.1381 +    }
  1.1382 +    if (listen(listenSock, 5) == SOCKET_ERROR) {
  1.1383 +        goto failed;
  1.1384 +    }
  1.1385 +    osfd[0] = socket(AF_INET, SOCK_STREAM, 0);
  1.1386 +    if (osfd[0] == INVALID_SOCKET) {
  1.1387 +        goto failed;
  1.1388 +    }
  1.1389 +    selfAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  1.1390 +
  1.1391 +    /*
  1.1392 +     * Only a thread is used to do the connect and accept.
  1.1393 +     * I am relying on the fact that connect returns
  1.1394 +     * successfully as soon as the connect request is put
  1.1395 +     * into the listen queue (but before accept is called).
  1.1396 +     * This is the behavior of the BSD socket code.  If
  1.1397 +     * connect does not return until accept is called, we
  1.1398 +     * will need to create another thread to call connect.
  1.1399 +     */
  1.1400 +    if (connect(osfd[0], (struct sockaddr *) &selfAddr,
  1.1401 +            addrLen) == SOCKET_ERROR) {
  1.1402 +        goto failed;
  1.1403 +    }
  1.1404 +    /*
  1.1405 +     * A malicious local process may connect to the listening
  1.1406 +     * socket, so we need to verify that the accepted connection
  1.1407 +     * is made from our own socket osfd[0].
  1.1408 +     */
  1.1409 +    if (getsockname(osfd[0], (struct sockaddr *) &selfAddr,
  1.1410 +            &addrLen) == SOCKET_ERROR) {
  1.1411 +        goto failed;
  1.1412 +    }
  1.1413 +    osfd[1] = accept(listenSock, (struct sockaddr *) &peerAddr, &addrLen);
  1.1414 +    if (osfd[1] == INVALID_SOCKET) {
  1.1415 +        goto failed;
  1.1416 +    }
  1.1417 +    if (peerAddr.sin_port != selfAddr.sin_port) {
  1.1418 +        /* the connection we accepted is not from osfd[0] */
  1.1419 +        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  1.1420 +        goto failed;
  1.1421 +    }
  1.1422 +    closesocket(listenSock);
  1.1423 +
  1.1424 +    f[0] = PR_AllocFileDesc(osfd[0], PR_GetTCPMethods());
  1.1425 +    if (!f[0]) {
  1.1426 +        closesocket(osfd[0]);
  1.1427 +        closesocket(osfd[1]);
  1.1428 +        /* PR_AllocFileDesc() has invoked PR_SetError(). */
  1.1429 +        return PR_FAILURE;
  1.1430 +    }
  1.1431 +    f[1] = PR_AllocFileDesc(osfd[1], PR_GetTCPMethods());
  1.1432 +    if (!f[1]) {
  1.1433 +        PR_Close(f[0]);
  1.1434 +        closesocket(osfd[1]);
  1.1435 +        /* PR_AllocFileDesc() has invoked PR_SetError(). */
  1.1436 +        return PR_FAILURE;
  1.1437 +    }
  1.1438 +    _PR_MD_INIT_FD_INHERITABLE(f[0], PR_FALSE);
  1.1439 +    _PR_MD_INIT_FD_INHERITABLE(f[1], PR_FALSE);
  1.1440 +    return PR_SUCCESS;
  1.1441 +
  1.1442 +failed:
  1.1443 +    if (listenSock != INVALID_SOCKET) {
  1.1444 +        closesocket(listenSock);
  1.1445 +    }
  1.1446 +    if (osfd[0] != INVALID_SOCKET) {
  1.1447 +        closesocket(osfd[0]);
  1.1448 +    }
  1.1449 +    if (osfd[1] != INVALID_SOCKET) {
  1.1450 +        closesocket(osfd[1]);
  1.1451 +    }
  1.1452 +    return PR_FAILURE;
  1.1453 +#else /* not Unix or NT */
  1.1454 +    /*
  1.1455 +     * default implementation
  1.1456 +     */
  1.1457 +    PRFileDesc *listenSock;
  1.1458 +    PRNetAddr selfAddr, peerAddr;
  1.1459 +    PRUint16 port;
  1.1460 +
  1.1461 +    f[0] = f[1] = NULL;
  1.1462 +    listenSock = PR_NewTCPSocket();
  1.1463 +    if (listenSock == NULL) {
  1.1464 +        goto failed;
  1.1465 +    }
  1.1466 +    PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr); /* BugZilla: 35408 */
  1.1467 +    if (PR_Bind(listenSock, &selfAddr) == PR_FAILURE) {
  1.1468 +        goto failed;
  1.1469 +    }
  1.1470 +    if (PR_GetSockName(listenSock, &selfAddr) == PR_FAILURE) {
  1.1471 +        goto failed;
  1.1472 +    }
  1.1473 +    port = ntohs(selfAddr.inet.port);
  1.1474 +    if (PR_Listen(listenSock, 5) == PR_FAILURE) {
  1.1475 +        goto failed;
  1.1476 +    }
  1.1477 +    f[0] = PR_NewTCPSocket();
  1.1478 +    if (f[0] == NULL) {
  1.1479 +        goto failed;
  1.1480 +    }
  1.1481 +#ifdef _PR_CONNECT_DOES_NOT_BIND
  1.1482 +    /*
  1.1483 +     * If connect does not implicitly bind the socket (e.g., on
  1.1484 +     * BeOS), we have to bind the socket so that we can get its
  1.1485 +     * port with getsockname later.
  1.1486 +     */
  1.1487 +    PR_InitializeNetAddr(PR_IpAddrLoopback, 0, &selfAddr);
  1.1488 +    if (PR_Bind(f[0], &selfAddr) == PR_FAILURE) {
  1.1489 +        goto failed;
  1.1490 +    }
  1.1491 +#endif
  1.1492 +    PR_InitializeNetAddr(PR_IpAddrLoopback, port, &selfAddr);
  1.1493 +
  1.1494 +    /*
  1.1495 +     * Only a thread is used to do the connect and accept.
  1.1496 +     * I am relying on the fact that PR_Connect returns
  1.1497 +     * successfully as soon as the connect request is put
  1.1498 +     * into the listen queue (but before PR_Accept is called).
  1.1499 +     * This is the behavior of the BSD socket code.  If
  1.1500 +     * connect does not return until accept is called, we
  1.1501 +     * will need to create another thread to call connect.
  1.1502 +     */
  1.1503 +    if (PR_Connect(f[0], &selfAddr, PR_INTERVAL_NO_TIMEOUT)
  1.1504 +            == PR_FAILURE) {
  1.1505 +        goto failed;
  1.1506 +    }
  1.1507 +    /*
  1.1508 +     * A malicious local process may connect to the listening
  1.1509 +     * socket, so we need to verify that the accepted connection
  1.1510 +     * is made from our own socket f[0].
  1.1511 +     */
  1.1512 +    if (PR_GetSockName(f[0], &selfAddr) == PR_FAILURE) {
  1.1513 +        goto failed;
  1.1514 +    }
  1.1515 +    f[1] = PR_Accept(listenSock, &peerAddr, PR_INTERVAL_NO_TIMEOUT);
  1.1516 +    if (f[1] == NULL) {
  1.1517 +        goto failed;
  1.1518 +    }
  1.1519 +    if (peerAddr.inet.port != selfAddr.inet.port) {
  1.1520 +        /* the connection we accepted is not from f[0] */
  1.1521 +        PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  1.1522 +        goto failed;
  1.1523 +    }
  1.1524 +    PR_Close(listenSock);
  1.1525 +    return PR_SUCCESS;
  1.1526 +
  1.1527 +failed:
  1.1528 +    if (listenSock) {
  1.1529 +        PR_Close(listenSock);
  1.1530 +    }
  1.1531 +    if (f[0]) {
  1.1532 +        PR_Close(f[0]);
  1.1533 +    }
  1.1534 +    if (f[1]) {
  1.1535 +        PR_Close(f[1]);
  1.1536 +    }
  1.1537 +    return PR_FAILURE;
  1.1538 +#endif
  1.1539 +}
  1.1540 +
  1.1541 +PR_IMPLEMENT(PROsfd)
  1.1542 +PR_FileDesc2NativeHandle(PRFileDesc *fd)
  1.1543 +{
  1.1544 +    if (fd) {
  1.1545 +        fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
  1.1546 +    }
  1.1547 +    if (!fd) {
  1.1548 +        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  1.1549 +        return -1;
  1.1550 +    }
  1.1551 +    return fd->secret->md.osfd;
  1.1552 +}
  1.1553 +
  1.1554 +PR_IMPLEMENT(void)
  1.1555 +PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PROsfd handle)
  1.1556 +{
  1.1557 +	if (fd)
  1.1558 +		fd->secret->md.osfd = handle;
  1.1559 +}
  1.1560 +
  1.1561 +/*
  1.1562 +** Select compatibility
  1.1563 +**
  1.1564 +*/
  1.1565 +
  1.1566 +PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
  1.1567 +{
  1.1568 +	memset(set, 0, sizeof(PR_fd_set));
  1.1569 +}
  1.1570 +
  1.1571 +PR_IMPLEMENT(void) PR_FD_SET(PRFileDesc *fh, PR_fd_set *set)
  1.1572 +{
  1.1573 +	PR_ASSERT( set->hsize < PR_MAX_SELECT_DESC );
  1.1574 +
  1.1575 +	set->harray[set->hsize++] = fh;
  1.1576 +}
  1.1577 +
  1.1578 +PR_IMPLEMENT(void) PR_FD_CLR(PRFileDesc *fh, PR_fd_set *set)
  1.1579 +{
  1.1580 +	PRUint32 index, index2;
  1.1581 +
  1.1582 +	for (index = 0; index<set->hsize; index++)
  1.1583 +		if (set->harray[index] == fh) {
  1.1584 +			for (index2=index; index2 < (set->hsize-1); index2++) {
  1.1585 +				set->harray[index2] = set->harray[index2+1];
  1.1586 +			}
  1.1587 +			set->hsize--;
  1.1588 +			break;
  1.1589 +		}
  1.1590 +}
  1.1591 +
  1.1592 +PR_IMPLEMENT(PRInt32) PR_FD_ISSET(PRFileDesc *fh, PR_fd_set *set)
  1.1593 +{
  1.1594 +	PRUint32 index;
  1.1595 +	for (index = 0; index<set->hsize; index++)
  1.1596 +		if (set->harray[index] == fh) {
  1.1597 +			return 1;
  1.1598 +		}
  1.1599 +	return 0;
  1.1600 +}
  1.1601 +
  1.1602 +PR_IMPLEMENT(void) PR_FD_NSET(PROsfd fd, PR_fd_set *set)
  1.1603 +{
  1.1604 +	PR_ASSERT( set->nsize < PR_MAX_SELECT_DESC );
  1.1605 +
  1.1606 +	set->narray[set->nsize++] = fd;
  1.1607 +}
  1.1608 +
  1.1609 +PR_IMPLEMENT(void) PR_FD_NCLR(PROsfd fd, PR_fd_set *set)
  1.1610 +{
  1.1611 +	PRUint32 index, index2;
  1.1612 +
  1.1613 +	for (index = 0; index<set->nsize; index++)
  1.1614 +		if (set->narray[index] == fd) {
  1.1615 +			for (index2=index; index2 < (set->nsize-1); index2++) {
  1.1616 +				set->narray[index2] = set->narray[index2+1];
  1.1617 +			}
  1.1618 +			set->nsize--;
  1.1619 +			break;
  1.1620 +		}
  1.1621 +}
  1.1622 +
  1.1623 +PR_IMPLEMENT(PRInt32) PR_FD_NISSET(PROsfd fd, PR_fd_set *set)
  1.1624 +{
  1.1625 +	PRUint32 index;
  1.1626 +	for (index = 0; index<set->nsize; index++)
  1.1627 +		if (set->narray[index] == fd) {
  1.1628 +			return 1;
  1.1629 +		}
  1.1630 +	return 0;
  1.1631 +}
  1.1632 +
  1.1633 +
  1.1634 +#if !defined(NEED_SELECT)
  1.1635 +#include "obsolete/probslet.h"
  1.1636 +
  1.1637 +#define PD_INCR 20
  1.1638 +
  1.1639 +static PRPollDesc *_pr_setfd(
  1.1640 +    PR_fd_set *set, PRInt16 flags, PRPollDesc *polldesc)
  1.1641 +{
  1.1642 +    PRUintn fsidx, pdidx;
  1.1643 +    PRPollDesc *poll = polldesc;
  1.1644 +
  1.1645 +    if (NULL == set) return poll;
  1.1646 +
  1.1647 +	/* First set the pr file handle osfds */
  1.1648 +	for (fsidx = 0; fsidx < set->hsize; fsidx++)
  1.1649 +	{
  1.1650 +	    for (pdidx = 0; 1; pdidx++)
  1.1651 +        {
  1.1652 +            if ((PRFileDesc*)-1 == poll[pdidx].fd)
  1.1653 +            {
  1.1654 +                /* our vector is full - extend and condition it */
  1.1655 +                poll = (PRPollDesc*)PR_Realloc(
  1.1656 +                    poll, (pdidx + 1 + PD_INCR) * sizeof(PRPollDesc));
  1.1657 +                if (NULL == poll) goto out_of_memory;
  1.1658 +                memset(
  1.1659 +                    poll + pdidx * sizeof(PRPollDesc),
  1.1660 +                    0, PD_INCR * sizeof(PRPollDesc));
  1.1661 +                poll[pdidx + PD_INCR].fd = (PRFileDesc*)-1;
  1.1662 +            }
  1.1663 +            if ((NULL == poll[pdidx].fd)
  1.1664 +            || (poll[pdidx].fd == set->harray[fsidx]))
  1.1665 +            {
  1.1666 +                /* PR_ASSERT(0 == (poll[pdidx].in_flags & flags)); */
  1.1667 +                /* either empty or prevously defined */
  1.1668 +                poll[pdidx].fd = set->harray[fsidx];  /* possibly redundant */
  1.1669 +                poll[pdidx].in_flags |= flags;  /* possibly redundant */
  1.1670 +                break;
  1.1671 +            }
  1.1672 +        }
  1.1673 +	}
  1.1674 +
  1.1675 +#if 0
  1.1676 +	/* Second set the native osfds */
  1.1677 +	for (fsidx = 0; fsidx < set->nsize; fsidx++)
  1.1678 +	{
  1.1679 +	    for (pdidx = 0; ((PRFileDesc*)-1 != poll[pdidx].fd); pdidx++)
  1.1680 +        {
  1.1681 +            if ((PRFileDesc*)-1 == poll[pdidx].fd)
  1.1682 +            {
  1.1683 +                /* our vector is full - extend and condition it */
  1.1684 +                poll = PR_Realloc(
  1.1685 +                    poll, (pdidx + PD_INCR) * sizeof(PRPollDesc));
  1.1686 +                if (NULL == poll) goto out_of_memory;
  1.1687 +                memset(
  1.1688 +                    poll + pdidx * sizeof(PRPollDesc),
  1.1689 +                    0, PD_INCR * sizeof(PRPollDesc));
  1.1690 +                poll[(pdidx + PD_INCR)].fd = (PRFileDesc*)-1;
  1.1691 +            }
  1.1692 +            if ((NULL == poll[pdidx].fd)
  1.1693 +            || (poll[pdidx].fd == set->narray[fsidx]))
  1.1694 +            {
  1.1695 +                /* either empty or prevously defined */
  1.1696 +                poll[pdidx].fd = set->narray[fsidx];
  1.1697 +                PR_ASSERT(0 == (poll[pdidx].in_flags & flags));
  1.1698 +                poll[pdidx].in_flags |= flags;
  1.1699 +                break;
  1.1700 +            }
  1.1701 +        }
  1.1702 +	}
  1.1703 +#endif /* 0 */
  1.1704 +
  1.1705 +	return poll;
  1.1706 +
  1.1707 +out_of_memory:
  1.1708 +    if (NULL != polldesc) PR_DELETE(polldesc);
  1.1709 +    return NULL;
  1.1710 +}  /* _pr_setfd */
  1.1711 +
  1.1712 +#endif /* !defined(NEED_SELECT) */
  1.1713 +
  1.1714 +PR_IMPLEMENT(PRInt32) PR_Select(
  1.1715 +    PRInt32 unused, PR_fd_set *pr_rd, PR_fd_set *pr_wr, 
  1.1716 +    PR_fd_set *pr_ex, PRIntervalTime timeout)
  1.1717 +{
  1.1718 +
  1.1719 +#if !defined(NEED_SELECT)
  1.1720 +    PRInt32 npds = 0; 
  1.1721 +    /*
  1.1722 +    ** Find out how many fds are represented in the three lists.
  1.1723 +    ** Then allocate a polling descriptor for the logical union
  1.1724 +    ** (there can't be any overlapping) and call PR_Poll().
  1.1725 +    */
  1.1726 +
  1.1727 +    PRPollDesc *copy, *poll;
  1.1728 +
  1.1729 +    static PRBool warning = PR_TRUE;
  1.1730 +    if (warning) warning = _PR_Obsolete( "PR_Select()", "PR_Poll()");
  1.1731 +
  1.1732 +    /* try to get an initial guesss at how much space we need */
  1.1733 +    npds = 0;
  1.1734 +    if ((NULL != pr_rd) && ((pr_rd->hsize + pr_rd->nsize - npds) > 0))
  1.1735 +        npds = pr_rd->hsize + pr_rd->nsize;
  1.1736 +    if ((NULL != pr_wr) && ((pr_wr->hsize + pr_wr->nsize - npds) > 0))
  1.1737 +        npds = pr_wr->hsize + pr_wr->nsize;
  1.1738 +    if ((NULL != pr_ex) && ((pr_ex->hsize + pr_ex->nsize - npds) > 0))
  1.1739 +        npds = pr_ex->hsize + pr_ex->nsize;
  1.1740 +
  1.1741 +    if (0 == npds)
  1.1742 +    {
  1.1743 +        PR_Sleep(timeout);
  1.1744 +        return 0;
  1.1745 +    }
  1.1746 +
  1.1747 +    copy = poll = (PRPollDesc*)PR_Calloc(npds + PD_INCR, sizeof(PRPollDesc));
  1.1748 +    if (NULL == poll) goto out_of_memory;
  1.1749 +    poll[npds + PD_INCR - 1].fd = (PRFileDesc*)-1;
  1.1750 +
  1.1751 +    poll = _pr_setfd(pr_rd, PR_POLL_READ, poll);
  1.1752 +    if (NULL == poll) goto out_of_memory;
  1.1753 +    poll = _pr_setfd(pr_wr, PR_POLL_WRITE, poll);
  1.1754 +    if (NULL == poll) goto out_of_memory;
  1.1755 +    poll = _pr_setfd(pr_ex, PR_POLL_EXCEPT, poll);
  1.1756 +    if (NULL == poll) goto out_of_memory;
  1.1757 +    unused = 0;
  1.1758 +    while (NULL != poll[unused].fd && (PRFileDesc*)-1 != poll[unused].fd)
  1.1759 +    {
  1.1760 +        ++unused;
  1.1761 +    }
  1.1762 +
  1.1763 +    PR_ASSERT(unused > 0);
  1.1764 +    npds = PR_Poll(poll, unused, timeout);
  1.1765 +
  1.1766 +    if (npds > 0)
  1.1767 +    {
  1.1768 +        /* Copy the results back into the fd sets */
  1.1769 +        if (NULL != pr_rd) pr_rd->nsize = pr_rd->hsize = 0;
  1.1770 +        if (NULL != pr_wr) pr_wr->nsize = pr_wr->hsize = 0;
  1.1771 +        if (NULL != pr_ex) pr_ex->nsize = pr_ex->hsize = 0;
  1.1772 +        for (copy = &poll[unused - 1]; copy >= poll; --copy)
  1.1773 +        {
  1.1774 +            if (copy->out_flags & PR_POLL_NVAL)
  1.1775 +            {
  1.1776 +                PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
  1.1777 +                npds = -1;
  1.1778 +                break;
  1.1779 +            }
  1.1780 +            if (copy->out_flags & PR_POLL_READ)
  1.1781 +                if (NULL != pr_rd) pr_rd->harray[pr_rd->hsize++] = copy->fd;
  1.1782 +            if (copy->out_flags & PR_POLL_WRITE)
  1.1783 +                if (NULL != pr_wr) pr_wr->harray[pr_wr->hsize++] = copy->fd;
  1.1784 +            if (copy->out_flags & PR_POLL_EXCEPT)
  1.1785 +                if (NULL != pr_ex) pr_ex->harray[pr_ex->hsize++] = copy->fd;
  1.1786 +        }
  1.1787 +    }
  1.1788 +    PR_DELETE(poll);
  1.1789 +
  1.1790 +    return npds;
  1.1791 +out_of_memory:
  1.1792 +    PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1.1793 +    return -1;    
  1.1794 +
  1.1795 +#endif /* !defined(NEED_SELECT) */
  1.1796 +    
  1.1797 +}

mercurial