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