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