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; PVOID APCFunction; HANDLE Event = NULL; HANDLE SockEvent; PSOCKET_INFORMATION Socket; AFD_DbgPrint(MID_TRACE,("Called (%x)\n", Handle)); /* Get the Socket Structure associate to this Socket*/ Socket = GetSocketStructure(Handle); if (!Socket) { *lpErrno = WSAENOTSOCK; return SOCKET_ERROR; } Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, NULL, 1, 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; } } /* Verifiy 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 { if (lpCompletionRoutine == NULL) { /* Using Overlapped Structure, but no Completition Routine, so no need for APC */ APCContext = lpOverlapped; APCFunction = NULL; Event = lpOverlapped->hEvent; } else { /* Using Overlapped Structure and a Completition Routine, so use an APC */ APCFunction = NULL; // should be a private io completition function inside us APCContext = lpCompletionRoutine; 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 completition 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 ); AFD_DbgPrint(MID_TRACE,("Status %x Information %d\n", Status, IOSB->Information)); /* 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); } return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead ); }
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) { *lpErrno = WSAENOTSOCK; 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, 1, 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; /* Verifiy 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 { if (lpCompletionRoutine == NULL) { /* Using Overlapped Structure, but no Completition Routine, so no need for APC */ APCContext = lpOverlapped; APCFunction = NULL; Event = lpOverlapped->hEvent; } else { /* Using Overlapped Structure and a Completition Routine, so use an APC */ /* Should be a private io completition function inside us */ APCFunction = NULL; APCContext = lpCompletionRoutine; 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 completition of not overlapped */ if (Status == STATUS_PENDING && lpOverlapped == NULL) { /* BUGBUG, shouldn't wait infintely for send... */ WaitForSingleObject(SockEvent, INFINITE); Status = IOSB->Status; } NtClose(SockEvent); HeapFree(GlobalHeap, 0, RemoteAddress); if (BindAddress != NULL) { HeapFree(GlobalHeap, 0, BindAddress); } SockReenableAsyncSelectEvent(Socket, FD_WRITE); return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); }
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) { *lpErrno = WSAENOTSOCK; return SOCKET_ERROR; } Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, NULL, 1, FALSE ); if( !NT_SUCCESS(Status) ) return -1; AFD_DbgPrint(MID_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; } } /* Verifiy 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 { if (lpCompletionRoutine == NULL) { /* Using Overlapped Structure, but no Completition Routine, so no need for APC */ APCContext = lpOverlapped; APCFunction = NULL; Event = lpOverlapped->hEvent; } else { /* Using Overlapped Structure and a Completition Routine, so use an APC */ APCFunction = NULL; // should be a private io completition function inside us APCContext = lpCompletionRoutine; 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 completition of not overlapped */ if (Status == STATUS_PENDING && lpOverlapped == NULL) { WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infintely for send... Status = IOSB->Status; } NtClose( SockEvent ); if (Status == STATUS_PENDING) { AFD_DbgPrint(MID_TRACE,("Leaving (Pending)\n")); return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); } /* Re-enable Async Event */ SockReenableAsyncSelectEvent(Socket, FD_WRITE); AFD_DbgPrint(MID_TRACE,("Leaving (Success, %d)\n", IOSB->Information)); return MsafdReturnWithErrno( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent ); }
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); Socket->SharedData.NonBlocking = TRUE; /* Deactive 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; }
int WSPAPI WSPEventSelect( SOCKET Handle, WSAEVENT hEventObject, long lNetworkEvents, LPINT lpErrno) { IO_STATUS_BLOCK IOSB; AFD_EVENT_SELECT_INFO EventSelectInfo; PSOCKET_INFORMATION Socket = NULL; NTSTATUS Status; BOOLEAN BlockMode; HANDLE SockEvent; Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, NULL, 1, FALSE ); if( !NT_SUCCESS(Status) ) return -1; /* Get the Socket Structure associate to this Socket*/ Socket = GetSocketStructure(Handle); if (!Socket) { NtClose(SockEvent); *lpErrno = WSAENOTSOCK; return SOCKET_ERROR; } /* Set Socket to Non-Blocking */ BlockMode = TRUE; SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL, NULL); Socket->SharedData.NonBlocking = TRUE; /* Deactivate Async Select if there is one */ if (Socket->EventObject) { Socket->SharedData.hWnd = NULL; Socket->SharedData.wMsg = 0; Socket->SharedData.AsyncEvents = 0; Socket->SharedData.SequenceNumber++; // This will kill Async Select after the next completion } /* Set Structure Info */ EventSelectInfo.EventObject = hEventObject; EventSelectInfo.Events = 0; /* Set Events to wait for */ if (lNetworkEvents & FD_READ) { EventSelectInfo.Events |= AFD_EVENT_RECEIVE; } if (lNetworkEvents & FD_WRITE) { EventSelectInfo.Events |= AFD_EVENT_SEND; } if (lNetworkEvents & FD_OOB) { EventSelectInfo.Events |= AFD_EVENT_OOB_RECEIVE; } if (lNetworkEvents & FD_ACCEPT) { EventSelectInfo.Events |= AFD_EVENT_ACCEPT; } if (lNetworkEvents & FD_CONNECT) { EventSelectInfo.Events |= AFD_EVENT_CONNECT | AFD_EVENT_CONNECT_FAIL; } if (lNetworkEvents & FD_CLOSE) { EventSelectInfo.Events |= AFD_EVENT_DISCONNECT | AFD_EVENT_ABORT | AFD_EVENT_CLOSE; } if (lNetworkEvents & FD_QOS) { EventSelectInfo.Events |= AFD_EVENT_QOS; } if (lNetworkEvents & FD_GROUP_QOS) { EventSelectInfo.Events |= AFD_EVENT_GROUP_QOS; } /* Send IOCTL */ Status = NtDeviceIoControlFile((HANDLE)Handle, SockEvent, NULL, NULL, &IOSB, IOCTL_AFD_EVENT_SELECT, &EventSelectInfo, sizeof(EventSelectInfo), NULL, 0); TRACE("AFD: %x\n", Status); /* Wait for return */ if (Status == STATUS_PENDING) { WaitForSingleObject(SockEvent, INFINITE); Status = IOSB.Status; } TRACE("Waited\n"); NtClose( SockEvent ); if (Status != STATUS_SUCCESS) { ERR("Got status 0x%08x.\n", Status); return MsafdReturnWithErrno(Status, lpErrno, 0, NULL); } TRACE("Closed event\n"); /* Set Socket Data*/ Socket->EventObject = hEventObject; Socket->NetworkEvents = lNetworkEvents; TRACE("Leaving\n"); return 0; }
INT WSPAPI WSPEnumNetworkEvents( IN SOCKET Handle, IN WSAEVENT hEventObject, OUT LPWSANETWORKEVENTS lpNetworkEvents, OUT LPINT lpErrno) { AFD_ENUM_NETWORK_EVENTS_INFO EnumReq; IO_STATUS_BLOCK IOSB; PSOCKET_INFORMATION Socket = NULL; NTSTATUS Status; HANDLE SockEvent; TRACE("Called (lpNetworkEvents %x)\n", lpNetworkEvents); Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, NULL, 1, FALSE ); if( !NT_SUCCESS(Status) ) { ERR("Could not make an event %x\n", Status); return -1; } /* Get the Socket Structure associate to this Socket*/ Socket = GetSocketStructure(Handle); if (!Socket) { NtClose(SockEvent); *lpErrno = WSAENOTSOCK; return SOCKET_ERROR; } EnumReq.Event = hEventObject; /* Send IOCTL */ Status = NtDeviceIoControlFile((HANDLE)Handle, SockEvent, NULL, NULL, &IOSB, IOCTL_AFD_ENUM_NETWORK_EVENTS, &EnumReq, sizeof(EnumReq), NULL, 0); TRACE("AFD: %x\n", Status); /* Wait for return */ if (Status == STATUS_PENDING) { WaitForSingleObject(SockEvent, INFINITE); Status = IOSB.Status; } TRACE("Waited\n"); NtClose( SockEvent ); if (Status != STATUS_SUCCESS) { ERR("Status 0x%08x", Status); return MsafdReturnWithErrno(Status, lpErrno, 0, NULL); } TRACE("Closed event\n"); TRACE("About to touch struct at %x (%d)\n", lpNetworkEvents, sizeof(*lpNetworkEvents)); lpNetworkEvents->lNetworkEvents = 0; /* Set Events to wait for */ if (EnumReq.PollEvents & AFD_EVENT_RECEIVE) { lpNetworkEvents->lNetworkEvents |= FD_READ; lpNetworkEvents->iErrorCode[FD_READ_BIT] = TranslateNtStatusError(EnumReq.EventStatus[FD_READ_BIT]); } if (EnumReq.PollEvents & AFD_EVENT_SEND) { lpNetworkEvents->lNetworkEvents |= FD_WRITE; lpNetworkEvents->iErrorCode[FD_WRITE_BIT] = TranslateNtStatusError(EnumReq.EventStatus[FD_WRITE_BIT]); } if (EnumReq.PollEvents & AFD_EVENT_OOB_RECEIVE) { lpNetworkEvents->lNetworkEvents |= FD_OOB; lpNetworkEvents->iErrorCode[FD_OOB_BIT] = TranslateNtStatusError(EnumReq.EventStatus[FD_OOB_BIT]); } if (EnumReq.PollEvents & AFD_EVENT_ACCEPT) { lpNetworkEvents->lNetworkEvents |= FD_ACCEPT; lpNetworkEvents->iErrorCode[FD_ACCEPT_BIT] = TranslateNtStatusError(EnumReq.EventStatus[FD_ACCEPT_BIT]); } if (EnumReq.PollEvents & (AFD_EVENT_CONNECT | AFD_EVENT_CONNECT_FAIL)) { lpNetworkEvents->lNetworkEvents |= FD_CONNECT; lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = TranslateNtStatusError(EnumReq.EventStatus[FD_CONNECT_BIT]); } if (EnumReq.PollEvents & (AFD_EVENT_DISCONNECT | AFD_EVENT_ABORT | AFD_EVENT_CLOSE)) { lpNetworkEvents->lNetworkEvents |= FD_CLOSE; lpNetworkEvents->iErrorCode[FD_CLOSE_BIT] = TranslateNtStatusError(EnumReq.EventStatus[FD_CLOSE_BIT]); } if (EnumReq.PollEvents & AFD_EVENT_QOS) { lpNetworkEvents->lNetworkEvents |= FD_QOS; lpNetworkEvents->iErrorCode[FD_QOS_BIT] = TranslateNtStatusError(EnumReq.EventStatus[FD_QOS_BIT]); } if (EnumReq.PollEvents & AFD_EVENT_GROUP_QOS) { lpNetworkEvents->lNetworkEvents |= FD_GROUP_QOS; lpNetworkEvents->iErrorCode[FD_GROUP_QOS_BIT] = TranslateNtStatusError(EnumReq.EventStatus[FD_GROUP_QOS_BIT]); } TRACE("Leaving\n"); return MsafdReturnWithErrno(STATUS_SUCCESS, lpErrno, 0, NULL); }