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