Index: dll/win32/msafd/misc/dllmain.c =================================================================== --- dll/win32/msafd/misc/dllmain.c (revision 72964) +++ dll/win32/msafd/misc/dllmain.c (working copy) @@ -352,7 +352,13 @@ /* Save Group Info */ if (g != 0) { - GetSocketInformation(Socket, AFD_INFO_GROUP_ID_TYPE, NULL, NULL, &GroupData); + GetSocketInformation(Socket, + AFD_INFO_GROUP_ID_TYPE, + NULL, + NULL, + &GroupData, + NULL, + NULL); Socket->SharedData->GroupID = GroupData.u.LowPart; Socket->SharedData->GroupType = GroupData.u.HighPart; } @@ -362,6 +368,8 @@ AFD_INFO_SEND_WINDOW_SIZE, NULL, &Socket->SharedData->SizeOfSendBuffer, + NULL, + NULL, NULL); GetSocketInformation (Socket, @@ -368,6 +376,8 @@ AFD_INFO_RECEIVE_WINDOW_SIZE, NULL, &Socket->SharedData->SizeOfRecvBuffer, + NULL, + NULL, NULL); ok: @@ -671,6 +681,8 @@ AFD_INFO_SENDS_IN_PROGRESS, NULL, &SendsInProgress, + NULL, + NULL, NULL)) { /* Bail out if anything but NO_ERROR */ @@ -2182,24 +2194,26 @@ OUT LPINT lpErrno) { PSOCKET_INFORMATION Socket = NULL; - BOOLEAN NeedsCompletion; + BOOLEAN NeedsCompletion = lpOverlapped != NULL; BOOLEAN NonBlocking; + INT Errno = NO_ERROR, Ret = SOCKET_ERROR; + DWORD cbRet = 0; - if (!lpcbBytesReturned) - { - *lpErrno = WSAEFAULT; - return SOCKET_ERROR; - } - /* Get the Socket Structure associate to this Socket*/ Socket = GetSocketStructure(Handle); if (!Socket) { - *lpErrno = WSAENOTSOCK; - return SOCKET_ERROR; + if(lpErrno) + *lpErrno = WSAENOTSOCK; + return SOCKET_ERROR; } - *lpcbBytesReturned = 0; + if (!lpcbBytesReturned && !lpOverlapped) + { + if(lpErrno) + *lpErrno = WSAEFAULT; + return SOCKET_ERROR; + } switch( dwIoControlCode ) { @@ -2206,108 +2220,128 @@ case FIONBIO: if( cbInBuffer < sizeof(INT) || IS_INTRESOURCE(lpvInBuffer) ) { - *lpErrno = WSAEFAULT; - return SOCKET_ERROR; + Errno = WSAEFAULT; + break; } NonBlocking = *((PULONG)lpvInBuffer) ? TRUE : FALSE; Socket->SharedData->NonBlocking = NonBlocking ? 1 : 0; - *lpErrno = SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &NonBlocking, NULL, NULL); - if (*lpErrno != NO_ERROR) - return SOCKET_ERROR; - else - return NO_ERROR; + NeedsCompletion = FALSE; + Errno = SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &NonBlocking, NULL, NULL, lpOverlapped, lpCompletionRoutine); + if (Errno == NO_ERROR) + Ret = NO_ERROR; + break; case FIONREAD: if (IS_INTRESOURCE(lpvOutBuffer) || cbOutBuffer == 0) { - *lpcbBytesReturned = sizeof(ULONG); - *lpErrno = WSAEFAULT; - return SOCKET_ERROR; + cbRet = sizeof(ULONG); + Errno = WSAEFAULT; + break; } if (cbOutBuffer < sizeof(ULONG)) { - *lpErrno = WSAEINVAL; - return SOCKET_ERROR; + Errno = WSAEINVAL; + break; } - *lpErrno = GetSocketInformation(Socket, AFD_INFO_RECEIVE_CONTENT_SIZE, NULL, (PULONG)lpvOutBuffer, NULL); - if (*lpErrno != NO_ERROR) - return SOCKET_ERROR; - else - { - *lpcbBytesReturned = sizeof(ULONG); - return NO_ERROR; - } + NeedsCompletion = FALSE; + Errno = GetSocketInformation(Socket, AFD_INFO_RECEIVE_CONTENT_SIZE, NULL, (PULONG)lpvOutBuffer, NULL, lpOverlapped, lpCompletionRoutine); + if (Errno == NO_ERROR) + { + cbRet = sizeof(ULONG); + Ret = NO_ERROR; + } + break; case SIOCATMARK: if (IS_INTRESOURCE(lpvOutBuffer) || cbOutBuffer == 0) { - *lpcbBytesReturned = sizeof(BOOL); - *lpErrno = WSAEFAULT; - return SOCKET_ERROR; + cbRet = sizeof(BOOL); + Errno = WSAEFAULT; + break; } if (cbOutBuffer < sizeof(BOOL)) { - *lpErrno = WSAEINVAL; - return SOCKET_ERROR; + Errno = WSAEINVAL; + break; } /* FIXME: Return false for now */ *(BOOL*)lpvOutBuffer = FALSE; - *lpcbBytesReturned = sizeof(BOOL); - *lpErrno = NO_ERROR; - return NO_ERROR; + cbRet = sizeof(BOOL); + Errno = NO_ERROR; + Ret = NO_ERROR; + break; case SIO_GET_EXTENSION_FUNCTION_POINTER: - *lpErrno = WSAEINVAL; - return SOCKET_ERROR; - + Errno = WSAEINVAL; + break; case SIO_ADDRESS_LIST_QUERY: if (IS_INTRESOURCE(lpvOutBuffer) || cbOutBuffer == 0) { - *lpcbBytesReturned = sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress); - *lpErrno = WSAEFAULT; - return SOCKET_ERROR; + cbRet = sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress); + Errno = WSAEFAULT; + break; } if (cbOutBuffer < sizeof(INT)) { - *lpErrno = WSAEINVAL; - return SOCKET_ERROR; + Errno = WSAEINVAL; + break; } - *lpcbBytesReturned = sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress); + cbRet = sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress); ((SOCKET_ADDRESS_LIST*)lpvOutBuffer)->iAddressCount = 1; if (cbOutBuffer < (sizeof(SOCKET_ADDRESS_LIST) + sizeof(Socket->SharedData->WSLocalAddress))) { - *lpErrno = WSAEFAULT; - return SOCKET_ERROR; + Errno = WSAEFAULT; + break; } ((SOCKET_ADDRESS_LIST*)lpvOutBuffer)->Address[0].iSockaddrLength = sizeof(Socket->SharedData->WSLocalAddress); ((SOCKET_ADDRESS_LIST*)lpvOutBuffer)->Address[0].lpSockaddr = &Socket->SharedData->WSLocalAddress; - *lpErrno = NO_ERROR; - return NO_ERROR; - + Errno = NO_ERROR; + Ret = NO_ERROR; + break; default: - *lpErrno = Socket->HelperData->WSHIoctl(Socket->HelperContext, - Handle, - Socket->TdiAddressHandle, - Socket->TdiConnectionHandle, - dwIoControlCode, - lpvInBuffer, - cbInBuffer, - lpvOutBuffer, - cbOutBuffer, - lpcbBytesReturned, - lpOverlapped, - lpCompletionRoutine, - (LPBOOL)&NeedsCompletion); + Errno = Socket->HelperData->WSHIoctl(Socket->HelperContext, + Handle, + Socket->TdiAddressHandle, + Socket->TdiConnectionHandle, + dwIoControlCode, + lpvInBuffer, + cbInBuffer, + lpvOutBuffer, + cbOutBuffer, + &cbRet, + lpOverlapped, + lpCompletionRoutine, + (LPBOOL)&NeedsCompletion); - if (*lpErrno != NO_ERROR) - return SOCKET_ERROR; - else - return NO_ERROR; + if (Errno == NO_ERROR) + Ret = NO_ERROR; + break; } + if (lpOverlapped && NeedsCompletion) + { + lpOverlapped->Internal = Errno; + lpOverlapped->InternalHigh = cbRet; + if (lpCompletionRoutine != NULL) + { + lpCompletionRoutine(Errno, cbRet, lpOverlapped, 0); + } + if (lpOverlapped->hEvent) + SetEvent(lpOverlapped->hEvent); + if (!PostQueuedCompletionStatus((HANDLE)Handle, cbRet, 0, lpOverlapped)) + { + ERR("PostQueuedCompletionStatus failed %d\n", GetLastError()); + } + return NO_ERROR; + } + if (lpErrno) + *lpErrno = Errno; + if (lpcbBytesReturned) + *lpcbBytesReturned = cbRet; + return Ret; } @@ -2852,7 +2886,17 @@ return 0; } +VOID +NTAPI +AfdInfoAPC(PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG Reserved) +{ + PAFDAPCCONTEXT Context = ApcContext; + Context->lpCompletionRoutine(IoStatusBlock->Status, IoStatusBlock->Information, Context->lpOverlapped, 0); + HeapFree(GlobalHeap, 0, ApcContext); +} int GetSocketInformation(PSOCKET_INFORMATION Socket, @@ -2859,11 +2903,17 @@ ULONG AfdInformationClass, PBOOLEAN Boolean OPTIONAL, PULONG Ulong OPTIONAL, - PLARGE_INTEGER LargeInteger OPTIONAL) + PLARGE_INTEGER LargeInteger OPTIONAL, + LPWSAOVERLAPPED Overlapped OPTIONAL, + LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine OPTIONAL) { - IO_STATUS_BLOCK IOSB; + PIO_STATUS_BLOCK IOSB; + IO_STATUS_BLOCK DummyIOSB; AFD_INFO InfoData; NTSTATUS Status; + PVOID APCContext; + PIO_APC_ROUTINE APCFunction; + HANDLE Event = NULL; HANDLE SockEvent; Status = NtCreateEvent(&SockEvent, @@ -2878,12 +2928,56 @@ /* Set Info Class */ InfoData.InformationClass = AfdInformationClass; + /* Verify if we should use APC */ + if (Overlapped == NULL) + { + /* Not using Overlapped structure, so use normal blocking on event */ + APCContext = NULL; + APCFunction = NULL; + Event = SockEvent; + IOSB = &DummyIOSB; + } + else + { + /* Overlapped request for non overlapped opened socket */ + if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0) + { + TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n"); + return 0; + } + if (CompletionRoutine == NULL) + { + /* Using Overlapped Structure, but no Completition Routine, so no need for APC */ + APCContext = Overlapped; + APCFunction = NULL; + Event = Overlapped->hEvent; + } + else + { + /* Using Overlapped Structure and a Completition Routine, so use an APC */ + APCFunction = &AfdInfoAPC; // should be a private io completition function inside us + APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); + if (!APCContext) + { + ERR("Not enough memory for APC Context\n"); + return WSAEFAULT; + } + ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = CompletionRoutine; + ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = Overlapped; + ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; + } + + IOSB = (PIO_STATUS_BLOCK)&Overlapped->Internal; + } + + IOSB->Status = STATUS_PENDING; + /* Send IOCTL */ Status = NtDeviceIoControlFile((HANDLE)Socket->Handle, - SockEvent, - NULL, - NULL, - &IOSB, + Event, + APCFunction, + APCContext, + IOSB, IOCTL_AFD_GET_INFO, &InfoData, sizeof(InfoData), @@ -2891,12 +2985,20 @@ sizeof(InfoData)); /* Wait for return */ - if (Status == STATUS_PENDING) + if (Status == STATUS_PENDING && Overlapped == NULL) { WaitForSingleObject(SockEvent, INFINITE); - Status = IOSB.Status; + Status = IOSB->Status; } + TRACE("Status %x Information %d\n", Status, IOSB->Information); + + if (Status == STATUS_PENDING) + { + TRACE("Leaving (Pending)\n"); + return WSA_IO_PENDING; + } + if (Status != STATUS_SUCCESS) return -1; @@ -2926,11 +3028,17 @@ ULONG AfdInformationClass, PBOOLEAN Boolean OPTIONAL, PULONG Ulong OPTIONAL, - PLARGE_INTEGER LargeInteger OPTIONAL) + PLARGE_INTEGER LargeInteger OPTIONAL, + LPWSAOVERLAPPED Overlapped OPTIONAL, + LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine OPTIONAL) { - IO_STATUS_BLOCK IOSB; + PIO_STATUS_BLOCK IOSB; + IO_STATUS_BLOCK DummyIOSB; AFD_INFO InfoData; NTSTATUS Status; + PVOID APCContext; + PIO_APC_ROUTINE APCFunction; + HANDLE Event = NULL; HANDLE SockEvent; Status = NtCreateEvent(&SockEvent, @@ -2959,12 +3067,56 @@ InfoData.Information.Boolean = *Boolean; } + /* Verify if we should use APC */ + if (Overlapped == NULL) + { + /* Not using Overlapped structure, so use normal blocking on event */ + APCContext = NULL; + APCFunction = NULL; + Event = SockEvent; + IOSB = &DummyIOSB; + } + else + { + /* Overlapped request for non overlapped opened socket */ + if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0) + { + TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n"); + return 0; + } + if (CompletionRoutine == NULL) + { + /* Using Overlapped Structure, but no Completition Routine, so no need for APC */ + APCContext = Overlapped; + APCFunction = NULL; + Event = Overlapped->hEvent; + } + else + { + /* Using Overlapped Structure and a Completition Routine, so use an APC */ + APCFunction = &AfdInfoAPC; // should be a private io completition function inside us + APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); + if (!APCContext) + { + ERR("Not enough memory for APC Context\n"); + return WSAEFAULT; + } + ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = CompletionRoutine; + ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = Overlapped; + ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; + } + + IOSB = (PIO_STATUS_BLOCK)&Overlapped->Internal; + } + + IOSB->Status = STATUS_PENDING; + /* Send IOCTL */ Status = NtDeviceIoControlFile((HANDLE)Socket->Handle, - SockEvent, - NULL, - NULL, - &IOSB, + Event, + APCFunction, + APCContext, + IOSB, IOCTL_AFD_SET_INFO, &InfoData, sizeof(InfoData), @@ -2972,14 +3124,22 @@ 0); /* Wait for return */ - if (Status == STATUS_PENDING) + if (Status == STATUS_PENDING && Overlapped == NULL) { WaitForSingleObject(SockEvent, INFINITE); - Status = IOSB.Status; + Status = IOSB->Status; } NtClose( SockEvent ); + TRACE("Status %x Information %d\n", Status, IOSB->Information); + + if (Status == STATUS_PENDING) + { + TRACE("Leaving (Pending)\n"); + return WSA_IO_PENDING; + } + return Status == STATUS_SUCCESS ? 0 : -1; } Index: dll/win32/msafd/misc/event.c =================================================================== --- dll/win32/msafd/misc/event.c (revision 72964) +++ dll/win32/msafd/misc/event.c (working copy) @@ -46,7 +46,7 @@ /* Set Socket to Non-Blocking */ BlockMode = TRUE; - SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL, NULL); + SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL, NULL, NULL, NULL); Socket->SharedData->NonBlocking = TRUE; /* Deactivate Async Select if there is one */ Index: dll/win32/msafd/misc/sndrcv.c =================================================================== --- dll/win32/msafd/misc/sndrcv.c (revision 72978) +++ dll/win32/msafd/misc/sndrcv.c (working copy) @@ -45,7 +45,7 @@ /* Change the Socket to Non Blocking */ BlockMode = TRUE; - SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL, NULL); + SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL, NULL, NULL, NULL); Socket->SharedData->NonBlocking = TRUE; /* Deactive WSPEventSelect */ @@ -104,9 +104,8 @@ OUT LPDWORD lpdwFlags, OUT LPINT lpErrno) { - PIO_STATUS_BLOCK IOSB; - NTSTATUS Status; PSOCKET_INFORMATION Socket; + BOOL Ret; TRACE("Called (%x)\n", Handle); @@ -124,36 +123,12 @@ *lpErrno = WSAEFAULT; return FALSE; } - IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; - if (!IOSB) - { - if (lpErrno) - *lpErrno = WSAEFAULT; - return FALSE; - } - Status = IOSB->Status; + Ret = GetOverlappedResult((HANDLE)Handle, lpOverlapped, lpdwBytes, fWait); - /* Wait for completition of overlapped */ - if (Status == STATUS_PENDING) + if (Ret) { - /* It's up to the protocol to time out recv. We must wait - * until the protocol decides it's had enough. - */ - if (fWait) - { - WaitForSingleObject(lpOverlapped->hEvent, INFINITE); - Status = IOSB->Status; - } - } - - TRACE("Status %x Information %d\n", Status, IOSB->Information); - - if (Status != STATUS_PENDING) - { *lpdwFlags = 0; - *lpdwBytes = IOSB->Information; - /* Re-enable Async Event */ SockReenableAsyncSelectEvent(Socket, FD_OOB); SockReenableAsyncSelectEvent(Socket, FD_WRITE); @@ -160,7 +135,7 @@ SockReenableAsyncSelectEvent(Socket, FD_READ); } - return Status == STATUS_SUCCESS; + return Ret; } VOID Index: dll/win32/msafd/msafd.h =================================================================== --- dll/win32/msafd/msafd.h (revision 72966) +++ dll/win32/msafd/msafd.h (working copy) @@ -434,7 +434,9 @@ ULONG AfdInformationClass, PBOOLEAN Boolean OPTIONAL, PULONG Ulong OPTIONAL, - PLARGE_INTEGER LargeInteger OPTIONAL + PLARGE_INTEGER LargeInteger OPTIONAL, + LPWSAOVERLAPPED Overlapped OPTIONAL, + LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine OPTIONAL ); int SetSocketInformation( @@ -442,7 +444,9 @@ ULONG AfdInformationClass, PBOOLEAN Boolean OPTIONAL, PULONG Ulong OPTIONAL, - PLARGE_INTEGER LargeInteger OPTIONAL + PLARGE_INTEGER LargeInteger OPTIONAL, + LPWSAOVERLAPPED Overlapped OPTIONAL, + LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine OPTIONAL ); int CreateContext(