Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1180 lines
22 KiB

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
iwinsock.cxx
Abstract:
Contains functions to load sockets DLL and entry points. Functions and data
in this module take care of indirecting sockets calls, hence _I_ in front
of the function name
Contents:
IwinsockInitialize
IwinsockTerminate
LoadWinsock
UnloadWinsock
SafeCloseSocket
Author:
Richard L Firth (rfirth) 12-Apr-1995
Environment:
Win32(s) user-mode DLL
Revision History:
12-Apr-1995 rfirth
Created
08-May-1996 arthurbi
Added support for Socks Firewalls.
05-Mar-1998 rfirth
Moved SOCKS support into ICSocket class. Removed SOCKS library
loading/unloading from this module (revert to pre-SOCKS)
--*/
#include <wininetp.h>
#if defined(__cplusplus)
extern "C" {
#endif
//#define RLF_DEBUG 1
#if INET_DEBUG
#ifdef RLF_DEBUG
#define DPRINTF dprintf
#else
#define DPRINTF (void)
#endif
BOOL
InitDebugSock(
VOID
);
VOID
TerminateDebugSock(
VOID
);
#else
#define DPRINTF (void)
#endif
//
// private types
//
typedef struct {
LPSTR FunctionOrdinal;
FARPROC * FunctionAddress;
} SOCKETS_FUNCTION;
//
// global data
//
GLOBAL
SOCKET
(PASCAL FAR * _I_accept)(
SOCKET s,
struct sockaddr FAR *addr,
int FAR *addrlen
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_bind)(
SOCKET s,
const struct sockaddr FAR *addr,
int namelen
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_closesocket)(
SOCKET s
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_connect)(
SOCKET s,
const struct sockaddr FAR *name,
int namelen
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_gethostname)(
char FAR * name,
int namelen
) = NULL;
GLOBAL
LPHOSTENT
(PASCAL FAR * _I_gethostbyname)(
LPSTR lpHostName
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_getsockname)(
SOCKET s,
struct sockaddr FAR *name,
int FAR * namelen
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_getsockopt)(
SOCKET s,
int level,
int optname,
char FAR * optval,
int FAR *optlen
);
GLOBAL
u_long
(PASCAL FAR * _I_htonl)(
u_long hostlong
) = NULL;
GLOBAL
u_short
(PASCAL FAR * _I_htons)(
u_short hostshort
) = NULL;
GLOBAL
unsigned long
(PASCAL FAR * _I_inet_addr)(
const char FAR * cp
) = NULL;
GLOBAL
char FAR *
(PASCAL FAR * _I_inet_ntoa)(
struct in_addr in
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_ioctlsocket)(
SOCKET s,
long cmd,
u_long FAR *argp
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_listen)(
SOCKET s,
int backlog
) = NULL;
GLOBAL
u_short
(PASCAL FAR * _I_ntohs)(
u_short netshort
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_recv)(
SOCKET s,
char FAR * buf,
int len,
int flags
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_WSARecv)(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_recvfrom)(
SOCKET s,
char FAR * buf,
int len,
int flags,
struct sockaddr FAR *from,
int FAR * fromlen
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_select)(
int nfds,
fd_set FAR *readfds,
fd_set FAR *writefds,
fd_set FAR *exceptfds,
const struct timeval FAR *timeout
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_send)(
SOCKET s,
const char FAR * buf,
int len,
int flags
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_WSASend)(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_sendto)(
SOCKET s,
const char FAR * buf,
int len,
int flags,
const struct sockaddr FAR *to,
int tolen
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_setsockopt)(
SOCKET s,
int level,
int optname,
const char FAR * optval,
int optlen
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_shutdown)(
SOCKET s,
int how
) = NULL;
GLOBAL
SOCKET
(PASCAL FAR * _I_socket)(
int af,
int type,
int protocol
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_WSAStartup)(
WORD wVersionRequired,
LPWSADATA lpWSAData
) = NULL;
GLOBAL
int
(PASCAL FAR * _I_WSACleanup)(
void
) = NULL;
//VENKATKBUG-remove later - for now trap any errors
GLOBAL
int
(PASCAL FAR * __I_WSAGetLastError)(
void
) = NULL;
int
___I_WSAGetLastError(
VOID
)
{
int nError = __I_WSAGetLastError();
/*
VENKATK_BUG - OK to have WSAENOTSOCK - could happen for timeout situations.
INET_ASSERT (nError != WSAENOTSOCK);
*/
return nError;
}
GLOBAL
int
(PASCAL FAR * _I_WSAGetLastError)(
void
) = ___I_WSAGetLastError;
GLOBAL
void
(PASCAL FAR * _I_WSASetLastError)(
int iError
) = NULL;
GLOBAL
int
(PASCAL FAR * _I___WSAFDIsSet)(
SOCKET,
fd_set FAR *
) = NULL;
#if INET_DEBUG
void SetupSocketsTracing(void);
#endif
//
// private data
//
//
// InitializationLock - protects against multiple threads loading WSOCK32.DLL
// and entry points
//
PRIVATE CCritSec InitializationLock;
//
// hWinsock - NULL when WSOCK32.DLL is not loaded
//
PRIVATE HINSTANCE hWinsock = NULL;
//
// WinsockLoadCount - the number of times we have made calls to LoadWinsock()
// and UnloadWinsock(). When this reaches 0 (again), we can unload the Winsock
// DLL for real
//
PRIVATE DWORD WinsockLoadCount = 0;
//
// SocketsFunctions - this is the list of entry points in WSOCK32.DLL that we
// need to load for WININET.DLL
//
PRIVATE
SOCKETS_FUNCTION
SocketsFunctions[] = {
"accept", (FARPROC*)&_I_accept,
"bind", (FARPROC*)&_I_bind,
"closesocket", (FARPROC*)&_I_closesocket,
"connect", (FARPROC*)&_I_connect,
"getsockname", (FARPROC*)&_I_getsockname,
"getsockopt", (FARPROC*)&_I_getsockopt,
"htonl", (FARPROC*)&_I_htonl,
"htons", (FARPROC*)&_I_htons,
"inet_addr", (FARPROC*)&_I_inet_addr,
"inet_ntoa", (FARPROC*)&_I_inet_ntoa,
"ioctlsocket", (FARPROC*)&_I_ioctlsocket,
"listen", (FARPROC*)&_I_listen,
"ntohs", (FARPROC*)&_I_ntohs,
"recv", (FARPROC*)&_I_recv,
"recvfrom", (FARPROC*)&_I_recvfrom,
"select", (FARPROC*)&_I_select,
"send", (FARPROC*)&_I_send,
"sendto", (FARPROC*)&_I_sendto,
"setsockopt", (FARPROC*)&_I_setsockopt,
"shutdown", (FARPROC*)&_I_shutdown,
"socket", (FARPROC*)&_I_socket,
"gethostbyname", (FARPROC*)&_I_gethostbyname,
"gethostname", (FARPROC*)&_I_gethostname,
"WSAGetLastError", (FARPROC*)&__I_WSAGetLastError,
"WSASetLastError", (FARPROC*)&_I_WSASetLastError,
"WSAStartup", (FARPROC*)&_I_WSAStartup,
"WSACleanup", (FARPROC*)&_I_WSACleanup,
"__WSAFDIsSet", (FARPROC*)&_I___WSAFDIsSet,
"WSARecv", (FARPROC*)&_I_WSARecv,
"WSASend", (FARPROC*)&_I_WSASend
};
//
// private prototypes
//
#if INET_DEBUG
void SetupSocketsTracing(void);
#endif
//
// functions
//
BOOL
IwinsockInitialize(
VOID
)
/*++
Routine Description:
Performs initialization/resource allocation for this module
Arguments:
None.
Return Value:
None.
--*/
{
BOOL fResult;
//
// initialize the critical section that protects against multiple threads
// trying to initialize Winsock
//
fResult = InitializationLock.Init();
#if INET_DEBUG
if (fResult)
fResult = InitDebugSock();
#endif
return fResult;
}
VOID
IwinsockTerminate(
VOID
)
/*++
Routine Description:
Performs termination & resource cleanup for this module
Arguments:
None.
Return Value:
None.
--*/
{
InitializationLock.FreeLock();
#if INET_DEBUG
TerminateDebugSock();
#endif
}
DWORD
LoadWinsock(
VOID
)
/*++
Routine Description:
Dynamically loads Windows sockets library
Arguments:
None.
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - Win32 error
e.g. LoadLibrary() failure
WSA error
e.g. WSAStartup() failure
--*/
{
DEBUG_ENTER((DBG_SOCKETS,
Dword,
"LoadWinsock",
NULL
));
DWORD error = ERROR_SUCCESS;
//
// ensure no 2 threads are trying to modify the loaded state of winsock at
// the same time
//
if (!InitializationLock.Lock())
{
error = ERROR_NOT_ENOUGH_MEMORY;
goto quit;
}
if (hWinsock == NULL) {
BOOL failed = FALSE;
//
// BUGBUG - read this value from registry
//
hWinsock = LoadLibrary("ws2_32");
if (hWinsock == NULL) {
DEBUG_PRINT(SOCKETS,
INFO,
("failed to load ws2_32.dll"));
hWinsock = LoadLibrary("wsock32");
}
if (hWinsock != NULL) {
//
// load the entry points
//
for (int i = 0; i < ARRAY_ELEMENTS(SocketsFunctions); ++i) {
FARPROC farProc;
farProc = GetProcAddress(
hWinsock,
(LPCSTR)SocketsFunctions[i].FunctionOrdinal
);
if (farProc == NULL) {
failed = TRUE;
break;
}
*SocketsFunctions[i].FunctionAddress = farProc;
}
if (!failed) {
//
// although we need a WSADATA for WSAStartup(), it is an
// expendible structure (not required for any other sockets
// calls)
//
WSADATA wsaData;
error = _I_WSAStartup(0x0101, &wsaData);
if (error == ERROR_SUCCESS) {
DEBUG_PRINT(SOCKETS,
INFO,
("winsock description: %q\n",
wsaData.szDescription
));
int stringLen;
stringLen = lstrlen(wsaData.szDescription);
if (strnistr(wsaData.szDescription, "novell", stringLen)
&& strnistr(wsaData.szDescription, "wsock32", stringLen)) {
DEBUG_PRINT(SOCKETS,
INFO,
("running on Novell Client32 stack\n"
));
GlobalRunningNovellClient32 = TRUE;
}
#if INET_DEBUG
SetupSocketsTracing();
#endif
} else {
failed = TRUE;
}
}
} else {
failed = TRUE;
}
//
// if we failed to find an entry point or WSAStartup() returned an error
// then unload the library
//
if (failed) {
//
// important: there should be no API calls between determining the
// failure and coming here to get the error code
//
// if error == ERROR_SUCCESS then we have to get the last error, else
// it is the error returned by WSAStartup()
//
if (error == ERROR_SUCCESS) {
error = GetLastError();
INET_ASSERT(error != ERROR_SUCCESS);
}
UnloadWinsock();
}
} else {
//
// just increment the number of times we have called LoadWinsock()
// without a corresponding call to UnloadWinsock();
//
++WinsockLoadCount;
}
InitializationLock.Unlock();
//
// if we failed for any reason, need to report that TCP/IP not available
//
if (error != ERROR_SUCCESS) {
error = ERROR_NOT_SUPPORTED;
}
quit:
DEBUG_LEAVE(error);
return error;
}
VOID
UnloadWinsock(
VOID
)
/*++
Routine Description:
Unloads winsock DLL and prepares hWinsock and SocketsFunctions[] for reload
Arguments:
None.
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_SOCKETS,
None,
"UnloadWinsock",
NULL
));
//
// ensure no 2 threads are trying to modify the loaded state of winsock at
// the same time
//
if (!InitializationLock.Lock())
{
goto quit;
}
//
// only unload the DLL if it has been mapped into process memory
//
if (hWinsock != NULL) {
//
// and only if this is the last load instance
//
if (WinsockLoadCount == 0) {
INET_ASSERT(_I_WSACleanup != NULL);
if (_I_WSACleanup != NULL) {
//
// need to terminate async support too - it is reliant on
// Winsock
//
//called only from LoadWinsock which is called only from INTERNET_HANDLE_OBJECT()
//so not in dynamic unload, so alrite to cleanup.
TerminateAsyncSupport(TRUE);
int serr = _I_WSACleanup();
if (serr != 0) {
DEBUG_PRINT(SOCKETS,
ERROR,
("WSACleanup() returns %d; WSA error = %d\n",
serr,
(_I_WSAGetLastError != NULL)
? _I_WSAGetLastError()
: -1
));
}
}
for (int i = 0; i < ARRAY_ELEMENTS(SocketsFunctions); ++i) {
*SocketsFunctions[i].FunctionAddress = (FARPROC)NULL;
}
FreeLibrary(hWinsock);
hWinsock = NULL;
} else {
//
// if there have been multiple virtual loads, then just reduce the
// load count
//
--WinsockLoadCount;
}
}
InitializationLock.Unlock();
quit:
DEBUG_LEAVE(0);
}
DWORD
SafeCloseSocket(
IN SOCKET Socket
)
/*++
Routine Description:
closesocket() call protected by exception handler in case winsock DLL has
been unloaded by system before Wininet DLL unloaded
Arguments:
Socket - socket handle to close
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - socket error mapped to ERROR_WINHTTP_ error
--*/
{
int serr;
__try {
serr = _I_closesocket(Socket);
} __except(EXCEPTION_EXECUTE_HANDLER) {
serr = 0;
}
ENDEXCEPT
return (serr == SOCKET_ERROR)
? MapInternetError(_I_WSAGetLastError())
: ERROR_SUCCESS;
}
CWrapOverlapped* GetWrapOverlappedObject(LPVOID lpAddress)
{
return CONTAINING_RECORD(lpAddress, CWrapOverlapped, m_Overlapped);
}
#if INET_DEBUG
//
// debug data types
//
SOCKET
PASCAL FAR
_II_socket(
int af,
int type,
int protocol
);
int
PASCAL FAR
_II_closesocket(
SOCKET s
);
SOCKET
PASCAL FAR
_II_accept(
SOCKET s,
struct sockaddr FAR *addr,
int FAR *addrlen
);
GLOBAL
SOCKET
(PASCAL FAR * _P_accept)(
SOCKET s,
struct sockaddr FAR *addr,
int FAR *addrlen
) = NULL;
GLOBAL
int
(PASCAL FAR * _P_closesocket)(
SOCKET s
) = NULL;
GLOBAL
SOCKET
(PASCAL FAR * _P_socket)(
int af,
int type,
int protocol
) = NULL;
#define MAX_STACK_TRACE 5
#define MAX_SOCK_ENTRIES 1000
typedef struct _DEBUG_SOCK_ENTRY {
SOCKET Socket;
DWORD StackTraceLength;
PVOID StackTrace[ MAX_STACK_TRACE ];
} DEBUG_SOCK_ENTRY, *LPDEBUG_SOCK_ENTRY;
CCritSec DebugSockLock;
DEBUG_SOCK_ENTRY GlobalSockEntry[MAX_SOCK_ENTRIES];
DWORD GlobalSocketsCount = 0;
#define LOCK_DEBUG_SOCK() (DebugSockLock.Lock())
#define UNLOCK_DEBUG_SOCK() (DebugSockLock.Unlock())
HINSTANCE NtDllHandle;
typedef USHORT (*RTL_CAPTURE_STACK_BACK_TRACE)(
IN ULONG FramesToSkip,
IN ULONG FramesToCapture,
OUT PVOID *BackTrace,
OUT PULONG BackTraceHash
);
RTL_CAPTURE_STACK_BACK_TRACE pRtlCaptureStackBackTrace;
BOOL
InitDebugSock(
VOID
)
{
memset( GlobalSockEntry, 0x0, sizeof(GlobalSockEntry) );
GlobalSocketsCount = 0;
if (!DebugSockLock.Init())
{
INET_ASSERT(FALSE);
return FALSE;
}
else
{
return TRUE;
}
}
VOID
TerminateDebugSock(
VOID
)
{
DebugSockLock.FreeLock();
}
VOID
SetupSocketsTracing(
VOID
)
{
if (!(InternetDebugCategoryFlags & DBG_TRACE_SOCKETS)) {
return ;
}
if (!IsPlatformWinNT()) {
return ;
}
if ((NtDllHandle = LoadLibrary("ntdll.dll")) == NULL) {
return ;
}
if ((pRtlCaptureStackBackTrace =
(RTL_CAPTURE_STACK_BACK_TRACE)
GetProcAddress(NtDllHandle, "RtlCaptureStackBackTrace")) == NULL) {
FreeLibrary(NtDllHandle);
return ;
}
//#ifdef DONT_DO_FOR_NOW
_P_accept = _I_accept;
_I_accept = _II_accept;
_P_closesocket = _I_closesocket;
_I_closesocket = _II_closesocket;
_P_socket = _I_socket;
_I_socket = _II_socket;
//#endif
}
VOID
AddSockEntry(
SOCKET S
)
{
DWORD i;
DWORD Hash;
if (!(InternetDebugCategoryFlags & DBG_TRACE_SOCKETS)) {
return ;
}
LOCK_DEBUG_SOCK();
//
// search for a free entry.
//
for( i = 0; i < MAX_SOCK_ENTRIES; i++ ) {
if( GlobalSockEntry[i].Socket == 0 ) {
DWORD Hash;
//
// found a free entry.
//
GlobalSockEntry[i].Socket = S;
//
// get caller stack.
//
#if i386
Hash = 0;
GlobalSockEntry[i].StackTraceLength =
pRtlCaptureStackBackTrace(
2,
MAX_STACK_TRACE,
GlobalSockEntry[i].StackTrace,
&Hash );
#else // i386
GlobalSockEntry[i].StackTraceLength = 0;
#endif // i386
GlobalSocketsCount++;
DEBUG_PRINT(SOCKETS,
INFO,
("socket count = %ld\n",
GlobalSocketsCount
));
DPRINTF("%d sockets\n", GlobalSocketsCount);
UNLOCK_DEBUG_SOCK();
return;
}
}
//
// we have reached a high handle limit, which is unusal, needs to be
// debugged.
//
INET_ASSERT( FALSE );
UNLOCK_DEBUG_SOCK();
return;
}
VOID
RemoveSockEntry(
SOCKET S
)
{
DWORD i;
if (!(InternetDebugCategoryFlags & DBG_TRACE_SOCKETS)) {
return ;
}
LOCK_DEBUG_SOCK();
for( i = 0; i < MAX_SOCK_ENTRIES; i++ ) {
if( GlobalSockEntry[i].Socket == S ) {
//
// found the entry. Free it now.
//
memset( &GlobalSockEntry[i], 0x0, sizeof(DEBUG_SOCK_ENTRY) );
GlobalSocketsCount--;
#ifdef IWINSOCK_DEBUG_PRINT
DEBUG_PRINT(SOCKETS,
INFO,
("count(%ld), RemoveSock(%lx)\n",
GlobalSocketsCount,
S
));
#endif // IWINSOCK_DEBUG_PRINT
DPRINTF("%d sockets\n", GlobalSocketsCount);
UNLOCK_DEBUG_SOCK();
return;
}
}
#ifdef IWINSOCK_DEBUG_PRINT
DEBUG_PRINT(SOCKETS,
INFO,
("count(%ld), UnknownSock(%lx)\n",
GlobalSocketsCount,
S
));
#endif // IWINSOCK_DEBUG_PRINT
//
// socket entry is not found.
//
// INET_ASSERT( FALSE );
UNLOCK_DEBUG_SOCK();
return;
}
SOCKET
PASCAL FAR
_II_socket(
int af,
int type,
int protocol
)
{
SOCKET S;
S = _P_socket( af, type, protocol );
AddSockEntry( S );
return( S );
}
int
PASCAL FAR
_II_closesocket(
SOCKET s
)
{
int Ret;
RemoveSockEntry( s );
Ret = _P_closesocket( s );
return( Ret );
}
SOCKET
PASCAL FAR
_II_accept(
SOCKET s,
struct sockaddr FAR *addr,
int FAR *addrlen
)
{
SOCKET S;
S = _P_accept( s, addr, addrlen );
AddSockEntry( S );
return( S );
}
VOID
IWinsockCheckSockets(
VOID
)
{
DEBUG_PRINT(SOCKETS,
INFO,
("GlobalSocketsCount = %d\n",
GlobalSocketsCount
));
for (DWORD i = 0; i < MAX_SOCK_ENTRIES; ++i) {
SOCKET sock;
if ((sock = GlobalSockEntry[i].Socket) != 0) {
DEBUG_PRINT(SOCKETS,
INFO,
("Socket %#x\n",
sock
));
}
}
}
#endif // INET_DEBUG
#if defined(__cplusplus)
}
#endif