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
,
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 */
212 if (Status
== STATUS_PENDING
)
213 return MsafdReturnWithErrno(Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
217 case STATUS_RECEIVE_EXPEDITED
:
218 *ReceiveFlags
= MSG_OOB
;
220 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
221 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
223 case STATUS_RECEIVE_PARTIAL
:
224 *ReceiveFlags
= MSG_PARTIAL
;
228 /* Re-enable Async Event */
229 if (*ReceiveFlags
& MSG_OOB
)
231 SockReenableAsyncSelectEvent(Socket
, FD_OOB
);
235 SockReenableAsyncSelectEvent(Socket
, FD_READ
);
238 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
243 WSPRecvFrom(SOCKET Handle
,
246 LPDWORD lpNumberOfBytesRead
,
247 LPDWORD ReceiveFlags
,
248 struct sockaddr
*SocketAddress
,
249 int *SocketAddressLength
,
250 LPWSAOVERLAPPED lpOverlapped
,
251 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
252 LPWSATHREADID lpThreadId
,
255 PIO_STATUS_BLOCK IOSB
;
256 IO_STATUS_BLOCK DummyIOSB
;
257 AFD_RECV_INFO_UDP RecvInfo
;
263 PSOCKET_INFORMATION Socket
;
265 /* Get the Socket Structure associate to this Socket*/
266 Socket
= GetSocketStructure(Handle
);
268 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
271 if( !NT_SUCCESS(Status
) )
274 /* Set up the Receive Structure */
275 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
276 RecvInfo
.BufferCount
= dwBufferCount
;
277 RecvInfo
.TdiFlags
= 0;
278 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
279 RecvInfo
.AddressLength
= SocketAddressLength
;
280 RecvInfo
.Address
= SocketAddress
;
282 /* Set the TDI Flags */
283 if (*ReceiveFlags
== 0)
285 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
289 if (*ReceiveFlags
& MSG_OOB
)
291 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
294 if (*ReceiveFlags
& MSG_PEEK
)
296 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
299 if (*ReceiveFlags
& MSG_PARTIAL
)
301 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PARTIAL
;
305 /* Verifiy if we should use APC */
307 if (lpOverlapped
== NULL
)
309 /* Not using Overlapped structure, so use normal blocking on event */
317 if (lpCompletionRoutine
== NULL
)
319 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
320 APCContext
= lpOverlapped
;
322 Event
= lpOverlapped
->hEvent
;
326 /* Using Overlapped Structure and a Completition Routine, so use an APC */
327 APCFunction
= NULL
; // should be a private io completition function inside us
328 APCContext
= lpCompletionRoutine
;
329 RecvInfo
.AfdFlags
|= AFD_SKIP_FIO
;
332 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
333 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
336 IOSB
->Status
= STATUS_PENDING
;
339 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
344 IOCTL_AFD_RECV_DATAGRAM
,
350 /* Wait for completition of not overlapped */
351 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
353 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for receive...
354 Status
= IOSB
->Status
;
357 NtClose( SockEvent
);
359 /* Return the Flags */
362 if (Status
== STATUS_PENDING
)
363 return MsafdReturnWithErrno(Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
367 case STATUS_RECEIVE_EXPEDITED
: *ReceiveFlags
= MSG_OOB
;
369 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
370 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
372 case STATUS_RECEIVE_PARTIAL
:
373 *ReceiveFlags
= MSG_PARTIAL
;
377 /* Re-enable Async Event */
378 SockReenableAsyncSelectEvent(Socket
, FD_READ
);
380 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
386 WSPSend(SOCKET Handle
,
389 LPDWORD lpNumberOfBytesSent
,
391 LPWSAOVERLAPPED lpOverlapped
,
392 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
393 LPWSATHREADID lpThreadId
,
396 PIO_STATUS_BLOCK IOSB
;
397 IO_STATUS_BLOCK DummyIOSB
;
398 AFD_SEND_INFO SendInfo
;
404 PSOCKET_INFORMATION Socket
;
406 /* Get the Socket Structure associate to this Socket*/
407 Socket
= GetSocketStructure(Handle
);
409 Status
= NtCreateEvent( &SockEvent
, GENERIC_READ
| GENERIC_WRITE
,
412 if( !NT_SUCCESS(Status
) )
415 AFD_DbgPrint(MID_TRACE
,("Called\n"));
417 /* Set up the Send Structure */
418 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
419 SendInfo
.BufferCount
= dwBufferCount
;
420 SendInfo
.TdiFlags
= 0;
421 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
423 /* Set the TDI Flags */
426 if (iFlags
& MSG_OOB
)
428 SendInfo
.TdiFlags
|= TDI_SEND_EXPEDITED
;
430 if (iFlags
& MSG_PARTIAL
)
432 SendInfo
.TdiFlags
|= TDI_SEND_PARTIAL
;
436 /* Verifiy if we should use APC */
437 if (lpOverlapped
== NULL
)
439 /* Not using Overlapped structure, so use normal blocking on event */
447 if (lpCompletionRoutine
== NULL
)
449 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
450 APCContext
= lpOverlapped
;
452 Event
= lpOverlapped
->hEvent
;
456 /* Using Overlapped Structure and a Completition Routine, so use an APC */
457 APCFunction
= NULL
; // should be a private io completition function inside us
458 APCContext
= lpCompletionRoutine
;
459 SendInfo
.AfdFlags
|= AFD_SKIP_FIO
;
462 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
463 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
466 IOSB
->Status
= STATUS_PENDING
;
469 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
480 /* Wait for completition of not overlapped */
481 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
483 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for send...
484 Status
= IOSB
->Status
;
487 NtClose( SockEvent
);
489 if (Status
== STATUS_PENDING
)
491 AFD_DbgPrint(MID_TRACE
,("Leaving (Pending)\n"));
492 return MsafdReturnWithErrno(Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
495 /* Re-enable Async Event */
496 SockReenableAsyncSelectEvent(Socket
, FD_WRITE
);
498 AFD_DbgPrint(MID_TRACE
,("Leaving (Success, %d)\n", IOSB
->Information
));
500 return MsafdReturnWithErrno( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
505 WSPSendTo(SOCKET Handle
,
508 LPDWORD lpNumberOfBytesSent
,
510 const struct sockaddr
*SocketAddress
,
511 int SocketAddressLength
,
512 LPWSAOVERLAPPED lpOverlapped
,
513 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
514 LPWSATHREADID lpThreadId
,
517 PIO_STATUS_BLOCK IOSB
;
518 IO_STATUS_BLOCK DummyIOSB
;
519 AFD_SEND_INFO_UDP SendInfo
;
524 PTRANSPORT_ADDRESS RemoteAddress
;
525 PSOCKADDR BindAddress
= NULL
;
526 INT BindAddressLength
;
528 PSOCKET_INFORMATION Socket
;
530 /* Get the Socket Structure associate to this Socket */
531 Socket
= GetSocketStructure(Handle
);
534 if (Socket
->SharedData
.State
== SocketOpen
)
536 /* Get the Wildcard Address */
537 BindAddressLength
= Socket
->HelperData
->MaxWSAddressLength
;
538 BindAddress
= HeapAlloc(GlobalHeap
, 0, BindAddressLength
);
541 MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
542 return INVALID_SOCKET
;
545 Socket
->HelperData
->WSHGetWildcardSockaddr(Socket
->HelperContext
,
549 if (WSPBind(Handle
, BindAddress
, BindAddressLength
, lpErrno
) == SOCKET_ERROR
)
553 RemoteAddress
= HeapAlloc(GlobalHeap
, 0, 0x6 + SocketAddressLength
);
556 if (BindAddress
!= NULL
)
558 HeapFree(GlobalHeap
, 0, BindAddress
);
560 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
563 Status
= NtCreateEvent(&SockEvent
,
564 GENERIC_READ
| GENERIC_WRITE
,
567 if (!NT_SUCCESS(Status
))
569 HeapFree(GlobalHeap
, 0, RemoteAddress
);
570 if (BindAddress
!= NULL
)
572 HeapFree(GlobalHeap
, 0, BindAddress
);
577 /* Set up Address in TDI Format */
578 RemoteAddress
->TAAddressCount
= 1;
579 RemoteAddress
->Address
[0].AddressLength
= SocketAddressLength
- sizeof(SocketAddress
->sa_family
);
580 RtlCopyMemory(&RemoteAddress
->Address
[0].AddressType
, SocketAddress
, SocketAddressLength
);
582 /* Set up Structure */
583 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
584 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
585 SendInfo
.BufferCount
= dwBufferCount
;
586 SendInfo
.TdiConnection
.RemoteAddress
= RemoteAddress
;
587 SendInfo
.TdiConnection
.RemoteAddressLength
= Socket
->HelperData
->MaxTDIAddressLength
;
589 /* Verifiy if we should use APC */
590 if (lpOverlapped
== NULL
)
592 /* Not using Overlapped structure, so use normal blocking on event */
600 if (lpCompletionRoutine
== NULL
)
602 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
603 APCContext
= lpOverlapped
;
605 Event
= lpOverlapped
->hEvent
;
609 /* Using Overlapped Structure and a Completition Routine, so use an APC */
610 /* Should be a private io completition function inside us */
612 APCContext
= lpCompletionRoutine
;
613 SendInfo
.AfdFlags
|= AFD_SKIP_FIO
;
616 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
617 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
621 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
626 IOCTL_AFD_SEND_DATAGRAM
,
632 /* Wait for completition of not overlapped */
633 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
635 /* BUGBUG, shouldn't wait infintely for send... */
636 WaitForSingleObject(SockEvent
, INFINITE
);
637 Status
= IOSB
->Status
;
641 HeapFree(GlobalHeap
, 0, RemoteAddress
);
642 if (BindAddress
!= NULL
)
644 HeapFree(GlobalHeap
, 0, BindAddress
);
647 if (Status
!= STATUS_PENDING
)
648 SockReenableAsyncSelectEvent(Socket
, FD_WRITE
);
650 return MsafdReturnWithErrno(Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
655 WSPRecvDisconnect(IN SOCKET s
,
656 OUT LPWSABUF lpInboundDisconnectData
,
667 WSPSendDisconnect(IN SOCKET s
,
668 IN LPWSABUF lpOutboundDisconnectData
,