xref: /reactos/dll/win32/msafd/misc/sndrcv.c (revision 9cfd8dd9)
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     /* Non-blocking sockets must wait until data is available */
295     if (Status == STATUS_PENDING && Socket->SharedData->NonBlocking)
296     {
297         if (lpErrno) *lpErrno = WSAEWOULDBLOCK;
298         return SOCKET_ERROR;
299     }
300 
301     /* Wait for completion of not overlapped */
302     if (Status == STATUS_PENDING && lpOverlapped == NULL)
303     {
304         /* It's up to the protocol to time out recv.  We must wait
305          * until the protocol decides it's had enough.
306          */
307         WaitForSingleObject(SockEvent, INFINITE);
308         Status = IOSB->Status;
309     }
310 
311     NtClose( SockEvent );
312 
313     TRACE("Status %x Information %d\n", Status, IOSB->Information);
314 
315     if (Status == STATUS_PENDING)
316     {
317         TRACE("Leaving (Pending)\n");
318         return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead);
319     }
320 
321     /* Return the Flags */
322     *ReceiveFlags = 0;
323 
324     switch (Status)
325     {
326         case STATUS_RECEIVE_EXPEDITED:
327             *ReceiveFlags = MSG_OOB;
328             break;
329         case STATUS_RECEIVE_PARTIAL_EXPEDITED:
330             *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
331             break;
332         case STATUS_RECEIVE_PARTIAL:
333             *ReceiveFlags = MSG_PARTIAL;
334             break;
335     }
336 
337     /* Re-enable Async Event */
338     if (*ReceiveFlags & MSG_OOB)
339     {
340         SockReenableAsyncSelectEvent(Socket, FD_OOB);
341     }
342     else
343     {
344         SockReenableAsyncSelectEvent(Socket, FD_READ);
345     }
346 
347     if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
348     {
349         lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags);
350         HeapFree(GlobalHeap, 0, (PVOID)APCContext);
351     }
352 
353     return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
354 }
355 
356 int
357 WSPAPI
358 WSPRecvFrom(SOCKET Handle,
359             LPWSABUF lpBuffers,
360             DWORD dwBufferCount,
361             LPDWORD lpNumberOfBytesRead,
362             LPDWORD ReceiveFlags,
363             struct sockaddr *SocketAddress,
364             int *SocketAddressLength,
365             LPWSAOVERLAPPED lpOverlapped,
366             LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
367             LPWSATHREADID lpThreadId,
368             LPINT lpErrno )
369 {
370     PIO_STATUS_BLOCK            IOSB;
371     IO_STATUS_BLOCK             DummyIOSB;
372     AFD_RECV_INFO_UDP           RecvInfo;
373     NTSTATUS                    Status;
374     PVOID                       APCContext;
375     PVOID                       APCFunction;
376     HANDLE                      Event = NULL;
377     HANDLE                      SockEvent;
378     PSOCKET_INFORMATION         Socket;
379 
380     /* Get the Socket Structure associate to this Socket*/
381     Socket = GetSocketStructure(Handle);
382     if (!Socket)
383     {
384         if (lpErrno)
385             *lpErrno = WSAENOTSOCK;
386         return SOCKET_ERROR;
387     }
388     if (!lpNumberOfBytesRead && !lpOverlapped)
389     {
390         if (lpErrno)
391             *lpErrno = WSAEFAULT;
392         return SOCKET_ERROR;
393     }
394     if (Socket->SharedData->OobInline && ReceiveFlags && (*ReceiveFlags & MSG_OOB) != 0)
395     {
396         if (lpErrno)
397             *lpErrno = WSAEINVAL;
398         return SOCKET_ERROR;
399     }
400 
401     if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS))
402     {
403         /* Call WSPRecv for a non-datagram socket */
404         return WSPRecv(Handle,
405                        lpBuffers,
406                        dwBufferCount,
407                        lpNumberOfBytesRead,
408                        ReceiveFlags,
409                        lpOverlapped,
410                        lpCompletionRoutine,
411                        lpThreadId,
412                        lpErrno);
413     }
414 
415     /* Bind us First */
416     if (Socket->SharedData->State == SocketOpen)
417     {
418         Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext,
419             SocketAddress,
420             SocketAddressLength);
421         /* Bind it */
422         if (WSPBind(Handle, SocketAddress, *SocketAddressLength, lpErrno) == SOCKET_ERROR)
423             return SOCKET_ERROR;
424     }
425 
426     Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
427                             NULL, SynchronizationEvent, FALSE );
428 
429     if( !NT_SUCCESS(Status) )
430         return -1;
431 
432     /* Set up the Receive Structure */
433     RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
434     RecvInfo.BufferCount = dwBufferCount;
435     RecvInfo.TdiFlags = 0;
436     RecvInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
437     RecvInfo.AddressLength = SocketAddressLength;
438     RecvInfo.Address = SocketAddress;
439 
440     /* Set the TDI Flags */
441     if (*ReceiveFlags == 0)
442     {
443         RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
444     }
445     else
446     {
447         if (*ReceiveFlags & MSG_OOB)
448         {
449             RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
450         }
451 
452         if (*ReceiveFlags & MSG_PEEK)
453         {
454             RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
455         }
456 
457         if (*ReceiveFlags & MSG_PARTIAL)
458         {
459             RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
460         }
461     }
462 
463     /* Verify if we should use APC */
464 
465     if (lpOverlapped == NULL)
466     {
467         /* Not using Overlapped structure, so use normal blocking on event */
468         APCContext = NULL;
469         APCFunction = NULL;
470         Event = SockEvent;
471         IOSB = &DummyIOSB;
472     }
473     else
474     {
475         /* Overlapped request for non overlapped opened socket */
476         if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
477         {
478             TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
479             return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesRead);
480         }
481         if (lpCompletionRoutine == NULL)
482         {
483             /* Using Overlapped Structure, but no Completion Routine, so no need for APC */
484             APCContext = lpOverlapped;
485             APCFunction = NULL;
486             Event = lpOverlapped->hEvent;
487         }
488         else
489         {
490             /* Using Overlapped Structure and a Completion Routine, so use an APC */
491             APCFunction = &AfdAPC; // should be a private io completion function inside us
492             APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
493             if (!APCContext)
494             {
495                 ERR("Not enough memory for APC Context\n");
496                 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesRead);
497             }
498             ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
499             ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
500             ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
501             RecvInfo.AfdFlags |= AFD_SKIP_FIO;
502         }
503 
504         IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
505         RecvInfo.AfdFlags |= AFD_OVERLAPPED;
506     }
507 
508     IOSB->Status = STATUS_PENDING;
509 
510     /* Send IOCTL */
511     Status = NtDeviceIoControlFile((HANDLE)Handle,
512                                     Event,
513                                     APCFunction,
514                                     APCContext,
515                                     IOSB,
516                                     IOCTL_AFD_RECV_DATAGRAM,
517                                     &RecvInfo,
518                                     sizeof(RecvInfo),
519                                     NULL,
520                                     0);
521 
522     /* Wait for completion of not overlapped */
523     if (Status == STATUS_PENDING && lpOverlapped == NULL)
524     {
525         WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infinitely for receive...
526         Status = IOSB->Status;
527     }
528 
529     NtClose( SockEvent );
530 
531     if (Status == STATUS_PENDING)
532     {
533         TRACE("Leaving (Pending)\n");
534         return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead);
535     }
536 
537     /* Return the Flags */
538     *ReceiveFlags = 0;
539 
540     switch (Status)
541     {
542         case STATUS_RECEIVE_EXPEDITED:
543             *ReceiveFlags = MSG_OOB;
544             break;
545         case STATUS_RECEIVE_PARTIAL_EXPEDITED:
546             *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
547             break;
548         case STATUS_RECEIVE_PARTIAL:
549             *ReceiveFlags = MSG_PARTIAL;
550             break;
551     }
552 
553     /* Re-enable Async Event */
554     if (*ReceiveFlags & MSG_OOB)
555     {
556         SockReenableAsyncSelectEvent(Socket, FD_OOB);
557     }
558     else
559     {
560         SockReenableAsyncSelectEvent(Socket, FD_READ);
561     }
562 
563     if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
564     {
565         lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags);
566         HeapFree(GlobalHeap, 0, (PVOID)APCContext);
567     }
568 
569     return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
570 }
571 
572 
573 int
574 WSPAPI
575 WSPSend(SOCKET Handle,
576         LPWSABUF lpBuffers,
577         DWORD dwBufferCount,
578         LPDWORD lpNumberOfBytesSent,
579         DWORD iFlags,
580         LPWSAOVERLAPPED lpOverlapped,
581         LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
582         LPWSATHREADID lpThreadId,
583         LPINT lpErrno)
584 {
585     PIO_STATUS_BLOCK        IOSB;
586     IO_STATUS_BLOCK         DummyIOSB;
587     AFD_SEND_INFO           SendInfo;
588     NTSTATUS                Status;
589     PVOID                   APCContext;
590     PVOID                   APCFunction;
591     HANDLE                  Event = NULL;
592     HANDLE                  SockEvent;
593     PSOCKET_INFORMATION     Socket;
594 
595     /* Get the Socket Structure associate to this Socket*/
596     Socket = GetSocketStructure(Handle);
597     if (!Socket)
598     {
599         if (lpErrno)
600             *lpErrno = WSAENOTSOCK;
601         return SOCKET_ERROR;
602     }
603     if (!lpNumberOfBytesSent && !lpOverlapped)
604     {
605         if (lpErrno)
606             *lpErrno = WSAEFAULT;
607         return SOCKET_ERROR;
608     }
609 
610     Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
611                             NULL, SynchronizationEvent, FALSE );
612 
613     if( !NT_SUCCESS(Status) )
614         return -1;
615 
616     TRACE("Called\n");
617 
618     /* Set up the Send Structure */
619     SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
620     SendInfo.BufferCount = dwBufferCount;
621     SendInfo.TdiFlags = 0;
622     SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
623 
624     /* Set the TDI Flags */
625     if (iFlags)
626     {
627         if (iFlags & MSG_OOB)
628         {
629             SendInfo.TdiFlags |= TDI_SEND_EXPEDITED;
630         }
631         if (iFlags & MSG_PARTIAL)
632         {
633             SendInfo.TdiFlags |= TDI_SEND_PARTIAL;
634         }
635     }
636 
637     /* Verify if we should use APC */
638     if (lpOverlapped == NULL)
639     {
640         /* Not using Overlapped structure, so use normal blocking on event */
641         APCContext = NULL;
642         APCFunction = NULL;
643         Event = SockEvent;
644         IOSB = &DummyIOSB;
645     }
646     else
647     {
648         /* Overlapped request for non overlapped opened socket */
649         if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
650         {
651             TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
652             return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent);
653         }
654         if (lpCompletionRoutine == NULL)
655         {
656             /* Using Overlapped Structure, but no Completion Routine, so no need for APC */
657             APCContext = lpOverlapped;
658             APCFunction = NULL;
659             Event = lpOverlapped->hEvent;
660         }
661         else
662         {
663             /* Using Overlapped Structure and a Completion Routine, so use an APC */
664             APCFunction = &AfdAPC; // should be a private io completion function inside us
665             APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
666             if (!APCContext)
667             {
668                 ERR("Not enough memory for APC Context\n");
669                 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent);
670             }
671             ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
672             ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
673             ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
674             SendInfo.AfdFlags |= AFD_SKIP_FIO;
675         }
676 
677         IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
678         SendInfo.AfdFlags |= AFD_OVERLAPPED;
679     }
680 
681     IOSB->Status = STATUS_PENDING;
682 
683     /* Send IOCTL */
684     Status = NtDeviceIoControlFile((HANDLE)Handle,
685                                     Event,
686                                     APCFunction,
687                                     APCContext,
688                                     IOSB,
689                                     IOCTL_AFD_SEND,
690                                     &SendInfo,
691                                     sizeof(SendInfo),
692                                     NULL,
693                                     0);
694 
695     /* Wait for completion of not overlapped */
696     if (Status == STATUS_PENDING && lpOverlapped == NULL)
697     {
698         WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infinitely for send...
699         Status = IOSB->Status;
700     }
701 
702     NtClose( SockEvent );
703 
704     if (Status == STATUS_PENDING)
705     {
706         TRACE("Leaving (Pending)\n");
707         return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
708     }
709 
710     /* Re-enable Async Event */
711     SockReenableAsyncSelectEvent(Socket, FD_WRITE);
712 
713     TRACE("Leaving (Success, %d)\n", IOSB->Information);
714 
715     if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
716     {
717         lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0);
718         HeapFree(GlobalHeap, 0, (PVOID)APCContext);
719     }
720 
721     return MsafdReturnWithErrno( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent );
722 }
723 
724 int
725 WSPAPI
726 WSPSendTo(SOCKET Handle,
727           LPWSABUF lpBuffers,
728           DWORD dwBufferCount,
729           LPDWORD lpNumberOfBytesSent,
730           DWORD iFlags,
731           const struct sockaddr *SocketAddress,
732           int SocketAddressLength,
733           LPWSAOVERLAPPED lpOverlapped,
734           LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
735           LPWSATHREADID lpThreadId,
736           LPINT lpErrno)
737 {
738     PIO_STATUS_BLOCK        IOSB;
739     IO_STATUS_BLOCK         DummyIOSB;
740     AFD_SEND_INFO_UDP       SendInfo;
741     NTSTATUS                Status;
742     PVOID                   APCContext;
743     PVOID                   APCFunction;
744     HANDLE                  Event = NULL;
745     PTRANSPORT_ADDRESS      RemoteAddress;
746     PSOCKADDR               BindAddress = NULL;
747     INT                     BindAddressLength;
748     HANDLE                  SockEvent;
749     PSOCKET_INFORMATION     Socket;
750 
751     /* Get the Socket Structure associate to this Socket */
752     Socket = GetSocketStructure(Handle);
753     if (!Socket)
754     {
755         if (lpErrno)
756             *lpErrno = WSAENOTSOCK;
757         return SOCKET_ERROR;
758     }
759     if (!lpNumberOfBytesSent && !lpOverlapped)
760     {
761         if (lpErrno)
762             *lpErrno = WSAEFAULT;
763         return SOCKET_ERROR;
764     }
765 
766     if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS))
767     {
768         /* Use WSPSend for connection-oriented sockets */
769         return WSPSend(Handle,
770                        lpBuffers,
771                        dwBufferCount,
772                        lpNumberOfBytesSent,
773                        iFlags,
774                        lpOverlapped,
775                        lpCompletionRoutine,
776                        lpThreadId,
777                        lpErrno);
778     }
779 
780     /* Bind us First */
781     if (Socket->SharedData->State == SocketOpen)
782     {
783         /* Get the Wildcard Address */
784         BindAddressLength = Socket->HelperData->MaxWSAddressLength;
785         BindAddress = HeapAlloc(GlobalHeap, 0, BindAddressLength);
786         if (!BindAddress)
787         {
788             MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
789             return INVALID_SOCKET;
790         }
791 
792         Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext,
793                                                    BindAddress,
794                                                    &BindAddressLength);
795         /* Bind it */
796         if (WSPBind(Handle, BindAddress, BindAddressLength, lpErrno) == SOCKET_ERROR)
797             return SOCKET_ERROR;
798     }
799 
800     RemoteAddress = HeapAlloc(GlobalHeap, 0, 0x6 + SocketAddressLength);
801     if (!RemoteAddress)
802     {
803         if (BindAddress != NULL)
804         {
805             HeapFree(GlobalHeap, 0, BindAddress);
806         }
807         return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
808     }
809 
810     Status = NtCreateEvent(&SockEvent,
811                            EVENT_ALL_ACCESS,
812                            NULL, SynchronizationEvent, FALSE);
813 
814     if (!NT_SUCCESS(Status))
815     {
816         HeapFree(GlobalHeap, 0, RemoteAddress);
817         if (BindAddress != NULL)
818         {
819             HeapFree(GlobalHeap, 0, BindAddress);
820         }
821         return SOCKET_ERROR;
822     }
823 
824     /* Set up Address in TDI Format */
825     RemoteAddress->TAAddressCount = 1;
826     RemoteAddress->Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family);
827     RtlCopyMemory(&RemoteAddress->Address[0].AddressType, SocketAddress, SocketAddressLength);
828 
829     /* Set up Structure */
830     SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
831     SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0;
832     SendInfo.BufferCount = dwBufferCount;
833     SendInfo.TdiConnection.RemoteAddress = RemoteAddress;
834     SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength;
835 
836     /* Verify if we should use APC */
837     if (lpOverlapped == NULL)
838     {
839         /* Not using Overlapped structure, so use normal blocking on event */
840         APCContext = NULL;
841         APCFunction = NULL;
842         Event = SockEvent;
843         IOSB = &DummyIOSB;
844     }
845     else
846     {
847         /* Overlapped request for non overlapped opened socket */
848         if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0)
849         {
850             TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n");
851             return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent);
852         }
853         if (lpCompletionRoutine == NULL)
854         {
855             /* Using Overlapped Structure, but no Completion Routine, so no need for APC */
856             APCContext = lpOverlapped;
857             APCFunction = NULL;
858             Event = lpOverlapped->hEvent;
859         }
860         else
861         {
862             /* Using Overlapped Structure and a Completion Routine, so use an APC */
863             APCFunction = &AfdAPC; // should be a private io completion function inside us
864             APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT));
865             if (!APCContext)
866             {
867                 ERR("Not enough memory for APC Context\n");
868                 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent);
869             }
870             ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine;
871             ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped;
872             ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket;
873             SendInfo.AfdFlags |= AFD_SKIP_FIO;
874         }
875 
876         IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
877         SendInfo.AfdFlags |= AFD_OVERLAPPED;
878     }
879 
880     /* Send IOCTL */
881     Status = NtDeviceIoControlFile((HANDLE)Handle,
882                                    Event,
883                                    APCFunction,
884                                    APCContext,
885                                    IOSB,
886                                    IOCTL_AFD_SEND_DATAGRAM,
887                                    &SendInfo,
888                                    sizeof(SendInfo),
889                                    NULL,
890                                    0);
891 
892     /* Wait for completion of not overlapped */
893     if (Status == STATUS_PENDING && lpOverlapped == NULL)
894     {
895         /* BUGBUG, shouldn't wait infinitely for send... */
896         WaitForSingleObject(SockEvent, INFINITE);
897         Status = IOSB->Status;
898     }
899 
900     NtClose(SockEvent);
901     HeapFree(GlobalHeap, 0, RemoteAddress);
902     if (BindAddress != NULL)
903     {
904         HeapFree(GlobalHeap, 0, BindAddress);
905     }
906 
907     if (Status == STATUS_PENDING)
908     {
909         TRACE("Leaving (Pending)\n");
910         return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
911     }
912 
913     SockReenableAsyncSelectEvent(Socket, FD_WRITE);
914 
915     if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine)
916     {
917         lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0);
918         HeapFree(GlobalHeap, 0, (PVOID)APCContext);
919     }
920 
921     return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
922 }
923 
924 INT
925 WSPAPI
926 WSPRecvDisconnect(IN  SOCKET s,
927                   OUT LPWSABUF lpInboundDisconnectData,
928                   OUT LPINT lpErrno)
929 {
930     UNIMPLEMENTED;
931     return 0;
932 }
933 
934 
935 
936 INT
937 WSPAPI
938 WSPSendDisconnect(IN  SOCKET s,
939                   IN  LPWSABUF lpOutboundDisconnectData,
940                   OUT LPINT lpErrno)
941 {
942     UNIMPLEMENTED;
943     return 0;
944 }
945 
946 /* EOF */
947