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