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
19 WSPAsyncSelect(IN SOCKET Handle
,
25 PSOCKET_INFORMATION Socket
= NULL
;
26 PASYNC_DATA AsyncData
;
30 /* Get the Socket Structure associated to this Socket */
31 Socket
= GetSocketStructure(Handle
);
34 *lpErrno
= WSAENOTSOCK
;
38 /* Allocate the Async Data Structure to pass on to the Thread later */
39 AsyncData
= HeapAlloc(GetProcessHeap(), 0, sizeof(*AsyncData
));
42 MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
43 return INVALID_SOCKET
;
46 /* Change the Socket to Non Blocking */
48 SetSocketInformation(Socket
, AFD_INFO_BLOCKING_MODE
, &BlockMode
, NULL
);
49 Socket
->SharedData
.NonBlocking
= TRUE
;
51 /* Deactive WSPEventSelect */
52 if (Socket
->SharedData
.AsyncEvents
)
54 WSPEventSelect(Handle
, NULL
, 0, NULL
);
57 /* Create the Asynch Thread if Needed */
58 SockCreateOrReferenceAsyncThread();
60 /* Open a Handle to AFD's Async Helper */
61 SockGetAsyncSelectHelperAfdHandle();
63 /* Store Socket Data */
64 Socket
->SharedData
.hWnd
= hWnd
;
65 Socket
->SharedData
.wMsg
= wMsg
;
66 Socket
->SharedData
.AsyncEvents
= lEvent
;
67 Socket
->SharedData
.AsyncDisabledEvents
= 0;
68 Socket
->SharedData
.SequenceNumber
++;
70 /* Return if there are no more Events */
71 if ((Socket
->SharedData
.AsyncEvents
& (~Socket
->SharedData
.AsyncDisabledEvents
)) == 0)
73 HeapFree(GetProcessHeap(), 0, AsyncData
);
77 /* Set up the Async Data */
78 AsyncData
->ParentSocket
= Socket
;
79 AsyncData
->SequenceNumber
= Socket
->SharedData
.SequenceNumber
;
81 /* Begin Async Select by using I/O Completion */
82 Status
= NtSetIoCompletion(SockAsyncCompletionPort
,
83 (PVOID
)&SockProcessQueuedAsyncSelect
,
95 WSPRecv(SOCKET Handle
,
98 LPDWORD lpNumberOfBytesRead
,
100 LPWSAOVERLAPPED lpOverlapped
,
101 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
102 LPWSATHREADID lpThreadId
,
105 PIO_STATUS_BLOCK IOSB
;
106 IO_STATUS_BLOCK DummyIOSB
;
107 AFD_RECV_INFO RecvInfo
;
113 PSOCKET_INFORMATION Socket
;
115 AFD_DbgPrint(MID_TRACE
,("Called (%x)\n", Handle
));
117 /* Get the Socket Structure associate to this Socket*/
118 Socket
= GetSocketStructure(Handle
);
121 *lpErrno
= WSAENOTSOCK
;
125 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
128 if( !NT_SUCCESS(Status
) )
131 /* Set up the Receive Structure */
132 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
133 RecvInfo
.BufferCount
= dwBufferCount
;
134 RecvInfo
.TdiFlags
= 0;
135 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
137 /* Set the TDI Flags */
138 if (*ReceiveFlags
== 0)
140 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
144 if (*ReceiveFlags
& MSG_OOB
)
146 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
149 if (*ReceiveFlags
& MSG_PEEK
)
151 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
154 if (*ReceiveFlags
& MSG_PARTIAL
)
156 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PARTIAL
;
160 /* Verifiy if we should use APC */
162 if (lpOverlapped
== NULL
)
164 /* Not using Overlapped structure, so use normal blocking on event */
172 if (lpCompletionRoutine
== NULL
)
174 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
175 APCContext
= lpOverlapped
;
177 Event
= lpOverlapped
->hEvent
;
181 /* Using Overlapped Structure and a Completition Routine, so use an APC */
182 APCFunction
= NULL
; // should be a private io completition function inside us
183 APCContext
= lpCompletionRoutine
;
184 RecvInfo
.AfdFlags
|= AFD_SKIP_FIO
;
187 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
188 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
191 IOSB
->Status
= STATUS_PENDING
;
194 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
205 /* Wait for completition of not overlapped */
206 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
208 /* It's up to the protocol to time out recv. We must wait
209 * until the protocol decides it's had enough.
211 WaitForSingleObject(SockEvent
, INFINITE
);
212 Status
= IOSB
->Status
;
215 NtClose( SockEvent
);
217 AFD_DbgPrint(MID_TRACE
,("Status %x Information %d\n", Status
, IOSB
->Information
));
219 /* Return the Flags */
224 case STATUS_RECEIVE_EXPEDITED
:
225 *ReceiveFlags
= MSG_OOB
;
227 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
228 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
230 case STATUS_RECEIVE_PARTIAL
:
231 *ReceiveFlags
= MSG_PARTIAL
;
235 /* Re-enable Async Event */
236 if (*ReceiveFlags
& MSG_OOB
)
238 SockReenableAsyncSelectEvent(Socket
, FD_OOB
);
242 SockReenableAsyncSelectEvent(Socket
, FD_READ
);
245 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
250 WSPRecvFrom(SOCKET Handle
,
253 LPDWORD lpNumberOfBytesRead
,
254 LPDWORD ReceiveFlags
,
255 struct sockaddr
*SocketAddress
,
256 int *SocketAddressLength
,
257 LPWSAOVERLAPPED lpOverlapped
,
258 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
259 LPWSATHREADID lpThreadId
,
262 PIO_STATUS_BLOCK IOSB
;
263 IO_STATUS_BLOCK DummyIOSB
;
264 AFD_RECV_INFO_UDP RecvInfo
;
270 PSOCKET_INFORMATION Socket
;
272 /* Get the Socket Structure associate to this Socket*/
273 Socket
= GetSocketStructure(Handle
);
276 *lpErrno
= WSAENOTSOCK
;
280 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
283 if( !NT_SUCCESS(Status
) )
286 /* Set up the Receive Structure */
287 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
288 RecvInfo
.BufferCount
= dwBufferCount
;
289 RecvInfo
.TdiFlags
= 0;
290 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
291 RecvInfo
.AddressLength
= SocketAddressLength
;
292 RecvInfo
.Address
= SocketAddress
;
294 /* Set the TDI Flags */
295 if (*ReceiveFlags
== 0)
297 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
301 if (*ReceiveFlags
& MSG_OOB
)
303 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
306 if (*ReceiveFlags
& MSG_PEEK
)
308 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
311 if (*ReceiveFlags
& MSG_PARTIAL
)
313 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PARTIAL
;
317 /* Verifiy if we should use APC */
319 if (lpOverlapped
== NULL
)
321 /* Not using Overlapped structure, so use normal blocking on event */
329 if (lpCompletionRoutine
== NULL
)
331 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
332 APCContext
= lpOverlapped
;
334 Event
= lpOverlapped
->hEvent
;
338 /* Using Overlapped Structure and a Completition Routine, so use an APC */
339 APCFunction
= NULL
; // should be a private io completition function inside us
340 APCContext
= lpCompletionRoutine
;
341 RecvInfo
.AfdFlags
|= AFD_SKIP_FIO
;
344 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
345 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
348 IOSB
->Status
= STATUS_PENDING
;
351 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
356 IOCTL_AFD_RECV_DATAGRAM
,
362 /* Wait for completition of not overlapped */
363 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
365 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for receive...
366 Status
= IOSB
->Status
;
369 NtClose( SockEvent
);
371 /* Return the Flags */
376 case STATUS_RECEIVE_EXPEDITED
: *ReceiveFlags
= MSG_OOB
;
378 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
379 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
381 case STATUS_RECEIVE_PARTIAL
:
382 *ReceiveFlags
= MSG_PARTIAL
;
386 /* Re-enable Async Event */
387 SockReenableAsyncSelectEvent(Socket
, FD_READ
);
389 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
395 WSPSend(SOCKET Handle
,
398 LPDWORD lpNumberOfBytesSent
,
400 LPWSAOVERLAPPED lpOverlapped
,
401 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
402 LPWSATHREADID lpThreadId
,
405 PIO_STATUS_BLOCK IOSB
;
406 IO_STATUS_BLOCK DummyIOSB
;
407 AFD_SEND_INFO SendInfo
;
413 PSOCKET_INFORMATION Socket
;
415 /* Get the Socket Structure associate to this Socket*/
416 Socket
= GetSocketStructure(Handle
);
419 *lpErrno
= WSAENOTSOCK
;
423 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
426 if( !NT_SUCCESS(Status
) )
429 AFD_DbgPrint(MID_TRACE
,("Called\n"));
431 /* Set up the Send Structure */
432 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
433 SendInfo
.BufferCount
= dwBufferCount
;
434 SendInfo
.TdiFlags
= 0;
435 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
437 /* Set the TDI Flags */
440 if (iFlags
& MSG_OOB
)
442 SendInfo
.TdiFlags
|= TDI_SEND_EXPEDITED
;
444 if (iFlags
& MSG_PARTIAL
)
446 SendInfo
.TdiFlags
|= TDI_SEND_PARTIAL
;
450 /* Verifiy if we should use APC */
451 if (lpOverlapped
== NULL
)
453 /* Not using Overlapped structure, so use normal blocking on event */
461 if (lpCompletionRoutine
== NULL
)
463 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
464 APCContext
= lpOverlapped
;
466 Event
= lpOverlapped
->hEvent
;
470 /* Using Overlapped Structure and a Completition Routine, so use an APC */
471 APCFunction
= NULL
; // should be a private io completition function inside us
472 APCContext
= lpCompletionRoutine
;
473 SendInfo
.AfdFlags
|= AFD_SKIP_FIO
;
476 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
477 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
480 IOSB
->Status
= STATUS_PENDING
;
483 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
494 /* Wait for completition of not overlapped */
495 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
497 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for send...
498 Status
= IOSB
->Status
;
501 NtClose( SockEvent
);
503 if (Status
== STATUS_PENDING
)
505 AFD_DbgPrint(MID_TRACE
,("Leaving (Pending)\n"));
506 return MsafdReturnWithErrno(Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
509 /* Re-enable Async Event */
510 SockReenableAsyncSelectEvent(Socket
, FD_WRITE
);
512 AFD_DbgPrint(MID_TRACE
,("Leaving (Success, %d)\n", IOSB
->Information
));
514 return MsafdReturnWithErrno( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
519 WSPSendTo(SOCKET Handle
,
522 LPDWORD lpNumberOfBytesSent
,
524 const struct sockaddr
*SocketAddress
,
525 int SocketAddressLength
,
526 LPWSAOVERLAPPED lpOverlapped
,
527 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
528 LPWSATHREADID lpThreadId
,
531 PIO_STATUS_BLOCK IOSB
;
532 IO_STATUS_BLOCK DummyIOSB
;
533 AFD_SEND_INFO_UDP SendInfo
;
538 PTRANSPORT_ADDRESS RemoteAddress
;
539 PSOCKADDR BindAddress
= NULL
;
540 INT BindAddressLength
;
542 PSOCKET_INFORMATION Socket
;
544 /* Get the Socket Structure associate to this Socket */
545 Socket
= GetSocketStructure(Handle
);
548 *lpErrno
= WSAENOTSOCK
;
553 if (Socket
->SharedData
.State
== SocketOpen
)
555 /* Get the Wildcard Address */
556 BindAddressLength
= Socket
->HelperData
->MaxWSAddressLength
;
557 BindAddress
= HeapAlloc(GlobalHeap
, 0, BindAddressLength
);
560 MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
561 return INVALID_SOCKET
;
564 Socket
->HelperData
->WSHGetWildcardSockaddr(Socket
->HelperContext
,
568 if (WSPBind(Handle
, BindAddress
, BindAddressLength
, lpErrno
) == SOCKET_ERROR
)
572 RemoteAddress
= HeapAlloc(GlobalHeap
, 0, 0x6 + SocketAddressLength
);
575 if (BindAddress
!= NULL
)
577 HeapFree(GlobalHeap
, 0, BindAddress
);
579 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
582 Status
= NtCreateEvent(&SockEvent
,
583 GENERIC_READ
| GENERIC_WRITE
,
586 if (!NT_SUCCESS(Status
))
588 HeapFree(GlobalHeap
, 0, RemoteAddress
);
589 if (BindAddress
!= NULL
)
591 HeapFree(GlobalHeap
, 0, BindAddress
);
596 /* Set up Address in TDI Format */
597 RemoteAddress
->TAAddressCount
= 1;
598 RemoteAddress
->Address
[0].AddressLength
= SocketAddressLength
- sizeof(SocketAddress
->sa_family
);
599 RtlCopyMemory(&RemoteAddress
->Address
[0].AddressType
, SocketAddress
, SocketAddressLength
);
601 /* Set up Structure */
602 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
603 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
604 SendInfo
.BufferCount
= dwBufferCount
;
605 SendInfo
.TdiConnection
.RemoteAddress
= RemoteAddress
;
606 SendInfo
.TdiConnection
.RemoteAddressLength
= Socket
->HelperData
->MaxTDIAddressLength
;
608 /* Verifiy if we should use APC */
609 if (lpOverlapped
== NULL
)
611 /* Not using Overlapped structure, so use normal blocking on event */
619 if (lpCompletionRoutine
== NULL
)
621 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
622 APCContext
= lpOverlapped
;
624 Event
= lpOverlapped
->hEvent
;
628 /* Using Overlapped Structure and a Completition Routine, so use an APC */
629 /* Should be a private io completition function inside us */
631 APCContext
= lpCompletionRoutine
;
632 SendInfo
.AfdFlags
|= AFD_SKIP_FIO
;
635 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
636 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
640 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
645 IOCTL_AFD_SEND_DATAGRAM
,
651 /* Wait for completition of not overlapped */
652 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
654 /* BUGBUG, shouldn't wait infintely for send... */
655 WaitForSingleObject(SockEvent
, INFINITE
);
656 Status
= IOSB
->Status
;
660 HeapFree(GlobalHeap
, 0, RemoteAddress
);
661 if (BindAddress
!= NULL
)
663 HeapFree(GlobalHeap
, 0, BindAddress
);
666 if (Status
!= STATUS_PENDING
)
667 SockReenableAsyncSelectEvent(Socket
, FD_WRITE
);
669 return MsafdReturnWithErrno(Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
674 WSPRecvDisconnect(IN SOCKET s
,
675 OUT LPWSABUF lpInboundDisconnectData
,
686 WSPSendDisconnect(IN SOCKET s
,
687 IN LPWSABUF lpOutboundDisconnectData
,