[MSAFD] Move the default debug channel to msafd.h.
[reactos.git] / dll / win32 / msafd / misc / sndrcv.c
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, 1, 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, 1, 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, 1, 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, 1, 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 */