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
);
33 /* Allocate the Async Data Structure to pass on to the Thread later */
34 AsyncData
= HeapAlloc(GetProcessHeap(), 0, sizeof(*AsyncData
));
37 MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
38 return INVALID_SOCKET
;
41 /* Change the Socket to Non Blocking */
43 SetSocketInformation(Socket
, AFD_INFO_BLOCKING_MODE
, &BlockMode
, NULL
);
44 Socket
->SharedData
.NonBlocking
= TRUE
;
46 /* Deactive WSPEventSelect */
47 if (Socket
->SharedData
.AsyncEvents
)
49 WSPEventSelect(Handle
, NULL
, 0, NULL
);
52 /* Create the Asynch Thread if Needed */
53 SockCreateOrReferenceAsyncThread();
55 /* Open a Handle to AFD's Async Helper */
56 SockGetAsyncSelectHelperAfdHandle();
58 /* Store Socket Data */
59 Socket
->SharedData
.hWnd
= hWnd
;
60 Socket
->SharedData
.wMsg
= wMsg
;
61 Socket
->SharedData
.AsyncEvents
= lEvent
;
62 Socket
->SharedData
.AsyncDisabledEvents
= 0;
63 Socket
->SharedData
.SequenceNumber
++;
65 /* Return if there are no more Events */
66 if ((Socket
->SharedData
.AsyncEvents
& (~Socket
->SharedData
.AsyncDisabledEvents
)) == 0)
68 HeapFree(GetProcessHeap(), 0, AsyncData
);
72 /* Set up the Async Data */
73 AsyncData
->ParentSocket
= Socket
;
74 AsyncData
->SequenceNumber
= Socket
->SharedData
.SequenceNumber
;
76 /* Begin Async Select by using I/O Completion */
77 Status
= NtSetIoCompletion(SockAsyncCompletionPort
,
78 (PVOID
)&SockProcessQueuedAsyncSelect
,
90 WSPRecv(SOCKET Handle
,
93 LPDWORD lpNumberOfBytesRead
,
95 LPWSAOVERLAPPED lpOverlapped
,
96 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
97 LPWSATHREADID lpThreadId
,
100 PIO_STATUS_BLOCK IOSB
;
101 IO_STATUS_BLOCK DummyIOSB
;
102 AFD_RECV_INFO RecvInfo
;
108 PSOCKET_INFORMATION Socket
;
110 AFD_DbgPrint(MID_TRACE
,("Called (%x)\n", Handle
));
112 /* Get the Socket Structure associate to this Socket*/
113 Socket
= GetSocketStructure(Handle
);
115 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
118 if( !NT_SUCCESS(Status
) )
121 /* Set up the Receive Structure */
122 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
123 RecvInfo
.BufferCount
= dwBufferCount
;
124 RecvInfo
.TdiFlags
= 0;
125 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
127 /* Set the TDI Flags */
128 if (*ReceiveFlags
== 0)
130 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
134 if (*ReceiveFlags
& MSG_OOB
)
136 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
139 if (*ReceiveFlags
& MSG_PEEK
)
141 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
144 if (*ReceiveFlags
& MSG_PARTIAL
)
146 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PARTIAL
;
150 /* Verifiy if we should use APC */
152 if (lpOverlapped
== NULL
)
154 /* Not using Overlapped structure, so use normal blocking on event */
162 if (lpCompletionRoutine
== NULL
)
164 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
165 APCContext
= lpOverlapped
;
167 Event
= lpOverlapped
->hEvent
;
171 /* Using Overlapped Structure and a Completition Routine, so use an APC */
172 APCFunction
= NULL
; // should be a private io completition function inside us
173 APCContext
= lpCompletionRoutine
;
174 RecvInfo
.AfdFlags
|= AFD_SKIP_FIO
;
177 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
178 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
181 IOSB
->Status
= STATUS_PENDING
;
184 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
185 Event
? Event
: SockEvent
,
195 /* Wait for completition of not overlapped */
196 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
198 /* It's up to the protocol to time out recv. We must wait
199 * until the protocol decides it's had enough.
201 WaitForSingleObject(SockEvent
, INFINITE
);
202 Status
= IOSB
->Status
;
205 NtClose( SockEvent
);
207 AFD_DbgPrint(MID_TRACE
,("Status %x Information %d\n", Status
, IOSB
->Information
));
209 /* Return the Flags */
214 case STATUS_RECEIVE_EXPEDITED
:
215 *ReceiveFlags
= MSG_OOB
;
217 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
218 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
220 case STATUS_RECEIVE_PARTIAL
:
221 *ReceiveFlags
= MSG_PARTIAL
;
225 /* Re-enable Async Event */
226 if (*ReceiveFlags
== MSG_OOB
)
228 SockReenableAsyncSelectEvent(Socket
, FD_OOB
);
232 SockReenableAsyncSelectEvent(Socket
, FD_READ
);
235 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
240 WSPRecvFrom(SOCKET Handle
,
243 LPDWORD lpNumberOfBytesRead
,
244 LPDWORD ReceiveFlags
,
245 struct sockaddr
*SocketAddress
,
246 int *SocketAddressLength
,
247 LPWSAOVERLAPPED lpOverlapped
,
248 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
249 LPWSATHREADID lpThreadId
,
252 PIO_STATUS_BLOCK IOSB
;
253 IO_STATUS_BLOCK DummyIOSB
;
254 AFD_RECV_INFO_UDP RecvInfo
;
260 PSOCKET_INFORMATION Socket
;
262 /* Get the Socket Structure associate to this Socket*/
263 Socket
= GetSocketStructure(Handle
);
265 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
268 if( !NT_SUCCESS(Status
) )
271 /* Set up the Receive Structure */
272 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
273 RecvInfo
.BufferCount
= dwBufferCount
;
274 RecvInfo
.TdiFlags
= 0;
275 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
276 RecvInfo
.AddressLength
= SocketAddressLength
;
277 RecvInfo
.Address
= SocketAddress
;
279 /* Set the TDI Flags */
280 if (*ReceiveFlags
== 0)
282 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
286 if (*ReceiveFlags
& MSG_OOB
)
288 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
291 if (*ReceiveFlags
& MSG_PEEK
)
293 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
296 if (*ReceiveFlags
& MSG_PARTIAL
)
298 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PARTIAL
;
302 /* Verifiy if we should use APC */
304 if (lpOverlapped
== NULL
)
306 /* Not using Overlapped structure, so use normal blocking on event */
314 if (lpCompletionRoutine
== NULL
)
316 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
317 APCContext
= lpOverlapped
;
319 Event
= lpOverlapped
->hEvent
;
323 /* Using Overlapped Structure and a Completition Routine, so use an APC */
324 APCFunction
= NULL
; // should be a private io completition function inside us
325 APCContext
= lpCompletionRoutine
;
326 RecvInfo
.AfdFlags
|= AFD_SKIP_FIO
;
329 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
330 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
333 IOSB
->Status
= STATUS_PENDING
;
336 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
337 Event
? Event
: SockEvent
,
341 IOCTL_AFD_RECV_DATAGRAM
,
347 /* Wait for completition of not overlapped */
348 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
350 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for receive...
351 Status
= IOSB
->Status
;
354 NtClose( SockEvent
);
356 /* Return the Flags */
361 case STATUS_RECEIVE_EXPEDITED
: *ReceiveFlags
= MSG_OOB
;
363 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
364 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
366 case STATUS_RECEIVE_PARTIAL
:
367 *ReceiveFlags
= MSG_PARTIAL
;
371 /* Re-enable Async Event */
372 SockReenableAsyncSelectEvent(Socket
, FD_READ
);
374 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
380 WSPSend(SOCKET Handle
,
383 LPDWORD lpNumberOfBytesSent
,
385 LPWSAOVERLAPPED lpOverlapped
,
386 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
387 LPWSATHREADID lpThreadId
,
390 PIO_STATUS_BLOCK IOSB
;
391 IO_STATUS_BLOCK DummyIOSB
;
392 AFD_SEND_INFO SendInfo
;
398 PSOCKET_INFORMATION Socket
;
400 /* Get the Socket Structure associate to this Socket*/
401 Socket
= GetSocketStructure(Handle
);
403 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
406 if( !NT_SUCCESS(Status
) )
409 AFD_DbgPrint(MID_TRACE
,("Called\n"));
411 /* Set up the Send Structure */
412 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
413 SendInfo
.BufferCount
= dwBufferCount
;
414 SendInfo
.TdiFlags
= 0;
415 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
417 /* Set the TDI Flags */
420 if (iFlags
& MSG_OOB
)
422 SendInfo
.TdiFlags
|= TDI_SEND_EXPEDITED
;
424 if (iFlags
& MSG_PARTIAL
)
426 SendInfo
.TdiFlags
|= TDI_SEND_PARTIAL
;
430 /* Verifiy if we should use APC */
431 if (lpOverlapped
== NULL
)
433 /* Not using Overlapped structure, so use normal blocking on event */
441 if (lpCompletionRoutine
== NULL
)
443 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
444 APCContext
= lpOverlapped
;
446 Event
= lpOverlapped
->hEvent
;
450 /* Using Overlapped Structure and a Completition Routine, so use an APC */
451 APCFunction
= NULL
; // should be a private io completition function inside us
452 APCContext
= lpCompletionRoutine
;
453 SendInfo
.AfdFlags
|= AFD_SKIP_FIO
;
456 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
457 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
460 IOSB
->Status
= STATUS_PENDING
;
463 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
464 Event
? Event
: SockEvent
,
474 /* Wait for completition of not overlapped */
475 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
477 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for send...
478 Status
= IOSB
->Status
;
481 NtClose( SockEvent
);
483 if (Status
== STATUS_PENDING
)
485 AFD_DbgPrint(MID_TRACE
,("Leaving (Pending)\n"));
486 return WSA_IO_PENDING
;
489 /* Re-enable Async Event */
490 SockReenableAsyncSelectEvent(Socket
, FD_WRITE
);
492 AFD_DbgPrint(MID_TRACE
,("Leaving (Success, %d)\n", IOSB
->Information
));
494 return MsafdReturnWithErrno( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
499 WSPSendTo(SOCKET Handle
,
502 LPDWORD lpNumberOfBytesSent
,
504 const struct sockaddr
*SocketAddress
,
505 int SocketAddressLength
,
506 LPWSAOVERLAPPED lpOverlapped
,
507 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
508 LPWSATHREADID lpThreadId
,
511 PIO_STATUS_BLOCK IOSB
;
512 IO_STATUS_BLOCK DummyIOSB
;
513 AFD_SEND_INFO_UDP SendInfo
;
518 PTRANSPORT_ADDRESS RemoteAddress
;
519 UCHAR TdiBuffer
[0x16];
520 PSOCKADDR BindAddress
;
521 INT BindAddressLength
;
523 PSOCKET_INFORMATION Socket
;
526 /* Get the Socket Structure associate to this Socket*/
527 Socket
= GetSocketStructure(Handle
);
529 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
532 if( !NT_SUCCESS(Status
) )
536 if (Socket
->SharedData
.State
== SocketOpen
)
538 /* Get the Wildcard Address */
539 BindAddressLength
= Socket
->HelperData
->MaxWSAddressLength
;
540 BindAddress
= HeapAlloc(GlobalHeap
, 0, BindAddressLength
);
543 MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
544 return INVALID_SOCKET
;
546 Socket
->HelperData
->WSHGetWildcardSockaddr (Socket
->HelperContext
,
551 WSPBind(Handle
, BindAddress
, BindAddressLength
, NULL
);
554 /* Set up Address in TDI Format */
555 RemoteAddress
= (PTRANSPORT_ADDRESS
)TdiBuffer
;
556 RemoteAddress
->TAAddressCount
= 1;
557 RemoteAddress
->Address
[0].AddressLength
= SocketAddressLength
- sizeof(SocketAddress
->sa_family
);
558 RtlCopyMemory(&RemoteAddress
->Address
[0].AddressType
, SocketAddress
, SocketAddressLength
);
560 /* Set up Structure */
561 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
562 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
563 SendInfo
.BufferCount
= dwBufferCount
;
564 SendInfo
.TdiConnection
.RemoteAddress
= RemoteAddress
;
565 SendInfo
.TdiConnection
.RemoteAddressLength
= Socket
->HelperData
->MaxTDIAddressLength
;
567 /* Verifiy if we should use APC */
568 if (lpOverlapped
== NULL
)
570 /* Not using Overlapped structure, so use normal blocking on event */
578 if (lpCompletionRoutine
== NULL
)
580 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
581 APCContext
= lpOverlapped
;
583 Event
= lpOverlapped
->hEvent
;
587 /* Using Overlapped Structure and a Completition Routine, so use an APC */
588 APCFunction
= NULL
; // should be a private io completition function inside us
589 APCContext
= lpCompletionRoutine
;
590 SendInfo
.AfdFlags
|= AFD_SKIP_FIO
;
593 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
594 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
598 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
599 Event
? Event
: SockEvent
,
603 IOCTL_AFD_SEND_DATAGRAM
,
609 /* Wait for completition of not overlapped */
610 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
612 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for send...
613 Status
= IOSB
->Status
;
616 NtClose( SockEvent
);
618 if (Status
== STATUS_PENDING
)
619 return WSA_IO_PENDING
;
622 /* Re-enable Async Event */
623 SockReenableAsyncSelectEvent(Socket
, FD_WRITE
);
625 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
629 WSPRecvDisconnect(IN SOCKET s
,
630 OUT LPWSABUF lpInboundDisconnectData
,
641 WSPSendDisconnect(IN SOCKET s
,
642 IN LPWSABUF lpOutboundDisconnectData
,