2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Ancillary Function Driver DLL
5 * PURPOSE: Send/receive routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Alex Ionescu (alex@relsoft.net)
9 * CSH 01/09-2000 Created
10 * Alex 16/07/2004 - Complete Rewrite
17 WSPAsyncSelect(IN SOCKET Handle
,
23 PSOCKET_INFORMATION Socket
= NULL
;
24 PASYNC_DATA AsyncData
;
27 /* Get the Socket Structure associated to this Socket */
28 Socket
= GetSocketStructure(Handle
);
31 *lpErrno
= WSAENOTSOCK
;
35 /* Allocate the Async Data Structure to pass on to the Thread later */
36 AsyncData
= HeapAlloc(GetProcessHeap(), 0, sizeof(*AsyncData
));
39 MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
40 return INVALID_SOCKET
;
43 /* Change the Socket to Non Blocking */
45 SetSocketInformation(Socket
, AFD_INFO_BLOCKING_MODE
, &BlockMode
, NULL
, NULL
);
46 Socket
->SharedData
.NonBlocking
= TRUE
;
48 /* Deactive WSPEventSelect */
49 if (Socket
->SharedData
.AsyncEvents
)
51 if (WSPEventSelect(Handle
, NULL
, 0, lpErrno
) == SOCKET_ERROR
)
53 HeapFree(GetProcessHeap(), 0, AsyncData
);
58 /* Create the Asynch Thread if Needed */
59 SockCreateOrReferenceAsyncThread();
61 /* Open a Handle to AFD's Async Helper */
62 SockGetAsyncSelectHelperAfdHandle();
64 /* Store Socket Data */
65 Socket
->SharedData
.hWnd
= hWnd
;
66 Socket
->SharedData
.wMsg
= wMsg
;
67 Socket
->SharedData
.AsyncEvents
= lEvent
;
68 Socket
->SharedData
.AsyncDisabledEvents
= 0;
69 Socket
->SharedData
.SequenceNumber
++;
71 /* Return if there are no more Events */
72 if ((Socket
->SharedData
.AsyncEvents
& (~Socket
->SharedData
.AsyncDisabledEvents
)) == 0)
74 HeapFree(GetProcessHeap(), 0, AsyncData
);
78 /* Set up the Async Data */
79 AsyncData
->ParentSocket
= Socket
;
80 AsyncData
->SequenceNumber
= Socket
->SharedData
.SequenceNumber
;
82 /* Begin Async Select by using I/O Completion */
83 NtSetIoCompletion(SockAsyncCompletionPort
,
84 (PVOID
)&SockProcessQueuedAsyncSelect
,
96 WSPRecv(SOCKET Handle
,
99 LPDWORD lpNumberOfBytesRead
,
100 LPDWORD ReceiveFlags
,
101 LPWSAOVERLAPPED lpOverlapped
,
102 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
103 LPWSATHREADID lpThreadId
,
106 PIO_STATUS_BLOCK IOSB
;
107 IO_STATUS_BLOCK DummyIOSB
;
108 AFD_RECV_INFO RecvInfo
;
114 PSOCKET_INFORMATION Socket
;
116 AFD_DbgPrint(MID_TRACE
,("Called (%x)\n", Handle
));
118 /* Get the Socket Structure associate to this Socket*/
119 Socket
= GetSocketStructure(Handle
);
122 *lpErrno
= WSAENOTSOCK
;
126 Status
= NtCreateEvent( &SockEvent
, EVENT_ALL_ACCESS
,
129 if( !NT_SUCCESS(Status
) )
132 /* Set up the Receive Structure */
133 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
134 RecvInfo
.BufferCount
= dwBufferCount
;
135 RecvInfo
.TdiFlags
= 0;
136 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
138 /* Set the TDI Flags */
139 if (*ReceiveFlags
== 0)
141 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
145 if (*ReceiveFlags
& MSG_OOB
)
147 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
150 if (*ReceiveFlags
& MSG_PEEK
)
152 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
155 if (*ReceiveFlags
& MSG_PARTIAL
)
157 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PARTIAL
;
161 /* Verifiy if we should use APC */
163 if (lpOverlapped
== NULL
)
165 /* Not using Overlapped structure, so use normal blocking on event */
173 if (lpCompletionRoutine
== NULL
)
175 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
176 APCContext
= lpOverlapped
;
178 Event
= lpOverlapped
->hEvent
;
182 /* Using Overlapped Structure and a Completition Routine, so use an APC */
183 APCFunction
= NULL
; // should be a private io completition function inside us
184 APCContext
= lpCompletionRoutine
;
185 RecvInfo
.AfdFlags
|= AFD_SKIP_FIO
;
188 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
189 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
192 IOSB
->Status
= STATUS_PENDING
;
195 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
206 /* Wait for completition of not overlapped */
207 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
209 /* It's up to the protocol to time out recv. We must wait
210 * until the protocol decides it's had enough.
212 WaitForSingleObject(SockEvent
, INFINITE
);
213 Status
= IOSB
->Status
;
216 NtClose( SockEvent
);
218 AFD_DbgPrint(MID_TRACE
,("Status %x Information %d\n", Status
, IOSB
->Information
));
220 /* Return the Flags */
225 case STATUS_RECEIVE_EXPEDITED
:
226 *ReceiveFlags
= MSG_OOB
;
228 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
229 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
231 case STATUS_RECEIVE_PARTIAL
:
232 *ReceiveFlags
= MSG_PARTIAL
;
236 /* Re-enable Async Event */
237 if (*ReceiveFlags
& MSG_OOB
)
239 SockReenableAsyncSelectEvent(Socket
, FD_OOB
);
243 SockReenableAsyncSelectEvent(Socket
, FD_READ
);
246 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
251 WSPRecvFrom(SOCKET Handle
,
254 LPDWORD lpNumberOfBytesRead
,
255 LPDWORD ReceiveFlags
,
256 struct sockaddr
*SocketAddress
,
257 int *SocketAddressLength
,
258 LPWSAOVERLAPPED lpOverlapped
,
259 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
260 LPWSATHREADID lpThreadId
,
263 PIO_STATUS_BLOCK IOSB
;
264 IO_STATUS_BLOCK DummyIOSB
;
265 AFD_RECV_INFO_UDP RecvInfo
;
271 PSOCKET_INFORMATION Socket
;
273 /* Get the Socket Structure associate to this Socket*/
274 Socket
= GetSocketStructure(Handle
);
277 *lpErrno
= WSAENOTSOCK
;
281 if (!(Socket
->SharedData
.ServiceFlags1
& XP1_CONNECTIONLESS
))
283 /* Call WSPRecv for a non-datagram socket */
284 return WSPRecv(Handle
,
295 Status
= NtCreateEvent( &SockEvent
, EVENT_ALL_ACCESS
,
298 if( !NT_SUCCESS(Status
) )
301 /* Set up the Receive Structure */
302 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
303 RecvInfo
.BufferCount
= dwBufferCount
;
304 RecvInfo
.TdiFlags
= 0;
305 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
306 RecvInfo
.AddressLength
= SocketAddressLength
;
307 RecvInfo
.Address
= SocketAddress
;
309 /* Set the TDI Flags */
310 if (*ReceiveFlags
== 0)
312 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
316 if (*ReceiveFlags
& MSG_OOB
)
318 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
321 if (*ReceiveFlags
& MSG_PEEK
)
323 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
326 if (*ReceiveFlags
& MSG_PARTIAL
)
328 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PARTIAL
;
332 /* Verifiy if we should use APC */
334 if (lpOverlapped
== NULL
)
336 /* Not using Overlapped structure, so use normal blocking on event */
344 if (lpCompletionRoutine
== NULL
)
346 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
347 APCContext
= lpOverlapped
;
349 Event
= lpOverlapped
->hEvent
;
353 /* Using Overlapped Structure and a Completition Routine, so use an APC */
354 APCFunction
= NULL
; // should be a private io completition function inside us
355 APCContext
= lpCompletionRoutine
;
356 RecvInfo
.AfdFlags
|= AFD_SKIP_FIO
;
359 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
360 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
363 IOSB
->Status
= STATUS_PENDING
;
366 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
371 IOCTL_AFD_RECV_DATAGRAM
,
377 /* Wait for completition of not overlapped */
378 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
380 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for receive...
381 Status
= IOSB
->Status
;
384 NtClose( SockEvent
);
386 /* Return the Flags */
391 case STATUS_RECEIVE_EXPEDITED
: *ReceiveFlags
= MSG_OOB
;
393 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
394 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
396 case STATUS_RECEIVE_PARTIAL
:
397 *ReceiveFlags
= MSG_PARTIAL
;
401 /* Re-enable Async Event */
402 if (*ReceiveFlags
& MSG_OOB
)
404 SockReenableAsyncSelectEvent(Socket
, FD_OOB
);
408 SockReenableAsyncSelectEvent(Socket
, FD_READ
);
411 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
417 WSPSend(SOCKET Handle
,
420 LPDWORD lpNumberOfBytesSent
,
422 LPWSAOVERLAPPED lpOverlapped
,
423 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
424 LPWSATHREADID lpThreadId
,
427 PIO_STATUS_BLOCK IOSB
;
428 IO_STATUS_BLOCK DummyIOSB
;
429 AFD_SEND_INFO SendInfo
;
435 PSOCKET_INFORMATION Socket
;
437 /* Get the Socket Structure associate to this Socket*/
438 Socket
= GetSocketStructure(Handle
);
441 *lpErrno
= WSAENOTSOCK
;
445 Status
= NtCreateEvent( &SockEvent
, EVENT_ALL_ACCESS
,
448 if( !NT_SUCCESS(Status
) )
451 AFD_DbgPrint(MID_TRACE
,("Called\n"));
453 /* Set up the Send Structure */
454 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
455 SendInfo
.BufferCount
= dwBufferCount
;
456 SendInfo
.TdiFlags
= 0;
457 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
459 /* Set the TDI Flags */
462 if (iFlags
& MSG_OOB
)
464 SendInfo
.TdiFlags
|= TDI_SEND_EXPEDITED
;
466 if (iFlags
& MSG_PARTIAL
)
468 SendInfo
.TdiFlags
|= TDI_SEND_PARTIAL
;
472 /* Verifiy if we should use APC */
473 if (lpOverlapped
== NULL
)
475 /* Not using Overlapped structure, so use normal blocking on event */
483 if (lpCompletionRoutine
== NULL
)
485 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
486 APCContext
= lpOverlapped
;
488 Event
= lpOverlapped
->hEvent
;
492 /* Using Overlapped Structure and a Completition Routine, so use an APC */
493 APCFunction
= NULL
; // should be a private io completition function inside us
494 APCContext
= lpCompletionRoutine
;
495 SendInfo
.AfdFlags
|= AFD_SKIP_FIO
;
498 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
499 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
502 IOSB
->Status
= STATUS_PENDING
;
505 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
516 /* Wait for completition of not overlapped */
517 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
519 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for send...
520 Status
= IOSB
->Status
;
523 NtClose( SockEvent
);
525 if (Status
== STATUS_PENDING
)
527 AFD_DbgPrint(MID_TRACE
,("Leaving (Pending)\n"));
528 return MsafdReturnWithErrno(Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
531 /* Re-enable Async Event */
532 SockReenableAsyncSelectEvent(Socket
, FD_WRITE
);
534 AFD_DbgPrint(MID_TRACE
,("Leaving (Success, %d)\n", IOSB
->Information
));
536 return MsafdReturnWithErrno( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
541 WSPSendTo(SOCKET Handle
,
544 LPDWORD lpNumberOfBytesSent
,
546 const struct sockaddr
*SocketAddress
,
547 int SocketAddressLength
,
548 LPWSAOVERLAPPED lpOverlapped
,
549 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
550 LPWSATHREADID lpThreadId
,
553 PIO_STATUS_BLOCK IOSB
;
554 IO_STATUS_BLOCK DummyIOSB
;
555 AFD_SEND_INFO_UDP SendInfo
;
560 PTRANSPORT_ADDRESS RemoteAddress
;
561 PSOCKADDR BindAddress
= NULL
;
562 INT BindAddressLength
;
564 PSOCKET_INFORMATION Socket
;
566 /* Get the Socket Structure associate to this Socket */
567 Socket
= GetSocketStructure(Handle
);
570 *lpErrno
= WSAENOTSOCK
;
574 if (!(Socket
->SharedData
.ServiceFlags1
& XP1_CONNECTIONLESS
))
576 /* Use WSPSend for connection-oriented sockets */
577 return WSPSend(Handle
,
589 if (Socket
->SharedData
.State
== SocketOpen
)
591 /* Get the Wildcard Address */
592 BindAddressLength
= Socket
->HelperData
->MaxWSAddressLength
;
593 BindAddress
= HeapAlloc(GlobalHeap
, 0, BindAddressLength
);
596 MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
597 return INVALID_SOCKET
;
600 Socket
->HelperData
->WSHGetWildcardSockaddr(Socket
->HelperContext
,
604 if (WSPBind(Handle
, BindAddress
, BindAddressLength
, lpErrno
) == SOCKET_ERROR
)
608 RemoteAddress
= HeapAlloc(GlobalHeap
, 0, 0x6 + SocketAddressLength
);
611 if (BindAddress
!= NULL
)
613 HeapFree(GlobalHeap
, 0, BindAddress
);
615 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
618 Status
= NtCreateEvent(&SockEvent
,
622 if (!NT_SUCCESS(Status
))
624 HeapFree(GlobalHeap
, 0, RemoteAddress
);
625 if (BindAddress
!= NULL
)
627 HeapFree(GlobalHeap
, 0, BindAddress
);
632 /* Set up Address in TDI Format */
633 RemoteAddress
->TAAddressCount
= 1;
634 RemoteAddress
->Address
[0].AddressLength
= SocketAddressLength
- sizeof(SocketAddress
->sa_family
);
635 RtlCopyMemory(&RemoteAddress
->Address
[0].AddressType
, SocketAddress
, SocketAddressLength
);
637 /* Set up Structure */
638 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
639 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
640 SendInfo
.BufferCount
= dwBufferCount
;
641 SendInfo
.TdiConnection
.RemoteAddress
= RemoteAddress
;
642 SendInfo
.TdiConnection
.RemoteAddressLength
= Socket
->HelperData
->MaxTDIAddressLength
;
644 /* Verifiy if we should use APC */
645 if (lpOverlapped
== NULL
)
647 /* Not using Overlapped structure, so use normal blocking on event */
655 if (lpCompletionRoutine
== NULL
)
657 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
658 APCContext
= lpOverlapped
;
660 Event
= lpOverlapped
->hEvent
;
664 /* Using Overlapped Structure and a Completition Routine, so use an APC */
665 /* Should be a private io completition function inside us */
667 APCContext
= lpCompletionRoutine
;
668 SendInfo
.AfdFlags
|= AFD_SKIP_FIO
;
671 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
672 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
676 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
681 IOCTL_AFD_SEND_DATAGRAM
,
687 /* Wait for completition of not overlapped */
688 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
690 /* BUGBUG, shouldn't wait infintely for send... */
691 WaitForSingleObject(SockEvent
, INFINITE
);
692 Status
= IOSB
->Status
;
696 HeapFree(GlobalHeap
, 0, RemoteAddress
);
697 if (BindAddress
!= NULL
)
699 HeapFree(GlobalHeap
, 0, BindAddress
);
702 SockReenableAsyncSelectEvent(Socket
, FD_WRITE
);
704 return MsafdReturnWithErrno(Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
709 WSPRecvDisconnect(IN SOCKET s
,
710 OUT LPWSABUF lpInboundDisconnectData
,
721 WSPSendDisconnect(IN SOCKET s
,
722 IN LPWSABUF lpOutboundDisconnectData
,