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
15 #include <wine/debug.h>
16 WINE_DEFAULT_DEBUG_CHANNEL(msafd
);
20 WSPAsyncSelect(IN SOCKET Handle
,
26 PSOCKET_INFORMATION Socket
= NULL
;
27 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
, NULL
);
49 Socket
->SharedData
.NonBlocking
= TRUE
;
51 /* Deactive WSPEventSelect */
52 if (Socket
->SharedData
.AsyncEvents
)
54 if (WSPEventSelect(Handle
, NULL
, 0, lpErrno
) == SOCKET_ERROR
)
56 HeapFree(GetProcessHeap(), 0, AsyncData
);
61 /* Create the Asynch Thread if Needed */
62 SockCreateOrReferenceAsyncThread();
64 /* Open a Handle to AFD's Async Helper */
65 SockGetAsyncSelectHelperAfdHandle();
67 /* Store Socket Data */
68 Socket
->SharedData
.hWnd
= hWnd
;
69 Socket
->SharedData
.wMsg
= wMsg
;
70 Socket
->SharedData
.AsyncEvents
= lEvent
;
71 Socket
->SharedData
.AsyncDisabledEvents
= 0;
72 Socket
->SharedData
.SequenceNumber
++;
74 /* Return if there are no more Events */
75 if ((Socket
->SharedData
.AsyncEvents
& (~Socket
->SharedData
.AsyncDisabledEvents
)) == 0)
77 HeapFree(GetProcessHeap(), 0, AsyncData
);
81 /* Set up the Async Data */
82 AsyncData
->ParentSocket
= Socket
;
83 AsyncData
->SequenceNumber
= Socket
->SharedData
.SequenceNumber
;
85 /* Begin Async Select by using I/O Completion */
86 NtSetIoCompletion(SockAsyncCompletionPort
,
87 (PVOID
)&SockProcessQueuedAsyncSelect
,
99 WSPRecv(SOCKET Handle
,
102 LPDWORD lpNumberOfBytesRead
,
103 LPDWORD ReceiveFlags
,
104 LPWSAOVERLAPPED lpOverlapped
,
105 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
106 LPWSATHREADID lpThreadId
,
109 PIO_STATUS_BLOCK IOSB
;
110 IO_STATUS_BLOCK DummyIOSB
;
111 AFD_RECV_INFO RecvInfo
;
117 PSOCKET_INFORMATION Socket
;
119 TRACE("Called (%x)\n", Handle
);
121 /* Get the Socket Structure associate to this Socket*/
122 Socket
= GetSocketStructure(Handle
);
125 *lpErrno
= WSAENOTSOCK
;
129 Status
= NtCreateEvent( &SockEvent
, EVENT_ALL_ACCESS
,
132 if( !NT_SUCCESS(Status
) )
135 /* Set up the Receive Structure */
136 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
137 RecvInfo
.BufferCount
= dwBufferCount
;
138 RecvInfo
.TdiFlags
= 0;
139 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
141 /* Set the TDI Flags */
142 if (*ReceiveFlags
== 0)
144 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
148 if (*ReceiveFlags
& MSG_OOB
)
150 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
153 if (*ReceiveFlags
& MSG_PEEK
)
155 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
158 if (*ReceiveFlags
& MSG_PARTIAL
)
160 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PARTIAL
;
164 /* Verifiy if we should use APC */
166 if (lpOverlapped
== NULL
)
168 /* Not using Overlapped structure, so use normal blocking on event */
176 if (lpCompletionRoutine
== NULL
)
178 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
179 APCContext
= lpOverlapped
;
181 Event
= lpOverlapped
->hEvent
;
185 /* Using Overlapped Structure and a Completition Routine, so use an APC */
186 APCFunction
= NULL
; // should be a private io completition function inside us
187 APCContext
= lpCompletionRoutine
;
188 RecvInfo
.AfdFlags
|= AFD_SKIP_FIO
;
191 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
192 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
195 IOSB
->Status
= STATUS_PENDING
;
198 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
209 /* Wait for completition of not overlapped */
210 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
212 /* It's up to the protocol to time out recv. We must wait
213 * until the protocol decides it's had enough.
215 WaitForSingleObject(SockEvent
, INFINITE
);
216 Status
= IOSB
->Status
;
219 NtClose( SockEvent
);
221 TRACE("Status %x Information %d\n", Status
, IOSB
->Information
);
223 /* Return the Flags */
228 case STATUS_RECEIVE_EXPEDITED
:
229 *ReceiveFlags
= MSG_OOB
;
231 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
232 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
234 case STATUS_RECEIVE_PARTIAL
:
235 *ReceiveFlags
= MSG_PARTIAL
;
239 /* Re-enable Async Event */
240 if (*ReceiveFlags
& MSG_OOB
)
242 SockReenableAsyncSelectEvent(Socket
, FD_OOB
);
246 SockReenableAsyncSelectEvent(Socket
, FD_READ
);
249 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
254 WSPRecvFrom(SOCKET Handle
,
257 LPDWORD lpNumberOfBytesRead
,
258 LPDWORD ReceiveFlags
,
259 struct sockaddr
*SocketAddress
,
260 int *SocketAddressLength
,
261 LPWSAOVERLAPPED lpOverlapped
,
262 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
263 LPWSATHREADID lpThreadId
,
266 PIO_STATUS_BLOCK IOSB
;
267 IO_STATUS_BLOCK DummyIOSB
;
268 AFD_RECV_INFO_UDP RecvInfo
;
274 PSOCKET_INFORMATION Socket
;
276 /* Get the Socket Structure associate to this Socket*/
277 Socket
= GetSocketStructure(Handle
);
280 *lpErrno
= WSAENOTSOCK
;
284 if (!(Socket
->SharedData
.ServiceFlags1
& XP1_CONNECTIONLESS
))
286 /* Call WSPRecv for a non-datagram socket */
287 return WSPRecv(Handle
,
298 Status
= NtCreateEvent( &SockEvent
, EVENT_ALL_ACCESS
,
301 if( !NT_SUCCESS(Status
) )
304 /* Set up the Receive Structure */
305 RecvInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
306 RecvInfo
.BufferCount
= dwBufferCount
;
307 RecvInfo
.TdiFlags
= 0;
308 RecvInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
309 RecvInfo
.AddressLength
= SocketAddressLength
;
310 RecvInfo
.Address
= SocketAddress
;
312 /* Set the TDI Flags */
313 if (*ReceiveFlags
== 0)
315 RecvInfo
.TdiFlags
|= TDI_RECEIVE_NORMAL
;
319 if (*ReceiveFlags
& MSG_OOB
)
321 RecvInfo
.TdiFlags
|= TDI_RECEIVE_EXPEDITED
;
324 if (*ReceiveFlags
& MSG_PEEK
)
326 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PEEK
;
329 if (*ReceiveFlags
& MSG_PARTIAL
)
331 RecvInfo
.TdiFlags
|= TDI_RECEIVE_PARTIAL
;
335 /* Verifiy if we should use APC */
337 if (lpOverlapped
== NULL
)
339 /* Not using Overlapped structure, so use normal blocking on event */
347 if (lpCompletionRoutine
== NULL
)
349 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
350 APCContext
= lpOverlapped
;
352 Event
= lpOverlapped
->hEvent
;
356 /* Using Overlapped Structure and a Completition Routine, so use an APC */
357 APCFunction
= NULL
; // should be a private io completition function inside us
358 APCContext
= lpCompletionRoutine
;
359 RecvInfo
.AfdFlags
|= AFD_SKIP_FIO
;
362 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
363 RecvInfo
.AfdFlags
|= AFD_OVERLAPPED
;
366 IOSB
->Status
= STATUS_PENDING
;
369 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
374 IOCTL_AFD_RECV_DATAGRAM
,
380 /* Wait for completition of not overlapped */
381 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
383 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for receive...
384 Status
= IOSB
->Status
;
387 NtClose( SockEvent
);
389 /* Return the Flags */
394 case STATUS_RECEIVE_EXPEDITED
: *ReceiveFlags
= MSG_OOB
;
396 case STATUS_RECEIVE_PARTIAL_EXPEDITED
:
397 *ReceiveFlags
= MSG_PARTIAL
| MSG_OOB
;
399 case STATUS_RECEIVE_PARTIAL
:
400 *ReceiveFlags
= MSG_PARTIAL
;
404 /* Re-enable Async Event */
405 if (*ReceiveFlags
& MSG_OOB
)
407 SockReenableAsyncSelectEvent(Socket
, FD_OOB
);
411 SockReenableAsyncSelectEvent(Socket
, FD_READ
);
414 return MsafdReturnWithErrno ( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesRead
);
420 WSPSend(SOCKET Handle
,
423 LPDWORD lpNumberOfBytesSent
,
425 LPWSAOVERLAPPED lpOverlapped
,
426 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
427 LPWSATHREADID lpThreadId
,
430 PIO_STATUS_BLOCK IOSB
;
431 IO_STATUS_BLOCK DummyIOSB
;
432 AFD_SEND_INFO SendInfo
;
438 PSOCKET_INFORMATION Socket
;
440 /* Get the Socket Structure associate to this Socket*/
441 Socket
= GetSocketStructure(Handle
);
444 *lpErrno
= WSAENOTSOCK
;
448 Status
= NtCreateEvent( &SockEvent
, EVENT_ALL_ACCESS
,
451 if( !NT_SUCCESS(Status
) )
456 /* Set up the Send Structure */
457 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
458 SendInfo
.BufferCount
= dwBufferCount
;
459 SendInfo
.TdiFlags
= 0;
460 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
462 /* Set the TDI Flags */
465 if (iFlags
& MSG_OOB
)
467 SendInfo
.TdiFlags
|= TDI_SEND_EXPEDITED
;
469 if (iFlags
& MSG_PARTIAL
)
471 SendInfo
.TdiFlags
|= TDI_SEND_PARTIAL
;
475 /* Verifiy if we should use APC */
476 if (lpOverlapped
== NULL
)
478 /* Not using Overlapped structure, so use normal blocking on event */
486 if (lpCompletionRoutine
== NULL
)
488 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
489 APCContext
= lpOverlapped
;
491 Event
= lpOverlapped
->hEvent
;
495 /* Using Overlapped Structure and a Completition Routine, so use an APC */
496 APCFunction
= NULL
; // should be a private io completition function inside us
497 APCContext
= lpCompletionRoutine
;
498 SendInfo
.AfdFlags
|= AFD_SKIP_FIO
;
501 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
502 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
505 IOSB
->Status
= STATUS_PENDING
;
508 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
519 /* Wait for completition of not overlapped */
520 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
522 WaitForSingleObject(SockEvent
, INFINITE
); // BUGBUG, shouldn wait infintely for send...
523 Status
= IOSB
->Status
;
526 NtClose( SockEvent
);
528 if (Status
== STATUS_PENDING
)
530 TRACE("Leaving (Pending)\n");
531 return MsafdReturnWithErrno(Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
534 /* Re-enable Async Event */
535 SockReenableAsyncSelectEvent(Socket
, FD_WRITE
);
537 TRACE("Leaving (Success, %d)\n", IOSB
->Information
);
539 return MsafdReturnWithErrno( Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
544 WSPSendTo(SOCKET Handle
,
547 LPDWORD lpNumberOfBytesSent
,
549 const struct sockaddr
*SocketAddress
,
550 int SocketAddressLength
,
551 LPWSAOVERLAPPED lpOverlapped
,
552 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
,
553 LPWSATHREADID lpThreadId
,
556 PIO_STATUS_BLOCK IOSB
;
557 IO_STATUS_BLOCK DummyIOSB
;
558 AFD_SEND_INFO_UDP SendInfo
;
563 PTRANSPORT_ADDRESS RemoteAddress
;
564 PSOCKADDR BindAddress
= NULL
;
565 INT BindAddressLength
;
567 PSOCKET_INFORMATION Socket
;
569 /* Get the Socket Structure associate to this Socket */
570 Socket
= GetSocketStructure(Handle
);
573 *lpErrno
= WSAENOTSOCK
;
577 if (!(Socket
->SharedData
.ServiceFlags1
& XP1_CONNECTIONLESS
))
579 /* Use WSPSend for connection-oriented sockets */
580 return WSPSend(Handle
,
592 if (Socket
->SharedData
.State
== SocketOpen
)
594 /* Get the Wildcard Address */
595 BindAddressLength
= Socket
->HelperData
->MaxWSAddressLength
;
596 BindAddress
= HeapAlloc(GlobalHeap
, 0, BindAddressLength
);
599 MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
600 return INVALID_SOCKET
;
603 Socket
->HelperData
->WSHGetWildcardSockaddr(Socket
->HelperContext
,
607 if (WSPBind(Handle
, BindAddress
, BindAddressLength
, lpErrno
) == SOCKET_ERROR
)
611 RemoteAddress
= HeapAlloc(GlobalHeap
, 0, 0x6 + SocketAddressLength
);
614 if (BindAddress
!= NULL
)
616 HeapFree(GlobalHeap
, 0, BindAddress
);
618 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES
, lpErrno
, 0, NULL
);
621 Status
= NtCreateEvent(&SockEvent
,
625 if (!NT_SUCCESS(Status
))
627 HeapFree(GlobalHeap
, 0, RemoteAddress
);
628 if (BindAddress
!= NULL
)
630 HeapFree(GlobalHeap
, 0, BindAddress
);
635 /* Set up Address in TDI Format */
636 RemoteAddress
->TAAddressCount
= 1;
637 RemoteAddress
->Address
[0].AddressLength
= SocketAddressLength
- sizeof(SocketAddress
->sa_family
);
638 RtlCopyMemory(&RemoteAddress
->Address
[0].AddressType
, SocketAddress
, SocketAddressLength
);
640 /* Set up Structure */
641 SendInfo
.BufferArray
= (PAFD_WSABUF
)lpBuffers
;
642 SendInfo
.AfdFlags
= Socket
->SharedData
.NonBlocking
? AFD_IMMEDIATE
: 0;
643 SendInfo
.BufferCount
= dwBufferCount
;
644 SendInfo
.TdiConnection
.RemoteAddress
= RemoteAddress
;
645 SendInfo
.TdiConnection
.RemoteAddressLength
= Socket
->HelperData
->MaxTDIAddressLength
;
647 /* Verifiy if we should use APC */
648 if (lpOverlapped
== NULL
)
650 /* Not using Overlapped structure, so use normal blocking on event */
658 if (lpCompletionRoutine
== NULL
)
660 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
661 APCContext
= lpOverlapped
;
663 Event
= lpOverlapped
->hEvent
;
667 /* Using Overlapped Structure and a Completition Routine, so use an APC */
668 /* Should be a private io completition function inside us */
670 APCContext
= lpCompletionRoutine
;
671 SendInfo
.AfdFlags
|= AFD_SKIP_FIO
;
674 IOSB
= (PIO_STATUS_BLOCK
)&lpOverlapped
->Internal
;
675 SendInfo
.AfdFlags
|= AFD_OVERLAPPED
;
679 Status
= NtDeviceIoControlFile((HANDLE
)Handle
,
684 IOCTL_AFD_SEND_DATAGRAM
,
690 /* Wait for completition of not overlapped */
691 if (Status
== STATUS_PENDING
&& lpOverlapped
== NULL
)
693 /* BUGBUG, shouldn't wait infintely for send... */
694 WaitForSingleObject(SockEvent
, INFINITE
);
695 Status
= IOSB
->Status
;
699 HeapFree(GlobalHeap
, 0, RemoteAddress
);
700 if (BindAddress
!= NULL
)
702 HeapFree(GlobalHeap
, 0, BindAddress
);
705 SockReenableAsyncSelectEvent(Socket
, FD_WRITE
);
707 return MsafdReturnWithErrno(Status
, lpErrno
, IOSB
->Information
, lpNumberOfBytesSent
);
712 WSPRecvDisconnect(IN SOCKET s
,
713 OUT LPWSABUF lpInboundDisconnectData
,
724 WSPSendDisconnect(IN SOCKET s
,
725 IN LPWSABUF lpOutboundDisconnectData
,