diff options
Diffstat (limited to 'pr/src/md/windows/w95sock.c')
-rw-r--r-- | pr/src/md/windows/w95sock.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/pr/src/md/windows/w95sock.c b/pr/src/md/windows/w95sock.c index 01c25258..1bcbaf21 100644 --- a/pr/src/md/windows/w95sock.c +++ b/pr/src/md/windows/w95sock.c @@ -53,6 +53,95 @@ static PRInt32 socket_io_wait( /* --- SOCKET IO --------------------------------------------------------- */ +/* + * we only want to call WSAIoctl() on Vista and later + * so don't pay for it at build time (and avoid including winsock2.h) + */ + +/* from ws2def.h */ +#define IOC_IN 0x80000000 /* copy in parameters */ +#define IOC_VENDOR 0x18000000 +#define _WSAIOW(x,y) (IOC_IN|(x)|(y)) +/* from MSWSockDef.h */ +#define SIO_SET_COMPATIBILITY_MODE _WSAIOW(IOC_VENDOR,300) + +typedef enum _WSA_COMPATIBILITY_BEHAVIOR_ID { + WsaBehaviorAll = 0, + WsaBehaviorReceiveBuffering, + WsaBehaviorAutoTuning +} WSA_COMPATIBILITY_BEHAVIOR_ID, *PWSA_COMPATIBILITY_BEHAVIOR_ID; + +/* from sdkddkver.h */ +#define NTDDI_LONGHORN 0x06000000 + +/* from winsock2.h */ +#define WSAEVENT HANDLE + +#define WSAOVERLAPPED OVERLAPPED +typedef struct _OVERLAPPED * LPWSAOVERLAPPED; + +typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)( + IN DWORD dwError, + IN DWORD cbTransferred, + IN LPWSAOVERLAPPED lpOverlapped, + IN DWORD dwFlags +); + +typedef int (__stdcall * WSAIOCTLPROC) ( + SOCKET s, + DWORD dwIoControlCode, + LPVOID lpvInBuffer, + DWORD cbInBuffer, + LPVOID lpvOutBuffer, + DWORD cbOutBuffer, + LPDWORD lpcbBytesReturned, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine +); + +typedef struct _WSA_COMPATIBILITY_MODE { + WSA_COMPATIBILITY_BEHAVIOR_ID BehaviorId; + ULONG TargetOsVersion; +} WSA_COMPATIBILITY_MODE, *PWSA_COMPATIBILITY_MODE; + +static HMODULE libWinsock2 = NULL; +static WSAIOCTLPROC wsaioctlProc = NULL; +static PRBool socketSetCompatMode = PR_FALSE; + +void _PR_MD_InitSockets(void) +{ + OSVERSIONINFO osvi; + + memset(&osvi, 0, sizeof(osvi)); + osvi.dwOSVersionInfoSize = sizeof(osvi); + GetVersionEx(&osvi); + + /* if Vista or later... */ + if (osvi.dwMajorVersion >= 6) + { + libWinsock2 = LoadLibrary("Ws2_32.dll"); + if (libWinsock2) + { + wsaioctlProc = (WSAIOCTLPROC)GetProcAddress(libWinsock2, + "WSAIoctl"); + if (wsaioctlProc) + { + socketSetCompatMode = PR_TRUE; + } + } + } +} + +void _PR_MD_CleanupSockets(void) +{ + socketSetCompatMode = PR_FALSE; + wsaioctlProc = NULL; + if (libWinsock2) + { + FreeLibrary(libWinsock2); + libWinsock2 = NULL; + } +} PRInt32 _PR_MD_SOCKET(int af, int type, int flags) @@ -78,6 +167,29 @@ _PR_MD_SOCKET(int af, int type, int flags) return -1; } + if ((af == AF_INET || af == AF_INET6) && + type == SOCK_STREAM && socketSetCompatMode) + { + WSA_COMPATIBILITY_MODE mode; + char dummy[4]; + int ret_dummy; + + mode.BehaviorId = WsaBehaviorAutoTuning; + mode.TargetOsVersion = NTDDI_LONGHORN; + if (wsaioctlProc(sock, SIO_SET_COMPATIBILITY_MODE, + (char *)&mode, sizeof(mode), + dummy, 4, &ret_dummy, 0, NULL) == SOCKET_ERROR) + { + int err = WSAGetLastError(); + PR_LOG(_pr_io_lm, PR_LOG_DEBUG, ("WSAIoctl() failed with %d", err)); + + /* SIO_SET_COMPATIBILITY_MODE may not be supported. + ** If the call to WSAIoctl() fails with WSAEOPNOTSUPP, + ** don't close the socket. + */ + } + } + return (PRInt32)sock; } |