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