/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Ancillary Function Driver DLL * FILE: dll/win32/msafd/misc/sndrcv.c * PURPOSE: Send/receive routines * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) * Alex Ionescu (alex@relsoft.net) * REVISIONS: * CSH 01/09-2000 Created * Alex 16/07/2004 - Complete Rewrite */ #include INT WSPAPI WSPAsyncSelect(IN SOCKET Handle, IN HWND hWnd, IN UINT wMsg, IN LONG lEvent, OUT LPINT lpErrno) { PSOCKET_INFORMATION Socket = NULL; PASYNC_DATA AsyncData; BOOLEAN BlockMode; /* Get the Socket Structure associated to this Socket */ Socket = GetSocketStructure(Handle); if (!Socket) { *lpErrno = WSAENOTSOCK; return SOCKET_ERROR; } /* Allocate the Async Data Structure to pass on to the Thread later */ AsyncData = HeapAlloc(GetProcessHeap(), 0, sizeof(*AsyncData)); if (!AsyncData) { MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL ); return INVALID_SOCKET; } /* Change the Socket to Non Blocking */ BlockMode = TRUE; SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL, NULL, NULL, NULL); Socket->SharedData->NonBlocking = TRUE; /* Deactivate WSPEventSelect */ if (Socket->SharedData->AsyncEvents) { if (WSPEventSelect(Handle, NULL, 0, lpErrno) == SOCKET_ERROR) { HeapFree(GetProcessHeap(), 0, AsyncData); return SOCKET_ERROR; } } /* Create the Asynch Thread if Needed */ SockCreateOrReferenceAsyncThread(); /* Open a Handle to AFD's Async Helper */ SockGetAsyncSelectHelperAfdHandle(); /* Store Socket Data */ Socket->SharedData->hWnd = hWnd; Socket->SharedData->wMsg = wMsg; Socket->SharedData->AsyncEvents = lEvent; Socket->SharedData->AsyncDisabledEvents = 0; Socket->SharedData->SequenceNumber++; /* Return if there are no more Events */ if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)) == 0) { HeapFree(GetProcessHeap(), 0, AsyncData); return 0; } /* Set up the Async Data */ AsyncData->ParentSocket = Socket; AsyncData->SequenceNumber = Socket->SharedData->SequenceNumber; /* Begin Async Select by using I/O Completion */ NtSetIoCompletion(SockAsyncCompletionPort, (PVOID)&SockProcessQueuedAsyncSelect, AsyncData, 0, 0); /* Return */ return ERROR_SUCCESS; } BOOL WSPAPI WSPGetOverlappedResult( IN SOCKET Handle, IN LPWSAOVERLAPPED lpOverlapped, OUT LPDWORD lpdwBytes, IN BOOL fWait, OUT LPDWORD lpdwFlags, OUT LPINT lpErrno) { PSOCKET_INFORMATION Socket; BOOL Ret; TRACE("Called (%x)\n", Handle); /* Get the Socket Structure associate to this Socket*/ Socket = GetSocketStructure(Handle); if (!Socket) { if(lpErrno) *lpErrno = WSAENOTSOCK; return FALSE; } if (!lpOverlapped || !lpdwBytes || !lpdwFlags) { if (lpErrno) *lpErrno = WSAEFAULT; return FALSE; } Ret = GetOverlappedResult((HANDLE)Handle, lpOverlapped, lpdwBytes, fWait); if (Ret) { *lpdwFlags = 0; /* Re-enable Async Event */ SockReenableAsyncSelectEvent(Socket, FD_OOB); SockReenableAsyncSelectEvent(Socket, FD_WRITE); SockReenableAsyncSelectEvent(Socket, FD_READ); } return Ret; } VOID NTAPI AfdAPC(PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG Reserved) { PAFDAPCCONTEXT Context = ApcContext; /* Re-enable Async Event */ SockReenableAsyncSelectEvent(Context->lpSocket, FD_OOB); SockReenableAsyncSelectEvent(Context->lpSocket, FD_READ); SockReenableAsyncSelectEvent(Context->lpSocket, FD_WRITE); Context->lpCompletionRoutine(IoStatusBlock->Status, IoStatusBlock->Information, Context->lpOverlapped, 0); HeapFree(GlobalHeap, 0, ApcContext); } int WSPAPI WSPRecv(SOCKET Handle, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRead, LPDWORD ReceiveFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno) { PIO_STATUS_BLOCK IOSB; IO_STATUS_BLOCK DummyIOSB; AFD_RECV_INFO RecvInfo; NTSTATUS Status; PVOID APCContext; PIO_APC_ROUTINE APCFunction; HANDLE Event = NULL; HANDLE SockEvent; PSOCKET_INFORMATION Socket; TRACE("Called (%x)\n", Handle); /* Get the Socket Structure associate to this Socket*/ Socket = GetSocketStructure(Handle); if (!Socket) { if (lpErrno) *lpErrno = WSAENOTSOCK; return SOCKET_ERROR; } if (!lpNumberOfBytesRead && !lpOverlapped) { if (lpErrno) *lpErrno = WSAEFAULT; return SOCKET_ERROR; } if (Socket->SharedData->OobInline && ReceiveFlags && (*ReceiveFlags & MSG_OOB) != 0) { if (lpErrno) *lpErrno = WSAEINVAL; return SOCKET_ERROR; } Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE ); if( !NT_SUCCESS(Status) ) return -1; /* Set up the Receive Structure */ RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers; RecvInfo.BufferCount = dwBufferCount; RecvInfo.TdiFlags = 0; RecvInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; /* Set the TDI Flags */ if (*ReceiveFlags == 0) { RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL; } else { if (*ReceiveFlags & MSG_OOB) { RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED; } if (*ReceiveFlags & MSG_PEEK) { RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK; } if (*ReceiveFlags & MSG_PARTIAL) { RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL; } } /* Verify if we should use APC */ if (lpOverlapped == 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 MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesRead); } if (lpCompletionRoutine == NULL) { /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ APCContext = lpOverlapped; APCFunction = NULL; Event = lpOverlapped->hEvent; } else { /* Using Overlapped Structure and a Completion Routine, so use an APC */ APCFunction = &AfdAPC; // should be a private io completion function inside us APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); if (!APCContext) { ERR("Not enough memory for APC Context\n"); return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesRead); } ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; RecvInfo.AfdFlags |= AFD_SKIP_FIO; } IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; RecvInfo.AfdFlags |= AFD_OVERLAPPED; } IOSB->Status = STATUS_PENDING; /* Send IOCTL */ Status = NtDeviceIoControlFile((HANDLE)Handle, Event, APCFunction, APCContext, IOSB, IOCTL_AFD_RECV, &RecvInfo, sizeof(RecvInfo), NULL, 0); /* Wait for completion of not overlapped */ if (Status == STATUS_PENDING && lpOverlapped == NULL) { /* It's up to the protocol to time out recv. We must wait * until the protocol decides it's had enough. */ WaitForSingleObject(SockEvent, INFINITE); Status = IOSB->Status; } NtClose( SockEvent ); TRACE("Status %x Information %d\n", Status, IOSB->Information); if (Status == STATUS_PENDING) { TRACE("Leaving (Pending)\n"); return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead); } /* Return the Flags */ *ReceiveFlags = 0; switch (Status) { case STATUS_RECEIVE_EXPEDITED: *ReceiveFlags = MSG_OOB; break; case STATUS_RECEIVE_PARTIAL_EXPEDITED: *ReceiveFlags = MSG_PARTIAL | MSG_OOB; break; case STATUS_RECEIVE_PARTIAL: *ReceiveFlags = MSG_PARTIAL; break; } /* Re-enable Async Event */ if (*ReceiveFlags & MSG_OOB) { SockReenableAsyncSelectEvent(Socket, FD_OOB); } else { SockReenableAsyncSelectEvent(Socket, FD_READ); } if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) { lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags); HeapFree(GlobalHeap, 0, (PVOID)APCContext); } return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead ); } int WSPAPI WSPRecvFrom(SOCKET Handle, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRead, LPDWORD ReceiveFlags, struct sockaddr *SocketAddress, int *SocketAddressLength, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno ) { PIO_STATUS_BLOCK IOSB; IO_STATUS_BLOCK DummyIOSB; AFD_RECV_INFO_UDP RecvInfo; NTSTATUS Status; PVOID APCContext; PVOID APCFunction; HANDLE Event = NULL; HANDLE SockEvent; PSOCKET_INFORMATION Socket; /* Get the Socket Structure associate to this Socket*/ Socket = GetSocketStructure(Handle); if (!Socket) { if (lpErrno) *lpErrno = WSAENOTSOCK; return SOCKET_ERROR; } if (!lpNumberOfBytesRead && !lpOverlapped) { if (lpErrno) *lpErrno = WSAEFAULT; return SOCKET_ERROR; } if (Socket->SharedData->OobInline && ReceiveFlags && (*ReceiveFlags & MSG_OOB) != 0) { if (lpErrno) *lpErrno = WSAEINVAL; return SOCKET_ERROR; } if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS)) { /* Call WSPRecv for a non-datagram socket */ return WSPRecv(Handle, lpBuffers, dwBufferCount, lpNumberOfBytesRead, ReceiveFlags, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno); } /* Bind us First */ if (Socket->SharedData->State == SocketOpen) { Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext, SocketAddress, SocketAddressLength); /* Bind it */ if (WSPBind(Handle, SocketAddress, *SocketAddressLength, lpErrno) == SOCKET_ERROR) return SOCKET_ERROR; } Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE ); if( !NT_SUCCESS(Status) ) return -1; /* Set up the Receive Structure */ RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers; RecvInfo.BufferCount = dwBufferCount; RecvInfo.TdiFlags = 0; RecvInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; RecvInfo.AddressLength = SocketAddressLength; RecvInfo.Address = SocketAddress; /* Set the TDI Flags */ if (*ReceiveFlags == 0) { RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL; } else { if (*ReceiveFlags & MSG_OOB) { RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED; } if (*ReceiveFlags & MSG_PEEK) { RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK; } if (*ReceiveFlags & MSG_PARTIAL) { RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL; } } /* Verify if we should use APC */ if (lpOverlapped == 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 MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesRead); } if (lpCompletionRoutine == NULL) { /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ APCContext = lpOverlapped; APCFunction = NULL; Event = lpOverlapped->hEvent; } else { /* Using Overlapped Structure and a Completion Routine, so use an APC */ APCFunction = &AfdAPC; // should be a private io completion function inside us APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); if (!APCContext) { ERR("Not enough memory for APC Context\n"); return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesRead); } ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; RecvInfo.AfdFlags |= AFD_SKIP_FIO; } IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; RecvInfo.AfdFlags |= AFD_OVERLAPPED; } IOSB->Status = STATUS_PENDING; /* Send IOCTL */ Status = NtDeviceIoControlFile((HANDLE)Handle, Event, APCFunction, APCContext, IOSB, IOCTL_AFD_RECV_DATAGRAM, &RecvInfo, sizeof(RecvInfo), NULL, 0); /* Wait for completion of not overlapped */ if (Status == STATUS_PENDING && lpOverlapped == NULL) { WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infinitely for receive... Status = IOSB->Status; } NtClose( SockEvent ); if (Status == STATUS_PENDING) { TRACE("Leaving (Pending)\n"); return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead); } /* Return the Flags */ *ReceiveFlags = 0; switch (Status) { case STATUS_RECEIVE_EXPEDITED: *ReceiveFlags = MSG_OOB; break; case STATUS_RECEIVE_PARTIAL_EXPEDITED: *ReceiveFlags = MSG_PARTIAL | MSG_OOB; break; case STATUS_RECEIVE_PARTIAL: *ReceiveFlags = MSG_PARTIAL; break; } /* Re-enable Async Event */ if (*ReceiveFlags & MSG_OOB) { SockReenableAsyncSelectEvent(Socket, FD_OOB); } else { SockReenableAsyncSelectEvent(Socket, FD_READ); } if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) { lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags); HeapFree(GlobalHeap, 0, (PVOID)APCContext); } return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead ); } int WSPAPI WSPSend(SOCKET Handle, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD iFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno) { PIO_STATUS_BLOCK IOSB; IO_STATUS_BLOCK DummyIOSB; AFD_SEND_INFO SendInfo; NTSTATUS Status; PVOID APCContext; PVOID APCFunction; HANDLE Event = NULL; HANDLE SockEvent; PSOCKET_INFORMATION Socket; /* Get the Socket Structure associate to this Socket*/ Socket = GetSocketStructure(Handle); if (!Socket) { if (lpErrno) *lpErrno = WSAENOTSOCK; return SOCKET_ERROR; } if (!lpNumberOfBytesSent && !lpOverlapped) { if (lpErrno) *lpErrno = WSAEFAULT; return SOCKET_ERROR; } Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE ); if( !NT_SUCCESS(Status) ) return -1; TRACE("Called\n"); /* Set up the Send Structure */ SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers; SendInfo.BufferCount = dwBufferCount; SendInfo.TdiFlags = 0; SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; /* Set the TDI Flags */ if (iFlags) { if (iFlags & MSG_OOB) { SendInfo.TdiFlags |= TDI_SEND_EXPEDITED; } if (iFlags & MSG_PARTIAL) { SendInfo.TdiFlags |= TDI_SEND_PARTIAL; } } /* Verify if we should use APC */ if (lpOverlapped == 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 MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent); } if (lpCompletionRoutine == NULL) { /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ APCContext = lpOverlapped; APCFunction = NULL; Event = lpOverlapped->hEvent; } else { /* Using Overlapped Structure and a Completion Routine, so use an APC */ APCFunction = &AfdAPC; // should be a private io completion function inside us APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); if (!APCContext) { ERR("Not enough memory for APC Context\n"); return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent); } ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; SendInfo.AfdFlags |= AFD_SKIP_FIO; } IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; SendInfo.AfdFlags |= AFD_OVERLAPPED; } IOSB->Status = STATUS_PENDING; /* Send IOCTL */ Status = NtDeviceIoControlFile((HANDLE)Handle, Event, APCFunction, APCContext, IOSB, IOCTL_AFD_SEND, &SendInfo, sizeof(SendInfo), NULL, 0); /* Wait for completion of not overlapped */ if (Status == STATUS_PENDING && lpOverlapped == NULL) { WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infinitely for send... Status = IOSB->Status; } NtClose( SockEvent ); if (Status == STATUS_PENDING) { TRACE("Leaving (Pending)\n"); return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); } /* Re-enable Async Event */ SockReenableAsyncSelectEvent(Socket, FD_WRITE); TRACE("Leaving (Success, %d)\n", IOSB->Information); if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) { lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0); HeapFree(GlobalHeap, 0, (PVOID)APCContext); } return MsafdReturnWithErrno( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent ); } int WSPAPI WSPSendTo(SOCKET Handle, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD iFlags, const struct sockaddr *SocketAddress, int SocketAddressLength, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno) { PIO_STATUS_BLOCK IOSB; IO_STATUS_BLOCK DummyIOSB; AFD_SEND_INFO_UDP SendInfo; NTSTATUS Status; PVOID APCContext; PVOID APCFunction; HANDLE Event = NULL; PTRANSPORT_ADDRESS RemoteAddress; PSOCKADDR BindAddress = NULL; INT BindAddressLength; HANDLE SockEvent; PSOCKET_INFORMATION Socket; /* Get the Socket Structure associate to this Socket */ Socket = GetSocketStructure(Handle); if (!Socket) { if (lpErrno) *lpErrno = WSAENOTSOCK; return SOCKET_ERROR; } if (!lpNumberOfBytesSent && !lpOverlapped) { if (lpErrno) *lpErrno = WSAEFAULT; return SOCKET_ERROR; } if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS)) { /* Use WSPSend for connection-oriented sockets */ return WSPSend(Handle, lpBuffers, dwBufferCount, lpNumberOfBytesSent, iFlags, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno); } /* Bind us First */ if (Socket->SharedData->State == SocketOpen) { /* Get the Wildcard Address */ BindAddressLength = Socket->HelperData->MaxWSAddressLength; BindAddress = HeapAlloc(GlobalHeap, 0, BindAddressLength); if (!BindAddress) { MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL); return INVALID_SOCKET; } Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext, BindAddress, &BindAddressLength); /* Bind it */ if (WSPBind(Handle, BindAddress, BindAddressLength, lpErrno) == SOCKET_ERROR) return SOCKET_ERROR; } RemoteAddress = HeapAlloc(GlobalHeap, 0, 0x6 + SocketAddressLength); if (!RemoteAddress) { if (BindAddress != NULL) { HeapFree(GlobalHeap, 0, BindAddress); } return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL); } Status = NtCreateEvent(&SockEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE); if (!NT_SUCCESS(Status)) { HeapFree(GlobalHeap, 0, RemoteAddress); if (BindAddress != NULL) { HeapFree(GlobalHeap, 0, BindAddress); } return SOCKET_ERROR; } /* Set up Address in TDI Format */ RemoteAddress->TAAddressCount = 1; RemoteAddress->Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family); RtlCopyMemory(&RemoteAddress->Address[0].AddressType, SocketAddress, SocketAddressLength); /* Set up Structure */ SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers; SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; SendInfo.BufferCount = dwBufferCount; SendInfo.TdiConnection.RemoteAddress = RemoteAddress; SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength; /* Verify if we should use APC */ if (lpOverlapped == 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 MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent); } if (lpCompletionRoutine == NULL) { /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ APCContext = lpOverlapped; APCFunction = NULL; Event = lpOverlapped->hEvent; } else { /* Using Overlapped Structure and a Completion Routine, so use an APC */ APCFunction = &AfdAPC; // should be a private io completion function inside us APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); if (!APCContext) { ERR("Not enough memory for APC Context\n"); return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent); } ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; SendInfo.AfdFlags |= AFD_SKIP_FIO; } IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; SendInfo.AfdFlags |= AFD_OVERLAPPED; } /* Send IOCTL */ Status = NtDeviceIoControlFile((HANDLE)Handle, Event, APCFunction, APCContext, IOSB, IOCTL_AFD_SEND_DATAGRAM, &SendInfo, sizeof(SendInfo), NULL, 0); /* Wait for completion of not overlapped */ if (Status == STATUS_PENDING && lpOverlapped == NULL) { /* BUGBUG, shouldn't wait infinitely for send... */ WaitForSingleObject(SockEvent, INFINITE); Status = IOSB->Status; } NtClose(SockEvent); HeapFree(GlobalHeap, 0, RemoteAddress); if (BindAddress != NULL) { HeapFree(GlobalHeap, 0, BindAddress); } if (Status == STATUS_PENDING) { TRACE("Leaving (Pending)\n"); return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); } SockReenableAsyncSelectEvent(Socket, FD_WRITE); if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) { lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0); HeapFree(GlobalHeap, 0, (PVOID)APCContext); } return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); } INT WSPAPI WSPRecvDisconnect(IN SOCKET s, OUT LPWSABUF lpInboundDisconnectData, OUT LPINT lpErrno) { UNIMPLEMENTED; return 0; } INT WSPAPI WSPSendDisconnect(IN SOCKET s, IN LPWSABUF lpOutboundDisconnectData, OUT LPINT lpErrno) { UNIMPLEMENTED; return 0; } /* EOF */