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
24 PSOCKET_INFORMATION Socket
= NULL
;
25 PASYNC_DATA AsyncData
;
29 /* Get the Socket Structure associated to this Socket */
30 Socket
= GetSocketStructure(Handle
);
32 /* Allocate the Async Data Structure to pass on to the Thread later */
33 HeapAlloc(GetProcessHeap(), 0, sizeof(*AsyncData
));
35 /* Change the Socket to Non Blocking */
37 SetSocketInformation(Socket
, AFD_INFO_BLOCKING_MODE
, &BlockMode
, NULL
);
38 Socket
->SharedData
.NonBlocking
= TRUE
;
40 /* Deactive WSPEventSelect */
41 if (Socket
->SharedData
.AsyncEvents
) {
42 WSPEventSelect(Handle
, NULL
, 0, NULL
);
45 /* Create the Asynch Thread if Needed */
46 SockCreateOrReferenceAsyncThread();
48 /* Open a Handle to AFD's Async Helper */
49 SockGetAsyncSelectHelperAfdHandle();
51 /* Store Socket Data */
52 Socket
->SharedData
.hWnd
= hWnd
;
53 Socket
->SharedData
.wMsg
= wMsg
;
54 Socket
->SharedData
.AsyncEvents
= lEvent
;
55 Socket
->SharedData
.AsyncDisabledEvents
= 0;
56 Socket
->SharedData
.SequenceNumber
++;
58 /* Return if there are no more Events */
59 if ((Socket
->SharedData
.AsyncEvents
& (~Socket
->SharedData
.AsyncDisabledEvents
)) == 0) {
60 HeapFree(GetProcessHeap(), 0, AsyncData
);
64 /* Set up the Async Data */
65 AsyncData
->ParentSocket
= Socket
;
66 AsyncData
->SequenceNumber
= Socket
->SharedData
.SequenceNumber
;
68 /* Begin Async Select by using I/O Completion */
69 Status
= NtSetIoCompletion(SockAsyncCompletionPort
,
70 (PVOID
)&SockProcessQueuedAsyncSelect
,
86 LPDWORD lpNumberOfBytesRead
,
88 LPWSAOVERLAPPED lpOverlapped
,
89 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
90 LPWSATHREADID lpThreadId
,
93 PIO_STATUS_BLOCK IOSB
;
94 IO_STATUS_BLOCK DummyIOSB
;
95 AFD_RECV_INFO RecvInfo
;
101 PSOCKET_INFORMATION Socket
;
104 /* Get the Socket Structure associate to this Socket*/
105 Socket
= GetSocketStructure(Handle
);
107 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
110 if( !NT_SUCCESS(Status
) ) return -1;
112 /* Set up the Receive Structure */
113 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
114 RecvInfo
.BufferCount
= dwBufferCount
;
115 RecvInfo
.TdiFlags
= 0;
116 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
118 /* Set the TDI Flags */
119 if (*ReceiveFlags
== 0) {
120 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
124 if (*ReceiveFlags
& MSG_OOB
) {
125 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
127 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
130 if (*ReceiveFlags
& MSG_PEEK
) {
131 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
134 if (*ReceiveFlags
& MSG_PARTIAL
) {
135 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
139 /* Verifiy if we should use APC */
141 if (lpOverlapped
== NULL
) {
143 /* Not using Overlapped structure, so use normal blocking on event */
151 if (lpCompletionRoutine
== NULL
) {
153 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
154 APCContext
= lpOverlapped
;
156 Event
= lpOverlapped
->hEvent
;
160 /* Using Overlapped Structure and a Completition Routine, so use an APC */
161 APCFunction
= NULL
; // should be a private io completition function inside us
162 APCContext
= lpCompletionRoutine
;
163 RecvInfo
.AfdFlags
= AFD_SKIP_FIO
;
166 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
167 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
170 IOSB
->Status
= STATUS_PENDING
;
173 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
184 /* Wait for completition of not overlapped */
185 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
) {
186 WaitForSingleObject(SockEvent
, 0); // BUGBUG, shouldn wait infintely for receive...
187 Status
= IOSB
->Status
;
190 NtClose( SockEvent
);
192 /* Return the Flags */
195 case STATUS_CANT_WAIT
:
196 return WSAEWOULDBLOCK
;
201 case STATUS_PENDING
:
202 return WSA_IO_PENDING
;
204 case STATUS_BUFFER_OVERFLOW
:
207 case STATUS_RECEIVE_EXPEDITED
:
208 *ReceiveFlags
= MSG_OOB
;
211 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
212 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
215 case STATUS_RECEIVE_PARTIAL
:
216 *ReceiveFlags
= MSG_PARTIAL
;
220 /* Return Number of bytes Read */
221 *lpNumberOfBytesRead
= (DWORD
)IOSB
->Information
;
224 return STATUS_SUCCESS
;
233 LPDWORD lpNumberOfBytesRead
,
234 LPDWORD ReceiveFlags
,
235 struct sockaddr
*SocketAddress
,
236 int *SocketAddressLength
,
237 LPWSAOVERLAPPED lpOverlapped
,
238 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
239 LPWSATHREADID lpThreadId
,
242 PIO_STATUS_BLOCK IOSB
;
243 IO_STATUS_BLOCK DummyIOSB
;
244 AFD_RECV_INFO_UDP RecvInfo
;
250 PSOCKET_INFORMATION Socket
;
252 /* Get the Socket Structure associate to this Socket*/
253 Socket
= GetSocketStructure(Handle
);
255 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
258 if( !NT_SUCCESS(Status
) ) return -1;
260 /* Set up the Receive Structure */
261 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
262 RecvInfo
.BufferCount
= dwBufferCount
;
263 RecvInfo
.TdiFlags
= 0;
264 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
265 RecvInfo
.AddressLength
= SocketAddressLength
;
266 RecvInfo
.Address
= SocketAddress
;
268 /* Set the TDI Flags */
269 if (*ReceiveFlags
== 0) {
270 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
274 if (*ReceiveFlags
& MSG_OOB
) {
275 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
277 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
280 if (*ReceiveFlags
& MSG_PEEK
) {
281 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
284 if (*ReceiveFlags
& MSG_PARTIAL
) {
285 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
289 /* Verifiy if we should use APC */
291 if (lpOverlapped
== NULL
) {
293 /* Not using Overlapped structure, so use normal blocking on event */
301 if (lpCompletionRoutine
== NULL
) {
303 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
304 APCContext
= lpOverlapped
;
306 Event
= lpOverlapped
->hEvent
;
310 /* Using Overlapped Structure and a Completition Routine, so use an APC */
311 APCFunction
= NULL
; // should be a private io completition function inside us
312 APCContext
= lpCompletionRoutine
;
313 RecvInfo
.AfdFlags
= AFD_SKIP_FIO
;
316 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
317 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
320 IOSB
->Status
= STATUS_PENDING
;
323 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
328 IOCTL_AFD_RECV_DATAGRAM
,
334 /* Wait for completition of not overlapped */
335 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
) {
336 WaitForSingleObject(SockEvent
, 0); // BUGBUG, shouldn wait infintely for receive...
337 Status
= IOSB
->Status
;
340 NtClose( SockEvent
);
342 /* Return the Flags */
345 case STATUS_CANT_WAIT
:
346 return WSAEWOULDBLOCK
;
351 case STATUS_PENDING
:
352 return WSA_IO_PENDING
;
354 case STATUS_BUFFER_OVERFLOW
:
357 case STATUS_RECEIVE_EXPEDITED
:
358 *ReceiveFlags
= MSG_OOB
;
361 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
362 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
365 case STATUS_RECEIVE_PARTIAL
:
366 *ReceiveFlags
= MSG_PARTIAL
;
370 /* Return Number of bytes Read */
371 *lpNumberOfBytesRead
= (DWORD
)IOSB
->Information
;
374 return STATUS_SUCCESS
;
384 LPDWORD lpNumberOfBytesSent
,
386 LPWSAOVERLAPPED lpOverlapped
,
387 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
388 LPWSATHREADID lpThreadId
,
391 PIO_STATUS_BLOCK IOSB
;
392 IO_STATUS_BLOCK DummyIOSB
;
393 AFD_SEND_INFO SendInfo
;
399 PSOCKET_INFORMATION Socket
;
401 /* Get the Socket Structure associate to this Socket*/
402 Socket
= GetSocketStructure(Handle
);
404 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
407 if( !NT_SUCCESS(Status
) ) return -1;
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 */
419 if (iFlags
& MSG_OOB
) {
420 SendInfo
.TdiFlags
|= TDI_SEND_EXPEDITED
;
422 if (iFlags
& MSG_PARTIAL
) {
423 SendInfo
.TdiFlags
|= TDI_SEND_PARTIAL
;
427 /* Verifiy if we should use APC */
428 if (lpOverlapped
== NULL
) {
430 /* Not using Overlapped structure, so use normal blocking on event */
438 if (lpCompletionRoutine
== NULL
) {
440 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
441 APCContext
= lpOverlapped
;
443 Event
= lpOverlapped
->hEvent
;
447 /* Using Overlapped Structure and a Completition Routine, so use an APC */
448 APCFunction
= NULL
; // should be a private io completition function inside us
449 APCContext
= lpCompletionRoutine
;
450 SendInfo
.AfdFlags
= AFD_SKIP_FIO
;
453 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
454 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
457 IOSB
->Status
= STATUS_PENDING
;
460 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
471 /* Wait for completition of not overlapped */
472 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
) {
473 WaitForSingleObject(SockEvent
, 0); // BUGBUG, shouldn wait infintely for send...
474 Status
= IOSB
->Status
;
477 NtClose( SockEvent
);
479 if (Status
== STATUS_PENDING
) {
480 AFD_DbgPrint(MID_TRACE
,("Leaving (Pending)\n"));
481 return WSA_IO_PENDING
;
484 /* Return Number of bytes Sent */
485 *lpNumberOfBytesSent
= (DWORD
)IOSB
->Information
;
487 AFD_DbgPrint(MID_TRACE
,("Leaving (Success, %d)\n", IOSB
->Information
));
490 return STATUS_SUCCESS
;
499 LPDWORD lpNumberOfBytesSent
,
501 struct sockaddr
*SocketAddress
,
502 int SocketAddressLength
,
503 LPWSAOVERLAPPED lpOverlapped
,
504 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
505 LPWSATHREADID lpThreadId
,
508 PIO_STATUS_BLOCK IOSB
;
509 IO_STATUS_BLOCK DummyIOSB
;
510 AFD_SEND_INFO_UDP SendInfo
;
515 PTRANSPORT_ADDRESS RemoteAddress
;
516 UCHAR TdiBuffer
[0x16];
517 PSOCKADDR BindAddress
;
518 INT BindAddressLength
;
520 PSOCKET_INFORMATION Socket
;
523 /* Get the Socket Structure associate to this Socket*/
524 Socket
= GetSocketStructure(Handle
);
526 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
529 if( !NT_SUCCESS(Status
) ) return -1;
532 if (Socket
->SharedData
.State
== SocketOpen
) {
534 /* Get the Wildcard Address */
535 BindAddressLength
= Socket
->HelperData
->MaxWSAddressLength
;
536 BindAddress
= HeapAlloc(GlobalHeap
, 0, BindAddressLength
);
537 Socket
->HelperData
->WSHGetWildcardSockaddr (Socket
->HelperContext
,
542 WSPBind(Handle
, BindAddress
, BindAddressLength
, NULL
);
545 /* Set up Address in TDI Format */
546 RemoteAddress
= (PTRANSPORT_ADDRESS
)TdiBuffer
;
547 RemoteAddress
->TAAddressCount
= 1;
548 RemoteAddress
->Address
[0].AddressLength
= SocketAddressLength
- sizeof(SocketAddress
->sa_family
);
549 RtlCopyMemory(&RemoteAddress
->Address
[0].AddressType
, SocketAddress
, SocketAddressLength
);
551 /* Set up Structure */
552 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
553 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
554 SendInfo
.BufferCount
= dwBufferCount
;
555 SendInfo
.RemoteAddress
= RemoteAddress
;
556 SendInfo
.SizeOfRemoteAddress
= Socket
->HelperData
->MaxTDIAddressLength
;
558 /* Verifiy if we should use APC */
559 if (lpOverlapped
== NULL
) {
561 /* Not using Overlapped structure, so use normal blocking on event */
569 if (lpCompletionRoutine
== NULL
) {
571 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
572 APCContext
= lpOverlapped
;
574 Event
= lpOverlapped
->hEvent
;
578 /* Using Overlapped Structure and a Completition Routine, so use an APC */
579 APCFunction
= NULL
; // should be a private io completition function inside us
580 APCContext
= lpCompletionRoutine
;
581 SendInfo
.AfdFlags
= AFD_SKIP_FIO
;
584 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
585 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
589 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
594 IOCTL_AFD_SEND_DATAGRAM
,
600 /* Wait for completition of not overlapped */
601 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
) {
602 WaitForSingleObject(SockEvent
, 0); // BUGBUG, shouldn wait infintely for send...
603 Status
= IOSB
->Status
;
606 NtClose( SockEvent
);
608 if (Status
== STATUS_PENDING
) {
609 return WSA_IO_PENDING
;
612 /* Return Number of bytes Sent */
613 *lpNumberOfBytesSent
= (DWORD
)IOSB
->Information
;
616 return STATUS_SUCCESS
;
622 OUT LPWSABUF lpInboundDisconnectData
,
636 IN LPWSABUF lpOutboundDisconnectData
,