xref: /reactos/dll/win32/msafd/misc/sndrcv.c (revision 442f5dfa)
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
WSPAsyncSelect(IN SOCKET Handle,IN HWND hWnd,IN UINT wMsg,IN LONG lEvent,OUT LPINT lpErrno)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
WSPGetOverlappedResult(IN SOCKET Handle,IN LPWSAOVERLAPPED lpOverlapped,OUT LPDWORD lpdwBytes,IN BOOL fWait,OUT LPDWORD lpdwFlags,OUT LPINT lpErrno)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
AfdAPC(PVOID ApcContext,PIO_STATUS_BLOCK IoStatusBlock,ULONG Reserved)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
WSPRecv(SOCKET Handle,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRead,LPDWORD ReceiveFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,LPWSATHREADID lpThreadId,LPINT lpErrno)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
WSPRecvFrom(SOCKET Handle,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesRead,LPDWORD ReceiveFlags,struct sockaddr * SocketAddress,int * SocketAddressLength,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,LPWSATHREADID lpThreadId,LPINT lpErrno)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
WSPSend(SOCKET Handle,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD iFlags,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,LPWSATHREADID lpThreadId,LPINT lpErrno)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
WSPSendTo(SOCKET Handle,LPWSABUF lpBuffers,DWORD dwBufferCount,LPDWORD lpNumberOfBytesSent,DWORD iFlags,const struct sockaddr * SocketAddress,int SocketAddressLength,LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,LPWSATHREADID lpThreadId,LPINT lpErrno)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
WSPRecvDisconnect(IN SOCKET s,OUT LPWSABUF lpInboundDisconnectData,OUT LPINT lpErrno)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
WSPSendDisconnect(IN SOCKET s,IN LPWSABUF lpOutboundDisconnectData,OUT LPINT lpErrno)938 WSPSendDisconnect(IN  SOCKET s,
939                   IN  LPWSABUF lpOutboundDisconnectData,
940                   OUT LPINT lpErrno)
941 {
942     UNIMPLEMENTED;
943     return 0;
944 }
945 
946 /* EOF */
947