1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 /* Win95 Sockets module
48 static PRInt32 socket_io_wait(
51 PRIntervalTime timeout);
54 /* --- SOCKET IO --------------------------------------------------------- */
57 * we only want to call WSAIoctl() on Vista and later
58 * so don't pay for it at build time (and avoid including winsock2.h)
62 #define IOC_IN 0x80000000 /* copy in parameters */
63 #define IOC_VENDOR 0x18000000
64 #define _WSAIOW(x,y) (IOC_IN|(x)|(y))
65 /* from MSWSockDef.h */
66 #define SIO_SET_COMPATIBILITY_MODE _WSAIOW(IOC_VENDOR,300)
68 typedef enum _WSA_COMPATIBILITY_BEHAVIOR_ID {
70 WsaBehaviorReceiveBuffering,
72 } WSA_COMPATIBILITY_BEHAVIOR_ID, *PWSA_COMPATIBILITY_BEHAVIOR_ID;
74 /* from sdkddkver.h */
75 #define NTDDI_WIN6 0x06000000 /* Windows Vista */
78 #define WSAEVENT HANDLE
80 #define WSAOVERLAPPED OVERLAPPED
81 typedef struct _OVERLAPPED * LPWSAOVERLAPPED;
83 typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)(
85 IN DWORD cbTransferred,
86 IN LPWSAOVERLAPPED lpOverlapped,
90 typedef int (__stdcall * WSAIOCTLPROC) (
92 DWORD dwIoControlCode,
97 LPDWORD lpcbBytesReturned,
98 LPWSAOVERLAPPED lpOverlapped,
99 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
102 typedef struct _WSA_COMPATIBILITY_MODE {
103 WSA_COMPATIBILITY_BEHAVIOR_ID BehaviorId;
104 ULONG TargetOsVersion;
105 } WSA_COMPATIBILITY_MODE, *PWSA_COMPATIBILITY_MODE;
107 static HMODULE libWinsock2 = NULL;
108 static WSAIOCTLPROC wsaioctlProc = NULL;
109 static PRBool socketSetCompatMode = PR_FALSE;
111 void _PR_MD_InitSockets(void)
115 memset(&osvi, 0, sizeof(osvi));
116 osvi.dwOSVersionInfoSize = sizeof(osvi);
119 /* if Vista or later... */
120 if (osvi.dwMajorVersion >= 6)
122 libWinsock2 = LoadLibraryW(L"Ws2_32.dll");
125 wsaioctlProc = (WSAIOCTLPROC)GetProcAddress(libWinsock2,
129 socketSetCompatMode = PR_TRUE;
135 void _PR_MD_CleanupSockets(void)
137 socketSetCompatMode = PR_FALSE;
141 FreeLibrary(libWinsock2);
147 _PR_MD_SOCKET(int af, int type, int flags)
152 sock = socket(af, type, flags);
154 if (sock == INVALID_SOCKET )
156 _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError());
161 ** Make the socket Non-Blocking
163 if (ioctlsocket( sock, FIONBIO, &one) != 0)
165 PR_SetError(PR_UNKNOWN_ERROR, WSAGetLastError());
170 if ((af == AF_INET || af == AF_INET6) &&
171 type == SOCK_STREAM && socketSetCompatMode)
173 WSA_COMPATIBILITY_MODE mode;
177 mode.BehaviorId = WsaBehaviorAutoTuning;
178 mode.TargetOsVersion = NTDDI_WIN6;
179 if (wsaioctlProc(sock, SIO_SET_COMPATIBILITY_MODE,
180 (char *)&mode, sizeof(mode),
181 dummy, 4, &ret_dummy, 0, NULL) == SOCKET_ERROR)
183 int err = WSAGetLastError();
184 PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("WSAIoctl() failed with %d", err));
186 /* SIO_SET_COMPATIBILITY_MODE may not be supported.
187 ** If the call to WSAIoctl() fails with WSAEOPNOTSUPP,
188 ** don't close the socket.
197 ** _MD_CloseSocket() -- Close a socket
201 _MD_CloseSocket(PROsfd osfd)
205 rv = closesocket((SOCKET) osfd );
207 _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
213 _MD_SocketAvailable(PRFileDesc *fd)
217 if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) {
218 PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError());
228 PRIntervalTime timeout )
230 PROsfd osfd = fd->secret->md.osfd;
234 while ((sock = accept(osfd, (struct sockaddr *) raddr, rlen)) == -1)
236 err = WSAGetLastError();
237 if ((err == WSAEWOULDBLOCK) && (!fd->secret->nonblocking))
239 if ((rv = socket_io_wait(osfd, READ_FD, timeout)) < 0)
246 _PR_MD_MAP_ACCEPT_ERROR(err);
251 } /* end _MD_accept() */
254 _PR_MD_CONNECT(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen,
255 PRIntervalTime timeout)
257 PROsfd osfd = fd->secret->md.osfd;
261 if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1)
263 err = WSAGetLastError();
264 if ((!fd->secret->nonblocking) && (err == WSAEWOULDBLOCK))
266 rv = socket_io_wait(osfd, CONNECT_FD, timeout);
278 _PR_MD_MAP_CONNECT_ERROR(err);
284 _PR_MD_BIND(PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
288 rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen);
290 if (rv == SOCKET_ERROR) {
291 _PR_MD_MAP_BIND_ERROR(WSAGetLastError());
299 _PR_MD_LISTEN(PRFileDesc *fd, PRIntn backlog)
303 rv = listen(fd->secret->md.osfd, backlog);
305 if (rv == SOCKET_ERROR) {
306 _PR_MD_MAP_DEFAULT_ERROR(WSAGetLastError());
314 _PR_MD_RECV(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
315 PRIntervalTime timeout)
317 PROsfd osfd = fd->secret->md.osfd;
324 PR_ASSERT(PR_MSG_PEEK == flags);
327 while ((rv = recv( osfd, buf, amount, osflags)) == -1)
329 if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
330 && (!fd->secret->nonblocking))
332 rv = socket_io_wait(osfd, READ_FD, timeout);
340 _PR_MD_MAP_RECV_ERROR(err);
348 _PR_MD_SEND(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
349 PRIntervalTime timeout)
351 PROsfd osfd = fd->secret->md.osfd;
353 PRInt32 bytesSent = 0;
355 while(bytesSent < amount )
357 while ((rv = send( osfd, buf, amount, 0 )) == -1)
359 if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
360 && (!fd->secret->nonblocking))
362 rv = socket_io_wait(osfd, WRITE_FD, timeout);
370 _PR_MD_MAP_SEND_ERROR(err);
375 if (fd->secret->nonblocking)
379 if (bytesSent < amount)
381 rv = socket_io_wait(osfd, WRITE_FD, timeout);
392 _PR_MD_SENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
393 const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
395 PROsfd osfd = fd->secret->md.osfd;
397 PRInt32 bytesSent = 0;
399 while(bytesSent < amount)
401 while ((rv = sendto( osfd, buf, amount, 0, (struct sockaddr *) addr,
404 if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
405 && (!fd->secret->nonblocking))
407 rv = socket_io_wait(osfd, WRITE_FD, timeout);
415 _PR_MD_MAP_SENDTO_ERROR(err);
420 if (fd->secret->nonblocking)
424 if (bytesSent < amount)
426 rv = socket_io_wait(osfd, WRITE_FD, timeout);
437 _PR_MD_RECVFROM(PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags,
438 PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
440 PROsfd osfd = fd->secret->md.osfd;
443 while ((rv = recvfrom( osfd, buf, amount, 0, (struct sockaddr *) addr,
446 if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
447 && (!fd->secret->nonblocking))
449 rv = socket_io_wait(osfd, READ_FD, timeout);
457 _PR_MD_MAP_RECVFROM_ERROR(err);
465 _PR_MD_WRITEV(PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
471 for (index=0; index < iov_size; index++)
473 rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0, timeout);
476 if ( rv != iov[index].iov_len )
480 if (fd->secret->nonblocking
481 && (PR_GetError() == PR_WOULD_BLOCK_ERROR)
491 /* Only a nonblocking socket can have partial sends */
492 PR_ASSERT(fd->secret->nonblocking);
500 _PR_MD_SHUTDOWN(PRFileDesc *fd, PRIntn how)
504 rv = shutdown(fd->secret->md.osfd, how);
506 _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError());
511 _PR_MD_GETSOCKNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
515 rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
519 _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError());
525 _PR_MD_GETPEERNAME(PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
529 rv = getpeername((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
533 _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError());
539 _PR_MD_GETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, char* optval, PRInt32* optlen)
543 rv = getsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
547 _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
553 _PR_MD_SETSOCKOPT(PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char* optval, PRInt32 optlen)
557 rv = setsockopt((SOCKET)fd->secret->md.osfd, level, optname, optval, optlen);
561 _PR_MD_MAP_SETSOCKOPT_ERROR(WSAGetLastError());
567 _MD_MakeNonblock(PRFileDesc *f)
569 return; /* do nothing */
577 * Wait for socket i/o, periodically checking for interrupt.
579 * This function returns 1 on success. On failure, it returns
580 * -1 and sets the error codes. It never returns 0.
582 #define _PR_INTERRUPT_CHECK_INTERVAL_SECS 5
584 static PRInt32 socket_io_wait(
587 PRIntervalTime timeout)
591 PRThread *me = _PR_MD_CURRENT_THREAD();
592 PRIntervalTime elapsed, remaining;
593 PRBool wait_for_remaining;
598 case PR_INTERVAL_NO_WAIT:
599 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
601 case PR_INTERVAL_NO_TIMEOUT:
603 * This is a special case of the 'default' case below.
604 * Please see the comments there.
606 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
611 FD_SET(osfd, &rd_wr);
616 rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv);
619 rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv);
622 rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv);
630 _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
633 if ( rv > 0 && fd_type == CONNECT_FD )
636 * Call Sleep(0) to work around a Winsock timing bug.
639 if (FD_ISSET((SOCKET)osfd, &ex))
642 if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
643 (char *) &err, &len) == SOCKET_ERROR)
645 _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
649 _PR_MD_MAP_CONNECT_ERROR(err);
651 PR_SetError(PR_UNKNOWN_ERROR, 0);
654 if (FD_ISSET((SOCKET)osfd, &rd_wr))
661 if (_PR_PENDING_INTERRUPT(me)) {
662 me->flags &= ~_PR_INTERRUPT;
663 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
675 * We block in _MD_SELECT for at most
676 * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds,
677 * so that there is an upper limit on the delay
678 * before the interrupt bit is checked.
680 wait_for_remaining = PR_TRUE;
681 tv.tv_sec = PR_IntervalToSeconds(remaining);
682 if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) {
683 wait_for_remaining = PR_FALSE;
684 tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS;
687 tv.tv_usec = PR_IntervalToMicroseconds(
689 PR_SecondsToInterval(tv.tv_sec));
691 FD_SET(osfd, &rd_wr);
696 rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv);
699 rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv);
702 rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv);
710 _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
713 if ( rv > 0 && fd_type == CONNECT_FD )
716 * Call Sleep(0) to work around a Winsock timing bug.
719 if (FD_ISSET((SOCKET)osfd, &ex))
722 if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
723 (char *) &err, &len) == SOCKET_ERROR)
725 _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
729 _PR_MD_MAP_CONNECT_ERROR(err);
731 PR_SetError(PR_UNKNOWN_ERROR, 0);
734 if (FD_ISSET((SOCKET)osfd, &rd_wr))
741 if (_PR_PENDING_INTERRUPT(me)) {
742 me->flags &= ~_PR_INTERRUPT;
743 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
748 * We loop again if _MD_SELECT timed out and the
749 * timeout deadline has not passed yet.
753 if (wait_for_remaining) {
756 elapsed = PR_SecondsToInterval(tv.tv_sec)
757 + PR_MicrosecondsToInterval(tv.tv_usec);
759 if (elapsed >= remaining) {
760 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
764 remaining = remaining - elapsed;
771 } /* end socket_io_wait() */