Synchronize with trunk revision 59781.
[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: 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
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);
46 Socket->SharedData.NonBlocking = TRUE;
47
48 /* Deactive 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 int
95 WSPAPI
96 WSPRecv(SOCKET Handle,
97 LPWSABUF lpBuffers,
98 DWORD dwBufferCount,
99 LPDWORD lpNumberOfBytesRead,
100 LPDWORD ReceiveFlags,
101 LPWSAOVERLAPPED lpOverlapped,
102 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
103 LPWSATHREADID lpThreadId,
104 LPINT lpErrno)
105 {
106 PIO_STATUS_BLOCK IOSB;
107 IO_STATUS_BLOCK DummyIOSB;
108 AFD_RECV_INFO RecvInfo;
109 NTSTATUS Status;
110 PVOID APCContext;
111 PVOID APCFunction;
112 HANDLE Event = NULL;
113 HANDLE SockEvent;
114 PSOCKET_INFORMATION Socket;
115
116 AFD_DbgPrint(MID_TRACE,("Called (%x)\n", Handle));
117
118 /* Get the Socket Structure associate to this Socket*/
119 Socket = GetSocketStructure(Handle);
120 if (!Socket)
121 {
122 *lpErrno = WSAENOTSOCK;
123 return SOCKET_ERROR;
124 }
125
126 Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
127 NULL, 1, FALSE );
128
129 if( !NT_SUCCESS(Status) )
130 return -1;
131
132 /* Set up the Receive Structure */
133 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
134 RecvInfo.BufferCount = dwBufferCount;
135 RecvInfo.TdiFlags = 0;
136 RecvInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
137
138 /* Set the TDI Flags */
139 if (*ReceiveFlags == 0)
140 {
141 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
142 }
143 else
144 {
145 if (*ReceiveFlags & MSG_OOB)
146 {
147 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
148 }
149
150 if (*ReceiveFlags & MSG_PEEK)
151 {
152 RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
153 }
154
155 if (*ReceiveFlags & MSG_PARTIAL)
156 {
157 RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
158 }
159 }
160
161 /* Verifiy if we should use APC */
162
163 if (lpOverlapped == NULL)
164 {
165 /* Not using Overlapped structure, so use normal blocking on event */
166 APCContext = NULL;
167 APCFunction = NULL;
168 Event = SockEvent;
169 IOSB = &DummyIOSB;
170 }
171 else
172 {
173 if (lpCompletionRoutine == NULL)
174 {
175 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
176 APCContext = lpOverlapped;
177 APCFunction = NULL;
178 Event = lpOverlapped->hEvent;
179 }
180 else
181 {
182 /* Using Overlapped Structure and a Completition Routine, so use an APC */
183 APCFunction = NULL; // should be a private io completition function inside us
184 APCContext = lpCompletionRoutine;
185 RecvInfo.AfdFlags |= AFD_SKIP_FIO;
186 }
187
188 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
189 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
190 }
191
192 IOSB->Status = STATUS_PENDING;
193
194 /* Send IOCTL */
195 Status = NtDeviceIoControlFile((HANDLE)Handle,
196 Event,
197 APCFunction,
198 APCContext,
199 IOSB,
200 IOCTL_AFD_RECV,
201 &RecvInfo,
202 sizeof(RecvInfo),
203 NULL,
204 0);
205
206 /* Wait for completition of not overlapped */
207 if (Status == STATUS_PENDING && lpOverlapped == NULL)
208 {
209 /* It's up to the protocol to time out recv. We must wait
210 * until the protocol decides it's had enough.
211 */
212 WaitForSingleObject(SockEvent, INFINITE);
213 Status = IOSB->Status;
214 }
215
216 NtClose( SockEvent );
217
218 AFD_DbgPrint(MID_TRACE,("Status %x Information %d\n", Status, IOSB->Information));
219
220 /* Return the Flags */
221 *ReceiveFlags = 0;
222
223 switch (Status)
224 {
225 case STATUS_RECEIVE_EXPEDITED:
226 *ReceiveFlags = MSG_OOB;
227 break;
228 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
229 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
230 break;
231 case STATUS_RECEIVE_PARTIAL:
232 *ReceiveFlags = MSG_PARTIAL;
233 break;
234 }
235
236 /* Re-enable Async Event */
237 if (*ReceiveFlags & MSG_OOB)
238 {
239 SockReenableAsyncSelectEvent(Socket, FD_OOB);
240 }
241 else
242 {
243 SockReenableAsyncSelectEvent(Socket, FD_READ);
244 }
245
246 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
247 }
248
249 int
250 WSPAPI
251 WSPRecvFrom(SOCKET Handle,
252 LPWSABUF lpBuffers,
253 DWORD dwBufferCount,
254 LPDWORD lpNumberOfBytesRead,
255 LPDWORD ReceiveFlags,
256 struct sockaddr *SocketAddress,
257 int *SocketAddressLength,
258 LPWSAOVERLAPPED lpOverlapped,
259 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
260 LPWSATHREADID lpThreadId,
261 LPINT lpErrno )
262 {
263 PIO_STATUS_BLOCK IOSB;
264 IO_STATUS_BLOCK DummyIOSB;
265 AFD_RECV_INFO_UDP RecvInfo;
266 NTSTATUS Status;
267 PVOID APCContext;
268 PVOID APCFunction;
269 HANDLE Event = NULL;
270 HANDLE SockEvent;
271 PSOCKET_INFORMATION Socket;
272
273 /* Get the Socket Structure associate to this Socket*/
274 Socket = GetSocketStructure(Handle);
275 if (!Socket)
276 {
277 *lpErrno = WSAENOTSOCK;
278 return SOCKET_ERROR;
279 }
280
281 if (!(Socket->SharedData.ServiceFlags1 & XP1_CONNECTIONLESS))
282 {
283 /* Call WSPRecv for a non-datagram socket */
284 return WSPRecv(Handle,
285 lpBuffers,
286 dwBufferCount,
287 lpNumberOfBytesRead,
288 ReceiveFlags,
289 lpOverlapped,
290 lpCompletionRoutine,
291 lpThreadId,
292 lpErrno);
293 }
294
295 Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
296 NULL, 1, FALSE );
297
298 if( !NT_SUCCESS(Status) )
299 return -1;
300
301 /* Set up the Receive Structure */
302 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
303 RecvInfo.BufferCount = dwBufferCount;
304 RecvInfo.TdiFlags = 0;
305 RecvInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
306 RecvInfo.AddressLength = SocketAddressLength;
307 RecvInfo.Address = SocketAddress;
308
309 /* Set the TDI Flags */
310 if (*ReceiveFlags == 0)
311 {
312 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
313 }
314 else
315 {
316 if (*ReceiveFlags & MSG_OOB)
317 {
318 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
319 }
320
321 if (*ReceiveFlags & MSG_PEEK)
322 {
323 RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
324 }
325
326 if (*ReceiveFlags & MSG_PARTIAL)
327 {
328 RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
329 }
330 }
331
332 /* Verifiy if we should use APC */
333
334 if (lpOverlapped == NULL)
335 {
336 /* Not using Overlapped structure, so use normal blocking on event */
337 APCContext = NULL;
338 APCFunction = NULL;
339 Event = SockEvent;
340 IOSB = &DummyIOSB;
341 }
342 else
343 {
344 if (lpCompletionRoutine == NULL)
345 {
346 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
347 APCContext = lpOverlapped;
348 APCFunction = NULL;
349 Event = lpOverlapped->hEvent;
350 }
351 else
352 {
353 /* Using Overlapped Structure and a Completition Routine, so use an APC */
354 APCFunction = NULL; // should be a private io completition function inside us
355 APCContext = lpCompletionRoutine;
356 RecvInfo.AfdFlags |= AFD_SKIP_FIO;
357 }
358
359 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
360 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
361 }
362
363 IOSB->Status = STATUS_PENDING;
364
365 /* Send IOCTL */
366 Status = NtDeviceIoControlFile((HANDLE)Handle,
367 Event,
368 APCFunction,
369 APCContext,
370 IOSB,
371 IOCTL_AFD_RECV_DATAGRAM,
372 &RecvInfo,
373 sizeof(RecvInfo),
374 NULL,
375 0);
376
377 /* Wait for completition of not overlapped */
378 if (Status == STATUS_PENDING && lpOverlapped == NULL)
379 {
380 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infintely for receive...
381 Status = IOSB->Status;
382 }
383
384 NtClose( SockEvent );
385
386 /* Return the Flags */
387 *ReceiveFlags = 0;
388
389 switch (Status)
390 {
391 case STATUS_RECEIVE_EXPEDITED: *ReceiveFlags = MSG_OOB;
392 break;
393 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
394 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
395 break;
396 case STATUS_RECEIVE_PARTIAL:
397 *ReceiveFlags = MSG_PARTIAL;
398 break;
399 }
400
401 /* Re-enable Async Event */
402 if (*ReceiveFlags & MSG_OOB)
403 {
404 SockReenableAsyncSelectEvent(Socket, FD_OOB);
405 }
406 else
407 {
408 SockReenableAsyncSelectEvent(Socket, FD_READ);
409 }
410
411 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
412 }
413
414
415 int
416 WSPAPI
417 WSPSend(SOCKET Handle,
418 LPWSABUF lpBuffers,
419 DWORD dwBufferCount,
420 LPDWORD lpNumberOfBytesSent,
421 DWORD iFlags,
422 LPWSAOVERLAPPED lpOverlapped,
423 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
424 LPWSATHREADID lpThreadId,
425 LPINT lpErrno)
426 {
427 PIO_STATUS_BLOCK IOSB;
428 IO_STATUS_BLOCK DummyIOSB;
429 AFD_SEND_INFO SendInfo;
430 NTSTATUS Status;
431 PVOID APCContext;
432 PVOID APCFunction;
433 HANDLE Event = NULL;
434 HANDLE SockEvent;
435 PSOCKET_INFORMATION Socket;
436
437 /* Get the Socket Structure associate to this Socket*/
438 Socket = GetSocketStructure(Handle);
439 if (!Socket)
440 {
441 *lpErrno = WSAENOTSOCK;
442 return SOCKET_ERROR;
443 }
444
445 Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS,
446 NULL, 1, FALSE );
447
448 if( !NT_SUCCESS(Status) )
449 return -1;
450
451 AFD_DbgPrint(MID_TRACE,("Called\n"));
452
453 /* Set up the Send Structure */
454 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
455 SendInfo.BufferCount = dwBufferCount;
456 SendInfo.TdiFlags = 0;
457 SendInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
458
459 /* Set the TDI Flags */
460 if (iFlags)
461 {
462 if (iFlags & MSG_OOB)
463 {
464 SendInfo.TdiFlags |= TDI_SEND_EXPEDITED;
465 }
466 if (iFlags & MSG_PARTIAL)
467 {
468 SendInfo.TdiFlags |= TDI_SEND_PARTIAL;
469 }
470 }
471
472 /* Verifiy if we should use APC */
473 if (lpOverlapped == NULL)
474 {
475 /* Not using Overlapped structure, so use normal blocking on event */
476 APCContext = NULL;
477 APCFunction = NULL;
478 Event = SockEvent;
479 IOSB = &DummyIOSB;
480 }
481 else
482 {
483 if (lpCompletionRoutine == NULL)
484 {
485 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
486 APCContext = lpOverlapped;
487 APCFunction = NULL;
488 Event = lpOverlapped->hEvent;
489 }
490 else
491 {
492 /* Using Overlapped Structure and a Completition Routine, so use an APC */
493 APCFunction = NULL; // should be a private io completition function inside us
494 APCContext = lpCompletionRoutine;
495 SendInfo.AfdFlags |= AFD_SKIP_FIO;
496 }
497
498 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
499 SendInfo.AfdFlags |= AFD_OVERLAPPED;
500 }
501
502 IOSB->Status = STATUS_PENDING;
503
504 /* Send IOCTL */
505 Status = NtDeviceIoControlFile((HANDLE)Handle,
506 Event,
507 APCFunction,
508 APCContext,
509 IOSB,
510 IOCTL_AFD_SEND,
511 &SendInfo,
512 sizeof(SendInfo),
513 NULL,
514 0);
515
516 /* Wait for completition of not overlapped */
517 if (Status == STATUS_PENDING && lpOverlapped == NULL)
518 {
519 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infintely for send...
520 Status = IOSB->Status;
521 }
522
523 NtClose( SockEvent );
524
525 if (Status == STATUS_PENDING)
526 {
527 AFD_DbgPrint(MID_TRACE,("Leaving (Pending)\n"));
528 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
529 }
530
531 /* Re-enable Async Event */
532 SockReenableAsyncSelectEvent(Socket, FD_WRITE);
533
534 AFD_DbgPrint(MID_TRACE,("Leaving (Success, %d)\n", IOSB->Information));
535
536 return MsafdReturnWithErrno( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent );
537 }
538
539 int
540 WSPAPI
541 WSPSendTo(SOCKET Handle,
542 LPWSABUF lpBuffers,
543 DWORD dwBufferCount,
544 LPDWORD lpNumberOfBytesSent,
545 DWORD iFlags,
546 const struct sockaddr *SocketAddress,
547 int SocketAddressLength,
548 LPWSAOVERLAPPED lpOverlapped,
549 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
550 LPWSATHREADID lpThreadId,
551 LPINT lpErrno)
552 {
553 PIO_STATUS_BLOCK IOSB;
554 IO_STATUS_BLOCK DummyIOSB;
555 AFD_SEND_INFO_UDP SendInfo;
556 NTSTATUS Status;
557 PVOID APCContext;
558 PVOID APCFunction;
559 HANDLE Event = NULL;
560 PTRANSPORT_ADDRESS RemoteAddress;
561 PSOCKADDR BindAddress = NULL;
562 INT BindAddressLength;
563 HANDLE SockEvent;
564 PSOCKET_INFORMATION Socket;
565
566 /* Get the Socket Structure associate to this Socket */
567 Socket = GetSocketStructure(Handle);
568 if (!Socket)
569 {
570 *lpErrno = WSAENOTSOCK;
571 return SOCKET_ERROR;
572 }
573
574 if (!(Socket->SharedData.ServiceFlags1 & XP1_CONNECTIONLESS))
575 {
576 /* Use WSPSend for connection-oriented sockets */
577 return WSPSend(Handle,
578 lpBuffers,
579 dwBufferCount,
580 lpNumberOfBytesSent,
581 iFlags,
582 lpOverlapped,
583 lpCompletionRoutine,
584 lpThreadId,
585 lpErrno);
586 }
587
588 /* Bind us First */
589 if (Socket->SharedData.State == SocketOpen)
590 {
591 /* Get the Wildcard Address */
592 BindAddressLength = Socket->HelperData->MaxWSAddressLength;
593 BindAddress = HeapAlloc(GlobalHeap, 0, BindAddressLength);
594 if (!BindAddress)
595 {
596 MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
597 return INVALID_SOCKET;
598 }
599
600 Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext,
601 BindAddress,
602 &BindAddressLength);
603 /* Bind it */
604 if (WSPBind(Handle, BindAddress, BindAddressLength, lpErrno) == SOCKET_ERROR)
605 return SOCKET_ERROR;
606 }
607
608 RemoteAddress = HeapAlloc(GlobalHeap, 0, 0x6 + SocketAddressLength);
609 if (!RemoteAddress)
610 {
611 if (BindAddress != NULL)
612 {
613 HeapFree(GlobalHeap, 0, BindAddress);
614 }
615 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
616 }
617
618 Status = NtCreateEvent(&SockEvent,
619 EVENT_ALL_ACCESS,
620 NULL, 1, FALSE);
621
622 if (!NT_SUCCESS(Status))
623 {
624 HeapFree(GlobalHeap, 0, RemoteAddress);
625 if (BindAddress != NULL)
626 {
627 HeapFree(GlobalHeap, 0, BindAddress);
628 }
629 return SOCKET_ERROR;
630 }
631
632 /* Set up Address in TDI Format */
633 RemoteAddress->TAAddressCount = 1;
634 RemoteAddress->Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family);
635 RtlCopyMemory(&RemoteAddress->Address[0].AddressType, SocketAddress, SocketAddressLength);
636
637 /* Set up Structure */
638 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
639 SendInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
640 SendInfo.BufferCount = dwBufferCount;
641 SendInfo.TdiConnection.RemoteAddress = RemoteAddress;
642 SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength;
643
644 /* Verifiy if we should use APC */
645 if (lpOverlapped == NULL)
646 {
647 /* Not using Overlapped structure, so use normal blocking on event */
648 APCContext = NULL;
649 APCFunction = NULL;
650 Event = SockEvent;
651 IOSB = &DummyIOSB;
652 }
653 else
654 {
655 if (lpCompletionRoutine == NULL)
656 {
657 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
658 APCContext = lpOverlapped;
659 APCFunction = NULL;
660 Event = lpOverlapped->hEvent;
661 }
662 else
663 {
664 /* Using Overlapped Structure and a Completition Routine, so use an APC */
665 /* Should be a private io completition function inside us */
666 APCFunction = NULL;
667 APCContext = lpCompletionRoutine;
668 SendInfo.AfdFlags |= AFD_SKIP_FIO;
669 }
670
671 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
672 SendInfo.AfdFlags |= AFD_OVERLAPPED;
673 }
674
675 /* Send IOCTL */
676 Status = NtDeviceIoControlFile((HANDLE)Handle,
677 Event,
678 APCFunction,
679 APCContext,
680 IOSB,
681 IOCTL_AFD_SEND_DATAGRAM,
682 &SendInfo,
683 sizeof(SendInfo),
684 NULL,
685 0);
686
687 /* Wait for completition of not overlapped */
688 if (Status == STATUS_PENDING && lpOverlapped == NULL)
689 {
690 /* BUGBUG, shouldn't wait infintely for send... */
691 WaitForSingleObject(SockEvent, INFINITE);
692 Status = IOSB->Status;
693 }
694
695 NtClose(SockEvent);
696 HeapFree(GlobalHeap, 0, RemoteAddress);
697 if (BindAddress != NULL)
698 {
699 HeapFree(GlobalHeap, 0, BindAddress);
700 }
701
702 SockReenableAsyncSelectEvent(Socket, FD_WRITE);
703
704 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
705 }
706
707 INT
708 WSPAPI
709 WSPRecvDisconnect(IN SOCKET s,
710 OUT LPWSABUF lpInboundDisconnectData,
711 OUT LPINT lpErrno)
712 {
713 UNIMPLEMENTED
714 return 0;
715 }
716
717
718
719 INT
720 WSPAPI
721 WSPSendDisconnect(IN SOCKET s,
722 IN LPWSABUF lpOutboundDisconnectData,
723 OUT LPINT lpErrno)
724 {
725 UNIMPLEMENTED
726 return 0;
727 }
728
729 /* EOF */