/*++ Copyright (c) 1992 Microsoft Corporation Module Name: Wsraw.h Abstract: Support for extended winsock calls for WOW. Author: David Treadwell (davidtr) 02-Oct-1992 Revision History: --*/ #include "precomp.h" #pragma hdrstop #include "wsdynmc.h" DLLENTRYPOINTS wsockapis[WOW_WSOCKAPI_COUNT] = { (char *) 1, NULL, (char *) 2, NULL, (char *) 3, NULL, (char *) 4, NULL, (char *) 5, NULL, (char *) 6, NULL, (char *) 7, NULL, (char *) 8, NULL, (char *) 9, NULL, (char *) 10, NULL, (char *) 11, NULL, (char *) 12, NULL, (char *) 13, NULL, (char *) 14, NULL, (char *) 15, NULL, (char *) 16, NULL, (char *) 17, NULL, (char *) 18, NULL, (char *) 19, NULL, (char *) 20, NULL, (char *) 21, NULL, (char *) 22, NULL, (char *) 23, NULL, (char *) 51, NULL, (char *) 52, NULL, (char *) 53, NULL, (char *) 54, NULL, (char *) 55, NULL, (char *) 56, NULL, (char *) 57, NULL, (char *) 101, NULL, (char *) 102, NULL, (char *) 103, NULL, (char *) 104, NULL, (char *) 105, NULL, (char *) 106, NULL, (char *) 107, NULL, (char *) 108, NULL, (char *) 109, NULL, (char *) 110, NULL, (char *) 111, NULL, (char *) 112, NULL, (char *) 113, NULL, (char *) 114, NULL, (char *) 115, NULL, (char *) 116, NULL, (char *) 151, NULL, (char *) 1000, NULL, (char *) 1107, NULL}; DWORD WWS32TlsSlot = 0xFFFFFFFF; RTL_CRITICAL_SECTION WWS32CriticalSection; BOOL WWS32Initialized = FALSE; LIST_ENTRY WWS32AsyncContextBlockListHead; WORD WWS32AsyncTaskHandleCounter; DWORD WWS32ThreadSerialNumberCounter; HINSTANCE hInstWSOCK32; DWORD WWS32CallBackHandler ( VOID ); BOOL WWS32DefaultBlockingHook ( VOID ); /*++ GENERIC FUNCTION PROTOTYPE: ========================== ULONG FASTCALL WWS32(PVDMFRAME pFrame) { ULONG ul; register P16 parg16; GETARGPTR(pFrame, sizeof(16), parg16); ALLOCVDMPTR GETVDMPTR GETMISCPTR et cetera 32 bit space> ul = GET16((parg16->f1, : : parg16->f); 16 bit space> FLUSHVDMPTR FREEARGPTR(parg16); RETURN(ul); } NOTE: The VDM frame is automatically set up, with all the function parameters available via parg16->f. Handles must ALWAYS be mapped for 16 -> 32 -> 16 space via the mapping tables laid out in WALIAS.C. Any storage you allocate must be freed (eventually...). Further to that - if a thunk which allocates memory fails in the 32 bit call then it must free that memory. Also, never update structures in 16 bit land if the 32 bit call fails. Be aware that the GETxxxPTR macros return the CURRENT selector-to-flat_memory mapping. Calls to some 32-bit functions may indirectly cause callbacks into 16-bit code. These may cause 16-bit memory to move due to allocations made in 16-bit land. If the 16-bit memory does move, the corresponding 32-bit ptr in WOW32 needs to be refreshed to reflect the NEW selector-to-flat_memory mapping. --*/ ULONG FASTCALL WWS32WSAAsyncSelect(PVDMFRAME pFrame) { ULONG ul; register PWSAASYNCSELECT16 parg16; SOCKET s32; if ( !WWS32IsThreadInitialized ) { SetLastError( WSANOTINITIALISED ); RETURN((ULONG)SOCKET_ERROR); } GETARGPTR(pFrame, sizeof(WSAASYNCSELECT16), parg16); // // Find the 32-bit socket handle. // s32 = GetWinsock32( parg16->hSocket ); if ( s32 == INVALID_SOCKET ) { (*wsockapis[WOW_WSASETLASTERROR].lpfn)( WSAENOTSOCK ); ul = (ULONG)GETWORD16( SOCKET_ERROR ); } else { ul = GETWORD16( (*wsockapis[WOW_WSAASYNCSELECT].lpfn)( s32, (HWND)HWND32(parg16->hWnd), (parg16->wMsg << 16) | WWS32_MESSAGE_ASYNC_SELECT, parg16->lEvent )); } FREEARGPTR(parg16); RETURN(ul); } // WWS32WSAAsyncSelect ULONG FASTCALL WWS32WSASetBlockingHook(PVDMFRAME pFrame) { ULONG ul; VPWNDPROC vpBlockFunc; //FARPROC previousHook; register PWSASETBLOCKINGHOOK16 parg16; GETARGPTR(pFrame, sizeof(WSASETBLOCKINGHOOK16), parg16); vpBlockFunc = parg16->lpBlockFunc; if ( !WWS32IsThreadInitialized ) { SetLastError( WSANOTINITIALISED ); RETURN((ULONG)NULL); } if ( (*wsockapis[WOW_WSAISBLOCKING].lpfn)( ) ) { SetLastError( WSAEINPROGRESS ); RETURN((ULONG)NULL); } ul = WWS32vBlockingHook; WWS32vBlockingHook = vpBlockFunc; FREEARGPTR( parg16 ); RETURN(ul); } // WWS32WSASetBlockingHook ULONG FASTCALL WWS32WSAUnhookBlockingHook(PVDMFRAME pFrame) { if ( !WWS32IsThreadInitialized ) { SetLastError( WSANOTINITIALISED ); RETURN((ULONG)SOCKET_ERROR); } if ( (*wsockapis[WOW_WSAISBLOCKING].lpfn) ) { SetLastError( WSAEINPROGRESS ); RETURN((ULONG)SOCKET_ERROR); } WWS32vBlockingHook = WWS32_DEFAULT_BLOCKING_HOOK; RETURN(0); } // WWS32WSAUnhookBlockingHook ULONG FASTCALL WWS32WSAGetLastError(PVDMFRAME pFrame) { ULONG ul; ul = GETWORD16( (*wsockapis[WOW_WSAGETLASTERROR].lpfn)( ) ); RETURN(ul); } // WWS32WSAGetLastError ULONG FASTCALL WWS32WSASetLastError(PVDMFRAME pFrame) { register PWSASETLASTERROR16 parg16; GETARGPTR(pFrame, sizeof(WSASETLASTERROR16), parg16); (*wsockapis[WOW_WSASETLASTERROR].lpfn)( FETCHWORD( parg16->Error ) ); FREEARGPTR(parg16); RETURN(0); } // WWS32WSASetLastError ULONG FASTCALL WWS32WSACancelBlockingCall(PVDMFRAME pFrame) { ULONG ul; if ( !WWS32IsThreadInitialized ) { SetLastError( WSANOTINITIALISED ); RETURN((ULONG)SOCKET_ERROR); } ul = GETWORD16((*wsockapis[WOW_WSACANCELBLOCKINGCALL].lpfn)( )); RETURN(ul); } // WWS32WSACancelBlockingCall ULONG FASTCALL WWS32WSAIsBlocking(PVDMFRAME pFrame) { ULONG ul; if ( !WWS32IsThreadInitialized ) { SetLastError( WSANOTINITIALISED ); RETURN((ULONG)FALSE); } ul = GETWORD16((*wsockapis[WOW_WSAISBLOCKING].lpfn)( )); RETURN(ul); } // WWS32WSAIsBlocking ULONG FASTCALL WWS32WSAStartup(PVDMFRAME pFrame) { ULONG ul = 0; register PWSASTARTUP16 parg16; PWSADATA16 wsaData16; PWINSOCK_THREAD_DATA data; NTSTATUS status; FARPROC previousHook; PSZ description; PSZ systemStatus; WORD versionRequested; VPWSADATA16 vpwsaData16; GETARGPTR(pFrame, sizeof(WSASTARTUP16), parg16); vpwsaData16 = parg16->lpWSAData; versionRequested = INT32(parg16->wVersionRequired); // // If winsock has not yet been initialized, initialize data structures // now. // if ( !WWS32Initialized ) { WSADATA wsaData; InitializeListHead( &WWS32AsyncContextBlockListHead ); InitializeListHead( &WWS32SocketHandleListHead ); WWS32AsyncTaskHandleCounter = 1; WWS32SocketHandleCounter = 1; WWS32SocketHandleCounterWrapped = FALSE; WWS32ThreadSerialNumberCounter = 1; // // Load WSOCK32.DLL and initialize all the entry points. // if (!LoadLibraryAndGetProcAddresses ("WSOCK32.DLL", wsockapis, WOW_WSOCKAPI_COUNT)) { LOGDEBUG (LOG_ALWAYS, ("WOW::WWS32WSAStartup: LoadLibrary failed\n")); ul = GETWORD16(WSAENOBUFS); return (ul); } // // Initialize the ntvdm process to the 32-bit Windows Sockets // DLL. // ul = (*wsockapis[WOW_WSASTARTUP].lpfn)( MAKEWORD( 1, 1 ), &wsaData ); if ( ul != NO_ERROR ) { RETURN(ul); } // // Initialize the critical section we'll use for synchronizing // async requests. // status = RtlInitializeCriticalSection( &WWS32CriticalSection ); if ( !NT_SUCCESS(status) ) { ul = GETWORD16(WSAENOBUFS); RETURN(ul); } // // Get a slot in TLS. // WWS32TlsSlot = TlsAlloc( ); if ( WWS32TlsSlot == 0xFFFFFFFF ) { RtlDeleteCriticalSection( &WWS32CriticalSection ); ul = GETWORD16(WSAENOBUFS); RETURN(ul); } WWS32Initialized = TRUE; } // // Make sure that we're not in a blocking call. // if ( (*wsockapis[WOW_WSAISBLOCKING].lpfn)( ) ) { RETURN((ULONG)WSAEINPROGRESS); } // // If this thread has not already had a WSAStartup() call, allocate // and initialize per-thread data. // if ( !WWS32IsThreadInitialized ) { // // We support versions 1.0 and 1.1 of the Windows Sockets // specification. If the requested version is below that, fail. // if ( LOBYTE(versionRequested) < 1 ) { ul = WSAVERNOTSUPPORTED; RETURN(ul); } // // Allocate space for the per-thread data that we need. Note that // we set the value in the TSL slot regardless of whether we actually // managed to allocate the memory--this is because we want NULL // in the TLS slot if we couldn't properly allocate the storage. // data = malloc_w( sizeof(*data) ); if ( !TlsSetValue( WWS32TlsSlot, (LPVOID)data ) || data == NULL ) { ul = GETWORD16(WSAENOBUFS); if ( data != NULL ) { free_w( (PVOID)data ); } FREEARGPTR( parg16 ); RETURN(ul); } // // Initialize the blocking hook. // WWS32vBlockingHook = WWS32_DEFAULT_BLOCKING_HOOK; // // Allocate the individual data objects we need for this task. // data->vIpAddress = GlobalAllocLock16( GMEM_MOVEABLE, 256, NULL ); if ( data->vIpAddress == 0 ) { free_w( (PVOID)data ); TlsSetValue( WWS32TlsSlot, NULL ); FREEARGPTR( parg16 ); RETURN(ul); } data->vHostent = GlobalAllocLock16( GMEM_MOVEABLE, MAXGETHOSTSTRUCT, NULL ); if ( data->vHostent == 0 ) { GlobalUnlockFree16( data->vIpAddress ); free_w( (PVOID)data ); TlsSetValue( WWS32TlsSlot, NULL ); FREEARGPTR( parg16 ); RETURN(ul); } data->vServent = GlobalAllocLock16( GMEM_MOVEABLE, MAXGETHOSTSTRUCT, NULL ); if ( data->vServent == 0 ) { GlobalUnlockFree16( data->vIpAddress ); GlobalUnlockFree16( data->vHostent ); free_w( (PVOID)data ); TlsSetValue( WWS32TlsSlot, NULL ); FREEARGPTR( parg16 ); RETURN(ul); } data->vProtoent = GlobalAllocLock16( GMEM_MOVEABLE, MAXGETHOSTSTRUCT, NULL ); if ( data->vProtoent == 0 ) { GlobalUnlockFree16( data->vIpAddress ); GlobalUnlockFree16( data->vHostent ); GlobalUnlockFree16( data->vServent ); free_w( (PVOID)data ); TlsSetValue( WWS32TlsSlot, NULL ); FREEARGPTR( parg16 ); RETURN(ul); } // // Initialize other per-thread data. // WWS32ThreadSerialNumber = WWS32ThreadSerialNumberCounter++; WWS32ThreadStartupCount = 1; // // If they requested version 1.0, give them 1.0. If they // requested anything else (has to be higher than 1.0 due to // above test), then give them 1.1. We only support 1.0 // and 1.1. If they can't handle 1.1, they will call // WSAStartup() and fail. // if ( versionRequested == 0x0001 ) { WWS32ThreadVersion = 0x0001; } else { WWS32ThreadVersion = 0x0101; } // // Set up the blocking hook. We always use this blocking hook, // even for the default case. // previousHook = (FARPROC) (*wsockapis[WOW_WSASETBLOCKINGHOOK].lpfn)( (FARPROC)WWS32CallBackHandler ); // // Set up the routine we'll use in leiu of wsock32.dll posting // messages directly to the application. We need to intervene // on all posts because we need to convert 32-bit arguments to // 16-bit. // (*wsockapis[WOW_WSAPSETPOSTROUTINE].lpfn)( WWS32DispatchPostMessage ); } else { // // This thread has already had a WSAStartup() call. Make sure // that they're requesting the same version as before. // if ( versionRequested != WWS32ThreadVersion ) { ul = WSAVERNOTSUPPORTED; RETURN(ul); } // // Increment the count of WSAStartup() calls for the thread. // WWS32ThreadStartupCount++; } // // Get a 32-bit pointer to the 16-bit WSADATA structure and // initialize the caller's WSAData structure. // GETVDMPTR( vpwsaData16, sizeof(WSADATA16), wsaData16 ); STOREWORD( wsaData16->wVersion, WWS32ThreadVersion ); STOREWORD( wsaData16->wHighVersion, MAKEWORD(1, 1) ); description = "Windows NT 16-bit Windows Sockets"; RtlCopyMemory( wsaData16->szDescription, description, strlen(description) + 1 ); systemStatus = "Running."; RtlCopyMemory( wsaData16->szSystemStatus, systemStatus, strlen(systemStatus) + 1 ); STOREWORD( wsaData16->iMaxSockets, 0xFFFF ); STOREWORD( wsaData16->iMaxUdpDg, 8096 ); STOREDWORD( wsaData16->lpVendorInfo, 0 ); FLUSHVDMPTR( vpwsaData16, sizeof(WSADATA16), wsaData16 ); FREEVDMPTR( wsaData16 ); FREEARGPTR( parg16 ); RETURN(ul); } // WWS32WSAStartup ULONG FASTCALL WWS32WSACleanup(PVDMFRAME pFrame) { ULONG ul = 0; if ( !WWS32IsThreadInitialized ) { SetLastError( WSANOTINITIALISED ); RETURN((ULONG)SOCKET_ERROR); } if ( (*wsockapis[WOW_WSAISBLOCKING].lpfn)( ) ) { SetLastError( WSAEINPROGRESS ); RETURN((ULONG)SOCKET_ERROR); } WWS32ThreadStartupCount--; if ( WWS32ThreadStartupCount == 0 ) { WWS32TaskCleanup( ); } RETURN(ul); } // WWS32WSACleanup VOID WWS32TaskCleanup( VOID ) { LIST_ENTRY listHead; PWINSOCK_THREAD_DATA data; PLIST_ENTRY listEntry; PWINSOCK_SOCKET_INFO socketInfo; struct linger lingerInfo; int err; // // Get a pointer to the thread's data and set the TLS slot for // this thread to NULL so that we know that the thread is no // longer initialized. // data = TlsGetValue( WWS32TlsSlot ); ASSERT( data != NULL ); TlsSetValue( WWS32TlsSlot, NULL ); // // Free thread data user for the database calls. // GlobalUnlockFree16( data->vIpAddress ); GlobalUnlockFree16( data->vHostent ); GlobalUnlockFree16( data->vServent ); GlobalUnlockFree16( data->vProtoent ); // // Close all sockets that the thread has opened. We first find // all the sockets for this thread, remove them from the global // list, and place them onto a local list. Then we close each // socket. We do this as two steps because we can't hold the // critical section while calling wsock32 in order to avoid // deadlocks. // RtlEnterCriticalSection( &WWS32CriticalSection ); InitializeListHead( &listHead ); for ( listEntry = WWS32SocketHandleListHead.Flink; listEntry != &WWS32SocketHandleListHead; listEntry = listEntry->Flink ) { socketInfo = CONTAINING_RECORD( listEntry, WINSOCK_SOCKET_INFO, GlobalSocketListEntry ); if ( socketInfo->ThreadSerialNumber == data->ThreadSerialNumber ) { // // The socket was opened by this thread. We need to // first remove the entry from the global list, but // maintain the listEntry local variable so that we can // still walk the list. // listEntry = socketInfo->GlobalSocketListEntry.Blink; RemoveEntryList( &socketInfo->GlobalSocketListEntry ); // // Now insert the entry on our local list. // InsertTailList( &listHead, &socketInfo->GlobalSocketListEntry ); } } RtlLeaveCriticalSection( &WWS32CriticalSection ); // // Walk through the sockets opened by this thread and close them // abortively. // for ( listEntry = listHead.Flink; listEntry != &listHead; listEntry = listEntry->Flink ) { // // Close it abortively and free the handle. // socketInfo = CONTAINING_RECORD( listEntry, WINSOCK_SOCKET_INFO, GlobalSocketListEntry ); lingerInfo.l_onoff = 1; lingerInfo.l_linger = 0; err = (*wsockapis[WOW_SETSOCKOPT].lpfn)( socketInfo->SocketHandle32, SOL_SOCKET, SO_LINGER, (char *)&lingerInfo, sizeof(lingerInfo) ); //ASSERT( err == NO_ERROR ); err = (*wsockapis[WOW_CLOSESOCKET].lpfn)( socketInfo->SocketHandle32 ); ASSERT( err == NO_ERROR ); // // When we free the handle the socketInfo structure will // also be freed. Set the list pointer to the entry // prior to this one so that we can successfully walk // the list. // listEntry = socketInfo->GlobalSocketListEntry.Blink; RemoveEntryList( &socketInfo->GlobalSocketListEntry ); free_w( (PVOID)socketInfo ); } // // Set the TLS slot for this thread to NULL so that we know // that the thread is not initialized. // err = TlsSetValue( WWS32TlsSlot, NULL ); ASSERT( err ); // // Free the structure that holds thread information. // free_w( (PVOID)data ); } // WWS32TaskCleanup ULONG FASTCALL WWS32__WSAFDIsSet(PVDMFRAME pFrame) { ULONG ul; register P__WSAFDISSET16 parg16; PFD_SET16 fdSet16; PFD_SET fdSet32; if ( !WWS32IsThreadInitialized ) { SetLastError( WSANOTINITIALISED ); RETURN((ULONG)FALSE); } GETARGPTR( pFrame, sizeof(__WSAFDISSET16), parg16 ); GETVDMPTR( parg16->Set, sizeof(FD_SET16), fdSet16 ); fdSet32 = AllocateFdSet32( fdSet16 ); if ( fdSet32 != NULL ) { ConvertFdSet16To32( fdSet16, fdSet32 ); ul = (*wsockapis[WOW_WSAFDISSET].lpfn)( GetWinsock32( parg16->hSocket ), fdSet32 ); free_w( (PVOID)fdSet32 ); } else { ul = 0; } FREEARGPTR(parg16); RETURN(ul); } // WWS32__WSAFDIsSet PWINSOCK_POST_ROUTINE WWS32PostDispatchTable[] = { WWS32PostAsyncSelect, WWS32PostAsyncGetHost, WWS32PostAsyncGetProto, WWS32PostAsyncGetServ }; BOOL WWS32DispatchPostMessage ( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ) { ASSERT( WWS32PostDispatchTable[WWS32_MESSAGE_ASYNC_SELECT] == WWS32PostAsyncSelect ); ASSERT( WWS32PostDispatchTable[WWS32_MESSAGE_ASYNC_GETHOST] == WWS32PostAsyncGetHost ); ASSERT( WWS32PostDispatchTable[WWS32_MESSAGE_ASYNC_GETPROTO] == WWS32PostAsyncGetProto ); ASSERT( WWS32PostDispatchTable[WWS32_MESSAGE_ASYNC_GETSERV] == WWS32PostAsyncGetServ ); ASSERT( (Msg & 0xFFFF) <= WWS32_MESSAGE_ASYNC_GETSERV ); // // Call the routine that will handle the message. The low word // of Msg specifies the routine, the high word of Msg is the // 16-bit message that that routine will post. // return WWS32PostDispatchTable[Msg & 0xFFFF]( hWnd, Msg, wParam, lParam ); } // WWS32DispatchPostMessage BOOL WWS32PostAsyncSelect ( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ) { HAND16 h16; h16 = GetWinsock16( wParam, 0 ); if( h16 == 0 ) { return TRUE; } return PostMessage( hWnd, Msg >> 16, h16, lParam ); } // WWS32PostAsyncSelect DWORD WWS32CallBackHandler ( VOID ) { VPVOID ret; // // If the default blocking hook is in force, use it. Otherwise, // call back into the application's blocking hook. // if ( WWS32vBlockingHook == WWS32_DEFAULT_BLOCKING_HOOK ) { return WWS32DefaultBlockingHook( ); } (VOID)CallBack16( RET_WINSOCKBLOCKHOOK, NULL, WWS32vBlockingHook, &ret ); return ret & 0xFF; } // WWS32CallBackHandler BOOL WWS32DefaultBlockingHook ( VOID ) { MSG msg; BOOLEAN retrievedMessage; // // Get the next message for this thread, if any. // retrievedMessage = PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ); // // Process the message if we got one. // if ( retrievedMessage ) { TranslateMessage( (CONST MSG *)&msg ); DispatchMessage( (CONST MSG *)&msg ); } // // If we got a message, indicate that we want to be called again. // return retrievedMessage; } // WWS32DefaultBlockingHook