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