xref: /reactos/dll/win32/msafd/misc/sndrcv.c (revision b99f0b49)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS Ancillary Function Driver DLL
4  * FILE:        dll/win32/msafd/misc/sndrcv.c
5  * PURPOSE:     Send/receive routines
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  *              Alex Ionescu (alex@relsoft.net)
8  * REVISIONS:
9  *              CSH 01/09-2000 Created
10  *              Alex 16/07/2004 - Complete Rewrite
11  */
12 
13 #include <msafd.h>
14 
15 INT
16 WSPAPI
17 WSPAsyncSelect(IN  SOCKET Handle,
18                IN  HWND hWnd,
19                IN  UINT wMsg,
20                IN  LONG lEvent,
21                OUT LPINT lpErrno)
22 {
23     PSOCKET_INFORMATION Socket = NULL;
24     PASYNC_DATA                 AsyncData;
25     BOOLEAN                     BlockMode;
26 
27     /* Get the Socket Structure associated to this Socket */
28     Socket = GetSocketStructure(Handle);
29     if (!Socket)
30     {
31        *lpErrno = WSAENOTSOCK;
32        return SOCKET_ERROR;
33     }
34 
35     /* Allocate the Async Data Structure to pass on to the Thread later */
36     AsyncData = HeapAlloc(GetProcessHeap(), 0, sizeof(*AsyncData));
37     if (!AsyncData)
38     {
39         MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
40         return INVALID_SOCKET;
41     }
42 
43     /* Change the Socket to Non Blocking */
44     BlockMode = TRUE;
45     SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL, NULL, NULL, NULL);
46     Socket->SharedData->NonBlocking = TRUE;
47 
48     /* Deactivate WSPEventSelect */
49     if (Socket->SharedData->AsyncEvents)
50     {
51         if (WSPEventSelect(Handle, NULL, 0, lpErrno) == SOCKET_ERROR)
52         {
53             HeapFree(GetProcessHeap(), 0, AsyncData);
54             return SOCKET_ERROR;
55         }
56     }
57 
58     /* Create the Asynch Thread if Needed */
59     SockCreateOrReferenceAsyncThread();
60 
61     /* Open a Handle to AFD's Async Helper */
62     SockGetAsyncSelectHelperAfdHandle();
63 
64     /* Store Socket Data */
65     Socket->SharedData->hWnd = hWnd;
66     Socket->SharedData->wMsg = wMsg;
67     Socket->SharedData->AsyncEvents = lEvent;
68     Socket->SharedData->AsyncDisabledEvents = 0;
69     Socket->SharedData->SequenceNumber++;
70 
71     /* Return if there are no more Events */
72     if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)) == 0)
73     {
74         HeapFree(GetProcessHeap(), 0, AsyncData);
75         return 0;
76     }
77 
78     /* Set up the Async Data */
79     AsyncData->ParentSocket = Socket;
80     AsyncData->SequenceNumber = Socket->SharedData->SequenceNumber;
81 
82     /* Begin Async Select by using I/O Completion */
83     NtSetIoCompletion(SockAsyncCompletionPort,
84                       (PVOID)&SockProcessQueuedAsyncSelect,
85                       AsyncData,
86                       0,
87                       0);
88 
89     /* Return */
90     return ERROR_SUCCESS;
91 }
92 
93 
94 BOOL
95 WSPAPI
96 WSPGetOverlappedResult(
97     IN  SOCKET Handle,
98     IN  LPWSAOVERLAPPED lpOverlapped,
99     OUT LPDWORD lpdwBytes,
100     IN  BOOL fWait,
101     OUT LPDWORD lpdwFlags,
102     OUT LPINT lpErrno)
103 {
104     PSOCKET_INFORMATION     Socket;
105     BOOL                    Ret;
106 
107     TRACE("Called (%x)\n", Handle);
108 
109     /* Get the Socket Structure associate to this Socket*/
110     Socket = GetSocketStructure(Handle);
111     if (!Socket)
112     {
113         if(lpErrno)
114             *lpErrno = WSAENOTSOCK;
115         return FALSE;
116     }
117     if (!lpOverlapped || !lpdwBytes || !lpdwFlags)
118     {
119         if (lpErrno)
120             *lpErrno = WSAEFAULT;
121         return FALSE;
122     }
123     Ret = GetOverlappedResult((HANDLE)Handle, lpOverlapped, lpdwBytes, fWait);
124 
125     if (Ret)
126     {
127         *lpdwFlags = 0;
128 
129         /* Re-enable Async Event */
130         SockReenableAsyncSelectEvent(Socket, FD_OOB);
131         SockReenableAsyncSelectEvent(Socket, FD_WRITE);
132         SockReenableAsyncSelectEvent(Socket, FD_READ);
133     }
134 
135     return Ret;
136 }
137 
138 VOID
139 NTAPI
140 AfdAPC(PVOID ApcContext,
141        PIO_STATUS_BLOCK IoStatusBlock,
142        ULONG Reserved)
143 {
144     PAFDAPCCONTEXT Context = ApcContext;
145 
146     /* Re-enable Async Event */
147     SockReenableAsyncSelectEvent(Context->lpSocket, FD_OOB);
148     SockReenableAsyncSelectEvent(Context->lpSocket, FD_READ);
149     SockReenableAsyncSelectEvent(Context->lpSocket, FD_WRITE);
150 
151     Context->lpCompletionRoutine(IoStatusBlock->Status, IoStatusBlock->Information, Context->lpOverlapped, 0);
152     HeapFree(GlobalHeap, 0, ApcContext);
153 }
154 
155 int
156 WSPAPI
157 WSPRecv(SOCKET Handle,
158         LPWSABUF lpBuffers,
159         DWORD dwBufferCount,
160         LPDWORD lpNumberOfBytesRead,
161         LPDWORD ReceiveFlags,
162         LPWSAOVERLAPPED lpOverlapped,
163         LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
164         LPWSATHREADID lpThreadId,
165         LPINT lpErrno)
166 {
167     PIO_STATUS_BLOCK        IOSB;
168     IO_STATUS_BLOCK         DummyIOSB;
169     AFD_RECV_INFO           RecvInfo;
170     NTSTATUS                Status;
171     PVOID                   APCContext;
172     PIO_APC_ROUTINE         APCFunction;
173     HANDLE                  Event = NULL;
174     HANDLE                  SockEvent;
175     PSOCKET_INFORMATION     Socket;
176 
177     TRACE("Called (%x)\n", Handle);
178 
179     /* Get the Socket Structure associate to this Socket*/
180     Socket = GetSocketStructure(Handle);
181     if (!Socket)
182     {
183         if (lpErrno)
184             *lpErrno = WSAENOTSOCK;
185         return SOCKET_ERROR;
186     }
187     if (!lpNumberOfBytesRead && !lpOverlapped)
188     {
189         if (lpErrno)
190             *lpErrno = WSAEFAULT;
191         return SOCKET_ERROR;
192     }
193     if (Socket->SharedData->OobInline && ReceiveFlags && (*ReceiveFlags & MSG_OOB) != 0)
194     {
195         if (lpErrno)
196             *lpErrno = WSAEINVAL;
197         return SOCKET_ERROR;
198     }
199 
200     Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
201                             NULL, SynchronizationEvent, FALSE );
202 
203     if( !NT_SUCCESS(Status) )
204         return -1;
205 
206     /* Set up the Receive Structure */
207     RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
208     RecvInfo.BufferCount = dwBufferCount;
209     RecvInfo.TdiFlags = 0;
210     RecvInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
211 
212     /* Set the TDI Flags */
213     if (*ReceiveFlags == 0)
214     {
215         RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
216     }
217     else
218     {
219         if (*ReceiveFlags & MSG_OOB)
220         {
221             RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
222         }
223 
224         if (*ReceiveFlags & MSG_PEEK)
225         {
226             RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
227         }
228 
229         if (*ReceiveFlags & MSG_PARTIAL)
230         {
231             RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
232         }
233     }
234 
235     /* Verify if we should use APC */
236 
237     if (lpOverlapped == NULL)
238     {
239         /* Not using Overlapped structure, so use normal blocking on event */
240         APCContext = NULL;
241         APCFunction = NULL;
242         Event = SockEvent;
243         IOSB = &DummyIOSB;
244     }
245     else
246     {
247         /* Overlapped request for non overlapped opened socket */
248         if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
249         {
250             TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
251             return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesRead);
252         }
253         if (lpCompletionRoutine == NULL)
254         {
255             /* Using Overlapped Structure, but no Completion Routine, so no need for APC */
256             APCContext = lpOverlapped;
257             APCFunction = NULL;
258             Event = lpOverlapped->hEvent;
259         }
260         else
261         {
262             /* Using Overlapped Structure and a Completion Routine, so use an APC */
263             APCFunction = &AfdAPC; // should be a private io completion function inside us
264             APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
265             if (!APCContext)
266             {
267                 ERR("Not enough memory for APC Context\n");
268                 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesRead);
269             }
270             ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
271             ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
272             ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
273             RecvInfo.AfdFlags |= AFD_SKIP_FIO;
274         }
275 
276         IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
277         RecvInfo.AfdFlags |= AFD_OVERLAPPED;
278     }
279 
280     IOSB->Status = STATUS_PENDING;
281 
282     /* Send IOCTL */
283     Status = NtDeviceIoControlFile((HANDLE)Handle,
284                                    Event,
285                                    APCFunction,
286                                    APCContext,
287                                    IOSB,
288                                    IOCTL_AFD_RECV,
289                                    &RecvInfo,
290                                    sizeof(RecvInfo),
291                                    NULL,
292                                    0);
293 
294     /* Wait for completion of not overlapped */
295     if (Status == STATUS_PENDING && lpOverlapped == NULL)
296     {
297         /* It's up to the protocol to time out recv.  We must wait
298          * until the protocol decides it's had enough.
299          */
300         WaitForSingleObject(SockEvent, INFINITE);
301         Status = IOSB->Status;
302     }
303 
304     NtClose( SockEvent );
305 
306     TRACE("Status %x Information %d\n", Status, IOSB->Information);
307 
308     if (Status == STATUS_PENDING)
309     {
310         TRACE("Leaving (Pending)\n");
311         return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead);
312     }
313 
314     /* Return the Flags */
315     *ReceiveFlags = 0;
316 
317     switch (Status)
318     {
319         case STATUS_RECEIVE_EXPEDITED:
320             *ReceiveFlags = MSG_OOB;
321             break;
322         case STATUS_RECEIVE_PARTIAL_EXPEDITED:
323             *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
324             break;
325         case STATUS_RECEIVE_PARTIAL:
326             *ReceiveFlags = MSG_PARTIAL;
327             break;
328     }
329 
330     /* Re-enable Async Event */
331     if (*ReceiveFlags & MSG_OOB)
332     {
333         SockReenableAsyncSelectEvent(Socket, FD_OOB);
334     }
335     else
336     {
337         SockReenableAsyncSelectEvent(Socket, FD_READ);
338     }
339 
340     if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
341     {
342         lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags);
343         HeapFree(GlobalHeap, 0, (PVOID)APCContext);
344     }
345 
346     return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
347 }
348 
349 int
350 WSPAPI
351 WSPRecvFrom(SOCKET Handle,
352             LPWSABUF lpBuffers,
353             DWORD dwBufferCount,
354             LPDWORD lpNumberOfBytesRead,
355             LPDWORD ReceiveFlags,
356             struct sockaddr *SocketAddress,
357             int *SocketAddressLength,
358             LPWSAOVERLAPPED lpOverlapped,
359             LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
360             LPWSATHREADID lpThreadId,
361             LPINT lpErrno )
362 {
363     PIO_STATUS_BLOCK            IOSB;
364     IO_STATUS_BLOCK             DummyIOSB;
365     AFD_RECV_INFO_UDP           RecvInfo;
366     NTSTATUS                    Status;
367     PVOID                       APCContext;
368     PVOID                       APCFunction;
369     HANDLE                      Event = NULL;
370     HANDLE                      SockEvent;
371     PSOCKET_INFORMATION         Socket;
372 
373     /* Get the Socket Structure associate to this Socket*/
374     Socket = GetSocketStructure(Handle);
375     if (!Socket)
376     {
377         if (lpErrno)
378             *lpErrno = WSAENOTSOCK;
379         return SOCKET_ERROR;
380     }
381     if (!lpNumberOfBytesRead && !lpOverlapped)
382     {
383         if (lpErrno)
384             *lpErrno = WSAEFAULT;
385         return SOCKET_ERROR;
386     }
387     if (Socket->SharedData->OobInline && ReceiveFlags && (*ReceiveFlags & MSG_OOB) != 0)
388     {
389         if (lpErrno)
390             *lpErrno = WSAEINVAL;
391         return SOCKET_ERROR;
392     }
393 
394     if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS))
395     {
396         /* Call WSPRecv for a non-datagram socket */
397         return WSPRecv(Handle,
398                        lpBuffers,
399                        dwBufferCount,
400                        lpNumberOfBytesRead,
401                        ReceiveFlags,
402                        lpOverlapped,
403                        lpCompletionRoutine,
404                        lpThreadId,
405                        lpErrno);
406     }
407 
408     /* Bind us First */
409     if (Socket->SharedData->State == SocketOpen)
410     {
411         Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext,
412             SocketAddress,
413             SocketAddressLength);
414         /* Bind it */
415         if (WSPBind(Handle, SocketAddress, *SocketAddressLength, lpErrno) == SOCKET_ERROR)
416             return SOCKET_ERROR;
417     }
418 
419     Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
420                             NULL, SynchronizationEvent, FALSE );
421 
422     if( !NT_SUCCESS(Status) )
423         return -1;
424 
425     /* Set up the Receive Structure */
426     RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
427     RecvInfo.BufferCount = dwBufferCount;
428     RecvInfo.TdiFlags = 0;
429     RecvInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
430     RecvInfo.AddressLength = SocketAddressLength;
431     RecvInfo.Address = SocketAddress;
432 
433     /* Set the TDI Flags */
434     if (*ReceiveFlags == 0)
435     {
436         RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
437     }
438     else
439     {
440         if (*ReceiveFlags & MSG_OOB)
441         {
442             RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
443         }
444 
445         if (*ReceiveFlags & MSG_PEEK)
446         {
447             RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
448         }
449 
450         if (*ReceiveFlags & MSG_PARTIAL)
451         {
452             RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
453         }
454     }
455 
456     /* Verify if we should use APC */
457 
458     if (lpOverlapped == NULL)
459     {
460         /* Not using Overlapped structure, so use normal blocking on event */
461         APCContext = NULL;
462         APCFunction = NULL;
463         Event = SockEvent;
464         IOSB = &DummyIOSB;
465     }
466     else
467     {
468         /* Overlapped request for non overlapped opened socket */
469         if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
470         {
471             TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
472             return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesRead);
473         }
474         if (lpCompletionRoutine == NULL)
475         {
476             /* Using Overlapped Structure, but no Completion Routine, so no need for APC */
477             APCContext = lpOverlapped;
478             APCFunction = NULL;
479             Event = lpOverlapped->hEvent;
480         }
481         else
482         {
483             /* Using Overlapped Structure and a Completion Routine, so use an APC */
484             APCFunction = &AfdAPC; // should be a private io completion function inside us
485             APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
486             if (!APCContext)
487             {
488                 ERR("Not enough memory for APC Context\n");
489                 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesRead);
490             }
491             ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
492             ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
493             ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
494             RecvInfo.AfdFlags |= AFD_SKIP_FIO;
495         }
496 
497         IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
498         RecvInfo.AfdFlags |= AFD_OVERLAPPED;
499     }
500 
501     IOSB->Status = STATUS_PENDING;
502 
503     /* Send IOCTL */
504     Status = NtDeviceIoControlFile((HANDLE)Handle,
505                                     Event,
506                                     APCFunction,
507                                     APCContext,
508                                     IOSB,
509                                     IOCTL_AFD_RECV_DATAGRAM,
510                                     &RecvInfo,
511                                     sizeof(RecvInfo),
512                                     NULL,
513                                     0);
514 
515     /* Wait for completion of not overlapped */
516     if (Status == STATUS_PENDING && lpOverlapped == NULL)
517     {
518         WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infinitely for receive...
519         Status = IOSB->Status;
520     }
521 
522     NtClose( SockEvent );
523 
524     if (Status == STATUS_PENDING)
525     {
526         TRACE("Leaving (Pending)\n");
527         return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead);
528     }
529 
530     /* Return the Flags */
531     *ReceiveFlags = 0;
532 
533     switch (Status)
534     {
535         case STATUS_RECEIVE_EXPEDITED:
536             *ReceiveFlags = MSG_OOB;
537             break;
538         case STATUS_RECEIVE_PARTIAL_EXPEDITED:
539             *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
540             break;
541         case STATUS_RECEIVE_PARTIAL:
542             *ReceiveFlags = MSG_PARTIAL;
543             break;
544     }
545 
546     /* Re-enable Async Event */
547     if (*ReceiveFlags & MSG_OOB)
548     {
549         SockReenableAsyncSelectEvent(Socket, FD_OOB);
550     }
551     else
552     {
553         SockReenableAsyncSelectEvent(Socket, FD_READ);
554     }
555 
556     if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
557     {
558         lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags);
559         HeapFree(GlobalHeap, 0, (PVOID)APCContext);
560     }
561 
562     return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
563 }
564 
565 
566 int
567 WSPAPI
568 WSPSend(SOCKET Handle,
569         LPWSABUF lpBuffers,
570         DWORD dwBufferCount,
571         LPDWORD lpNumberOfBytesSent,
572         DWORD iFlags,
573         LPWSAOVERLAPPED lpOverlapped,
574         LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
575         LPWSATHREADID lpThreadId,
576         LPINT lpErrno)
577 {
578     PIO_STATUS_BLOCK        IOSB;
579     IO_STATUS_BLOCK         DummyIOSB;
580     AFD_SEND_INFO           SendInfo;
581     NTSTATUS                Status;
582     PVOID                   APCContext;
583     PVOID                   APCFunction;
584     HANDLE                  Event = NULL;
585     HANDLE                  SockEvent;
586     PSOCKET_INFORMATION     Socket;
587 
588     /* Get the Socket Structure associate to this Socket*/
589     Socket = GetSocketStructure(Handle);
590     if (!Socket)
591     {
592         if (lpErrno)
593             *lpErrno = WSAENOTSOCK;
594         return SOCKET_ERROR;
595     }
596     if (!lpNumberOfBytesSent && !lpOverlapped)
597     {
598         if (lpErrno)
599             *lpErrno = WSAEFAULT;
600         return SOCKET_ERROR;
601     }
602 
603     Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
604                             NULL, SynchronizationEvent, FALSE );
605 
606     if( !NT_SUCCESS(Status) )
607         return -1;
608 
609     TRACE("Called\n");
610 
611     /* Set up the Send Structure */
612     SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
613     SendInfo.BufferCount = dwBufferCount;
614     SendInfo.TdiFlags = 0;
615     SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
616 
617     /* Set the TDI Flags */
618     if (iFlags)
619     {
620         if (iFlags & MSG_OOB)
621         {
622             SendInfo.TdiFlags |= TDI_SEND_EXPEDITED;
623         }
624         if (iFlags & MSG_PARTIAL)
625         {
626             SendInfo.TdiFlags |= TDI_SEND_PARTIAL;
627         }
628     }
629 
630     /* Verify if we should use APC */
631     if (lpOverlapped == NULL)
632     {
633         /* Not using Overlapped structure, so use normal blocking on event */
634         APCContext = NULL;
635         APCFunction = NULL;
636         Event = SockEvent;
637         IOSB = &DummyIOSB;
638     }
639     else
640     {
641         /* Overlapped request for non overlapped opened socket */
642         if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
643         {
644             TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
645             return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent);
646         }
647         if (lpCompletionRoutine == NULL)
648         {
649             /* Using Overlapped Structure, but no Completion Routine, so no need for APC */
650             APCContext = lpOverlapped;
651             APCFunction = NULL;
652             Event = lpOverlapped->hEvent;
653         }
654         else
655         {
656             /* Using Overlapped Structure and a Completion Routine, so use an APC */
657             APCFunction = &AfdAPC; // should be a private io completion function inside us
658             APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
659             if (!APCContext)
660             {
661                 ERR("Not enough memory for APC Context\n");
662                 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent);
663             }
664             ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
665             ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
666             ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
667             SendInfo.AfdFlags |= AFD_SKIP_FIO;
668         }
669 
670         IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
671         SendInfo.AfdFlags |= AFD_OVERLAPPED;
672     }
673 
674     IOSB->Status = STATUS_PENDING;
675 
676     /* Send IOCTL */
677     Status = NtDeviceIoControlFile((HANDLE)Handle,
678                                     Event,
679                                     APCFunction,
680                                     APCContext,
681                                     IOSB,
682                                     IOCTL_AFD_SEND,
683                                     &SendInfo,
684                                     sizeof(SendInfo),
685                                     NULL,
686                                     0);
687 
688     /* Wait for completion of not overlapped */
689     if (Status == STATUS_PENDING && lpOverlapped == NULL)
690     {
691         WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infinitely for send...
692         Status = IOSB->Status;
693     }
694 
695     NtClose( SockEvent );
696 
697     if (Status == STATUS_PENDING)
698     {
699         TRACE("Leaving (Pending)\n");
700         return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
701     }
702 
703     /* Re-enable Async Event */
704     SockReenableAsyncSelectEvent(Socket, FD_WRITE);
705 
706     TRACE("Leaving (Success, %d)\n", IOSB->Information);
707 
708     if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
709     {
710         lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0);
711         HeapFree(GlobalHeap, 0, (PVOID)APCContext);
712     }
713 
714     return MsafdReturnWithErrno( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent );
715 }
716 
717 int
718 WSPAPI
719 WSPSendTo(SOCKET Handle,
720           LPWSABUF lpBuffers,
721           DWORD dwBufferCount,
722           LPDWORD lpNumberOfBytesSent,
723           DWORD iFlags,
724           const struct sockaddr *SocketAddress,
725           int SocketAddressLength,
726           LPWSAOVERLAPPED lpOverlapped,
727           LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
728           LPWSATHREADID lpThreadId,
729           LPINT lpErrno)
730 {
731     PIO_STATUS_BLOCK        IOSB;
732     IO_STATUS_BLOCK         DummyIOSB;
733     AFD_SEND_INFO_UDP       SendInfo;
734     NTSTATUS                Status;
735     PVOID                   APCContext;
736     PVOID                   APCFunction;
737     HANDLE                  Event = NULL;
738     PTRANSPORT_ADDRESS      RemoteAddress;
739     PSOCKADDR               BindAddress = NULL;
740     INT                     BindAddressLength;
741     HANDLE                  SockEvent;
742     PSOCKET_INFORMATION     Socket;
743 
744     /* Get the Socket Structure associate to this Socket */
745     Socket = GetSocketStructure(Handle);
746     if (!Socket)
747     {
748         if (lpErrno)
749             *lpErrno = WSAENOTSOCK;
750         return SOCKET_ERROR;
751     }
752     if (!lpNumberOfBytesSent && !lpOverlapped)
753     {
754         if (lpErrno)
755             *lpErrno = WSAEFAULT;
756         return SOCKET_ERROR;
757     }
758 
759     if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS))
760     {
761         /* Use WSPSend for connection-oriented sockets */
762         return WSPSend(Handle,
763                        lpBuffers,
764                        dwBufferCount,
765                        lpNumberOfBytesSent,
766                        iFlags,
767                        lpOverlapped,
768                        lpCompletionRoutine,
769                        lpThreadId,
770                        lpErrno);
771     }
772 
773     /* Bind us First */
774     if (Socket->SharedData->State == SocketOpen)
775     {
776         /* Get the Wildcard Address */
777         BindAddressLength = Socket->HelperData->MaxWSAddressLength;
778         BindAddress = HeapAlloc(GlobalHeap, 0, BindAddressLength);
779         if (!BindAddress)
780         {
781             MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
782             return INVALID_SOCKET;
783         }
784 
785         Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext,
786                                                    BindAddress,
787                                                    &BindAddressLength);
788         /* Bind it */
789         if (WSPBind(Handle, BindAddress, BindAddressLength, lpErrno) == SOCKET_ERROR)
790             return SOCKET_ERROR;
791     }
792 
793     RemoteAddress = HeapAlloc(GlobalHeap, 0, 0x6 + SocketAddressLength);
794     if (!RemoteAddress)
795     {
796         if (BindAddress != NULL)
797         {
798             HeapFree(GlobalHeap, 0, BindAddress);
799         }
800         return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
801     }
802 
803     Status = NtCreateEvent(&SockEvent,
804                            EVENT_ALL_ACCESS,
805                            NULL, SynchronizationEvent, FALSE);
806 
807     if (!NT_SUCCESS(Status))
808     {
809         HeapFree(GlobalHeap, 0, RemoteAddress);
810         if (BindAddress != NULL)
811         {
812             HeapFree(GlobalHeap, 0, BindAddress);
813         }
814         return SOCKET_ERROR;
815     }
816 
817     /* Set up Address in TDI Format */
818     RemoteAddress->TAAddressCount = 1;
819     RemoteAddress->Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family);
820     RtlCopyMemory(&RemoteAddress->Address[0].AddressType, SocketAddress, SocketAddressLength);
821 
822     /* Set up Structure */
823     SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
824     SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
825     SendInfo.BufferCount = dwBufferCount;
826     SendInfo.TdiConnection.RemoteAddress = RemoteAddress;
827     SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength;
828 
829     /* Verify if we should use APC */
830     if (lpOverlapped == NULL)
831     {
832         /* Not using Overlapped structure, so use normal blocking on event */
833         APCContext = NULL;
834         APCFunction = NULL;
835         Event = SockEvent;
836         IOSB = &DummyIOSB;
837     }
838     else
839     {
840         /* Overlapped request for non overlapped opened socket */
841         if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
842         {
843             TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
844             return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent);
845         }
846         if (lpCompletionRoutine == NULL)
847         {
848             /* Using Overlapped Structure, but no Completion Routine, so no need for APC */
849             APCContext = lpOverlapped;
850             APCFunction = NULL;
851             Event = lpOverlapped->hEvent;
852         }
853         else
854         {
855             /* Using Overlapped Structure and a Completion Routine, so use an APC */
856             APCFunction = &AfdAPC; // should be a private io completion function inside us
857             APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
858             if (!APCContext)
859             {
860                 ERR("Not enough memory for APC Context\n");
861                 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent);
862             }
863             ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
864             ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
865             ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
866             SendInfo.AfdFlags |= AFD_SKIP_FIO;
867         }
868 
869         IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
870         SendInfo.AfdFlags |= AFD_OVERLAPPED;
871     }
872 
873     /* Send IOCTL */
874     Status = NtDeviceIoControlFile((HANDLE)Handle,
875                                    Event,
876                                    APCFunction,
877                                    APCContext,
878                                    IOSB,
879                                    IOCTL_AFD_SEND_DATAGRAM,
880                                    &SendInfo,
881                                    sizeof(SendInfo),
882                                    NULL,
883                                    0);
884 
885     /* Wait for completion of not overlapped */
886     if (Status == STATUS_PENDING && lpOverlapped == NULL)
887     {
888         /* BUGBUG, shouldn't wait infinitely for send... */
889         WaitForSingleObject(SockEvent, INFINITE);
890         Status = IOSB->Status;
891     }
892 
893     NtClose(SockEvent);
894     HeapFree(GlobalHeap, 0, RemoteAddress);
895     if (BindAddress != NULL)
896     {
897         HeapFree(GlobalHeap, 0, BindAddress);
898     }
899 
900     if (Status == STATUS_PENDING)
901     {
902         TRACE("Leaving (Pending)\n");
903         return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
904     }
905 
906     SockReenableAsyncSelectEvent(Socket, FD_WRITE);
907 
908     if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
909     {
910         lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0);
911         HeapFree(GlobalHeap, 0, (PVOID)APCContext);
912     }
913 
914     return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
915 }
916 
917 INT
918 WSPAPI
919 WSPRecvDisconnect(IN  SOCKET s,
920                   OUT LPWSABUF lpInboundDisconnectData,
921                   OUT LPINT lpErrno)
922 {
923     UNIMPLEMENTED;
924     return 0;
925 }
926 
927 
928 
929 INT
930 WSPAPI
931 WSPSendDisconnect(IN  SOCKET s,
932                   IN  LPWSABUF lpOutboundDisconnectData,
933                   OUT LPINT lpErrno)
934 {
935     UNIMPLEMENTED;
936     return 0;
937 }
938 
939 /* EOF */
940