Merge aicom-network-branch (without NDIS changes for now)
[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: 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 <debug.h>
16
17 INT
18 WSPAPI
19 WSPAsyncSelect(IN SOCKET Handle,
20 IN HWND hWnd,
21 IN UINT wMsg,
22 IN LONG lEvent,
23 OUT LPINT lpErrno)
24 {
25 PSOCKET_INFORMATION Socket = NULL;
26 PASYNC_DATA AsyncData;
27 NTSTATUS Status;
28 ULONG BlockMode;
29
30 /* Get the Socket Structure associated to this Socket */
31 Socket = GetSocketStructure(Handle);
32
33 /* Allocate the Async Data Structure to pass on to the Thread later */
34 AsyncData = HeapAlloc(GetProcessHeap(), 0, sizeof(*AsyncData));
35 if (!AsyncData)
36 {
37 MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
38 return INVALID_SOCKET;
39 }
40
41 /* Change the Socket to Non Blocking */
42 BlockMode = 1;
43 SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL);
44 Socket->SharedData.NonBlocking = TRUE;
45
46 /* Deactive WSPEventSelect */
47 if (Socket->SharedData.AsyncEvents)
48 {
49 WSPEventSelect(Handle, NULL, 0, NULL);
50 }
51
52 /* Create the Asynch Thread if Needed */
53 SockCreateOrReferenceAsyncThread();
54
55 /* Open a Handle to AFD's Async Helper */
56 SockGetAsyncSelectHelperAfdHandle();
57
58 /* Store Socket Data */
59 Socket->SharedData.hWnd = hWnd;
60 Socket->SharedData.wMsg = wMsg;
61 Socket->SharedData.AsyncEvents = lEvent;
62 Socket->SharedData.AsyncDisabledEvents = 0;
63 Socket->SharedData.SequenceNumber++;
64
65 /* Return if there are no more Events */
66 if ((Socket->SharedData.AsyncEvents & (~Socket->SharedData.AsyncDisabledEvents)) == 0)
67 {
68 HeapFree(GetProcessHeap(), 0, AsyncData);
69 return 0;
70 }
71
72 /* Set up the Async Data */
73 AsyncData->ParentSocket = Socket;
74 AsyncData->SequenceNumber = Socket->SharedData.SequenceNumber;
75
76 /* Begin Async Select by using I/O Completion */
77 Status = NtSetIoCompletion(SockAsyncCompletionPort,
78 (PVOID)&SockProcessQueuedAsyncSelect,
79 AsyncData,
80 0,
81 0);
82
83 /* Return */
84 return ERROR_SUCCESS;
85 }
86
87
88 int
89 WSPAPI
90 WSPRecv(SOCKET Handle,
91 LPWSABUF lpBuffers,
92 DWORD dwBufferCount,
93 LPDWORD lpNumberOfBytesRead,
94 LPDWORD ReceiveFlags,
95 LPWSAOVERLAPPED lpOverlapped,
96 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
97 LPWSATHREADID lpThreadId,
98 LPINT lpErrno)
99 {
100 PIO_STATUS_BLOCK IOSB;
101 IO_STATUS_BLOCK DummyIOSB;
102 AFD_RECV_INFO RecvInfo;
103 NTSTATUS Status;
104 PVOID APCContext;
105 PVOID APCFunction;
106 HANDLE Event = NULL;
107 HANDLE SockEvent;
108 PSOCKET_INFORMATION Socket;
109
110 AFD_DbgPrint(MID_TRACE,("Called (%x)\n", Handle));
111
112 /* Get the Socket Structure associate to this Socket*/
113 Socket = GetSocketStructure(Handle);
114
115 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
116 NULL, 1, FALSE );
117
118 if( !NT_SUCCESS(Status) )
119 return -1;
120
121 /* Set up the Receive Structure */
122 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
123 RecvInfo.BufferCount = dwBufferCount;
124 RecvInfo.TdiFlags = 0;
125 RecvInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
126
127 /* Set the TDI Flags */
128 if (*ReceiveFlags == 0)
129 {
130 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
131 }
132 else
133 {
134 if (*ReceiveFlags & MSG_OOB)
135 {
136 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
137 }
138
139 if (*ReceiveFlags & MSG_PEEK)
140 {
141 RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
142 }
143
144 if (*ReceiveFlags & MSG_PARTIAL)
145 {
146 RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
147 }
148 }
149
150 /* Verifiy if we should use APC */
151
152 if (lpOverlapped == NULL)
153 {
154 /* Not using Overlapped structure, so use normal blocking on event */
155 APCContext = NULL;
156 APCFunction = NULL;
157 Event = SockEvent;
158 IOSB = &DummyIOSB;
159 }
160 else
161 {
162 if (lpCompletionRoutine == NULL)
163 {
164 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
165 APCContext = lpOverlapped;
166 APCFunction = NULL;
167 Event = lpOverlapped->hEvent;
168 }
169 else
170 {
171 /* Using Overlapped Structure and a Completition Routine, so use an APC */
172 APCFunction = NULL; // should be a private io completition function inside us
173 APCContext = lpCompletionRoutine;
174 RecvInfo.AfdFlags |= AFD_SKIP_FIO;
175 }
176
177 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
178 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
179 }
180
181 IOSB->Status = STATUS_PENDING;
182
183 /* Send IOCTL */
184 Status = NtDeviceIoControlFile((HANDLE)Handle,
185 Event ? Event : SockEvent,
186 APCFunction,
187 APCContext,
188 IOSB,
189 IOCTL_AFD_RECV,
190 &RecvInfo,
191 sizeof(RecvInfo),
192 NULL,
193 0);
194
195 /* Wait for completition of not overlapped */
196 if (Status == STATUS_PENDING && lpOverlapped == NULL)
197 {
198 /* It's up to the protocol to time out recv. We must wait
199 * until the protocol decides it's had enough.
200 */
201 WaitForSingleObject(SockEvent, INFINITE);
202 Status = IOSB->Status;
203 }
204
205 NtClose( SockEvent );
206
207 AFD_DbgPrint(MID_TRACE,("Status %x Information %d\n", Status, IOSB->Information));
208
209 /* Return the Flags */
210 *ReceiveFlags = 0;
211
212 switch (Status)
213 {
214 case STATUS_RECEIVE_EXPEDITED:
215 *ReceiveFlags = MSG_OOB;
216 break;
217 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
218 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
219 break;
220 case STATUS_RECEIVE_PARTIAL:
221 *ReceiveFlags = MSG_PARTIAL;
222 break;
223 }
224
225 /* Re-enable Async Event */
226 if (*ReceiveFlags == MSG_OOB)
227 {
228 SockReenableAsyncSelectEvent(Socket, FD_OOB);
229 }
230 else
231 {
232 SockReenableAsyncSelectEvent(Socket, FD_READ);
233 }
234
235 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
236 }
237
238 int
239 WSPAPI
240 WSPRecvFrom(SOCKET Handle,
241 LPWSABUF lpBuffers,
242 DWORD dwBufferCount,
243 LPDWORD lpNumberOfBytesRead,
244 LPDWORD ReceiveFlags,
245 struct sockaddr *SocketAddress,
246 int *SocketAddressLength,
247 LPWSAOVERLAPPED lpOverlapped,
248 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
249 LPWSATHREADID lpThreadId,
250 LPINT lpErrno )
251 {
252 PIO_STATUS_BLOCK IOSB;
253 IO_STATUS_BLOCK DummyIOSB;
254 AFD_RECV_INFO_UDP RecvInfo;
255 NTSTATUS Status;
256 PVOID APCContext;
257 PVOID APCFunction;
258 HANDLE Event = NULL;
259 HANDLE SockEvent;
260 PSOCKET_INFORMATION Socket;
261
262 /* Get the Socket Structure associate to this Socket*/
263 Socket = GetSocketStructure(Handle);
264
265 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
266 NULL, 1, FALSE );
267
268 if( !NT_SUCCESS(Status) )
269 return -1;
270
271 /* Set up the Receive Structure */
272 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
273 RecvInfo.BufferCount = dwBufferCount;
274 RecvInfo.TdiFlags = 0;
275 RecvInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
276 RecvInfo.AddressLength = SocketAddressLength;
277 RecvInfo.Address = SocketAddress;
278
279 /* Set the TDI Flags */
280 if (*ReceiveFlags == 0)
281 {
282 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
283 }
284 else
285 {
286 if (*ReceiveFlags & MSG_OOB)
287 {
288 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
289 }
290
291 if (*ReceiveFlags & MSG_PEEK)
292 {
293 RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
294 }
295
296 if (*ReceiveFlags & MSG_PARTIAL)
297 {
298 RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
299 }
300 }
301
302 /* Verifiy if we should use APC */
303
304 if (lpOverlapped == NULL)
305 {
306 /* Not using Overlapped structure, so use normal blocking on event */
307 APCContext = NULL;
308 APCFunction = NULL;
309 Event = SockEvent;
310 IOSB = &DummyIOSB;
311 }
312 else
313 {
314 if (lpCompletionRoutine == NULL)
315 {
316 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
317 APCContext = lpOverlapped;
318 APCFunction = NULL;
319 Event = lpOverlapped->hEvent;
320 }
321 else
322 {
323 /* Using Overlapped Structure and a Completition Routine, so use an APC */
324 APCFunction = NULL; // should be a private io completition function inside us
325 APCContext = lpCompletionRoutine;
326 RecvInfo.AfdFlags |= AFD_SKIP_FIO;
327 }
328
329 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
330 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
331 }
332
333 IOSB->Status = STATUS_PENDING;
334
335 /* Send IOCTL */
336 Status = NtDeviceIoControlFile((HANDLE)Handle,
337 Event ? Event : SockEvent,
338 APCFunction,
339 APCContext,
340 IOSB,
341 IOCTL_AFD_RECV_DATAGRAM,
342 &RecvInfo,
343 sizeof(RecvInfo),
344 NULL,
345 0);
346
347 /* Wait for completition of not overlapped */
348 if (Status == STATUS_PENDING && lpOverlapped == NULL)
349 {
350 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infintely for receive...
351 Status = IOSB->Status;
352 }
353
354 NtClose( SockEvent );
355
356 /* Return the Flags */
357 *ReceiveFlags = 0;
358
359 switch (Status)
360 {
361 case STATUS_RECEIVE_EXPEDITED: *ReceiveFlags = MSG_OOB;
362 break;
363 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
364 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
365 break;
366 case STATUS_RECEIVE_PARTIAL:
367 *ReceiveFlags = MSG_PARTIAL;
368 break;
369 }
370
371 /* Re-enable Async Event */
372 SockReenableAsyncSelectEvent(Socket, FD_READ);
373
374 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
375 }
376
377
378 int
379 WSPAPI
380 WSPSend(SOCKET Handle,
381 LPWSABUF lpBuffers,
382 DWORD dwBufferCount,
383 LPDWORD lpNumberOfBytesSent,
384 DWORD iFlags,
385 LPWSAOVERLAPPED lpOverlapped,
386 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
387 LPWSATHREADID lpThreadId,
388 LPINT lpErrno)
389 {
390 PIO_STATUS_BLOCK IOSB;
391 IO_STATUS_BLOCK DummyIOSB;
392 AFD_SEND_INFO SendInfo;
393 NTSTATUS Status;
394 PVOID APCContext;
395 PVOID APCFunction;
396 HANDLE Event = NULL;
397 HANDLE SockEvent;
398 PSOCKET_INFORMATION Socket;
399
400 /* Get the Socket Structure associate to this Socket*/
401 Socket = GetSocketStructure(Handle);
402
403 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
404 NULL, 1, FALSE );
405
406 if( !NT_SUCCESS(Status) )
407 return -1;
408
409 AFD_DbgPrint(MID_TRACE,("Called\n"));
410
411 /* Set up the Send Structure */
412 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
413 SendInfo.BufferCount = dwBufferCount;
414 SendInfo.TdiFlags = 0;
415 SendInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
416
417 /* Set the TDI Flags */
418 if (iFlags)
419 {
420 if (iFlags & MSG_OOB)
421 {
422 SendInfo.TdiFlags |= TDI_SEND_EXPEDITED;
423 }
424 if (iFlags & MSG_PARTIAL)
425 {
426 SendInfo.TdiFlags |= TDI_SEND_PARTIAL;
427 }
428 }
429
430 /* Verifiy if we should use APC */
431 if (lpOverlapped == NULL)
432 {
433 /* Not using Overlapped structure, so use normal blocking on event */
434 APCContext = NULL;
435 APCFunction = NULL;
436 Event = SockEvent;
437 IOSB = &DummyIOSB;
438 }
439 else
440 {
441 if (lpCompletionRoutine == NULL)
442 {
443 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
444 APCContext = lpOverlapped;
445 APCFunction = NULL;
446 Event = lpOverlapped->hEvent;
447 }
448 else
449 {
450 /* Using Overlapped Structure and a Completition Routine, so use an APC */
451 APCFunction = NULL; // should be a private io completition function inside us
452 APCContext = lpCompletionRoutine;
453 SendInfo.AfdFlags |= AFD_SKIP_FIO;
454 }
455
456 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
457 SendInfo.AfdFlags |= AFD_OVERLAPPED;
458 }
459
460 IOSB->Status = STATUS_PENDING;
461
462 /* Send IOCTL */
463 Status = NtDeviceIoControlFile((HANDLE)Handle,
464 Event ? Event : SockEvent,
465 APCFunction,
466 APCContext,
467 IOSB,
468 IOCTL_AFD_SEND,
469 &SendInfo,
470 sizeof(SendInfo),
471 NULL,
472 0);
473
474 /* Wait for completition of not overlapped */
475 if (Status == STATUS_PENDING && lpOverlapped == NULL)
476 {
477 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infintely for send...
478 Status = IOSB->Status;
479 }
480
481 NtClose( SockEvent );
482
483 if (Status == STATUS_PENDING)
484 {
485 AFD_DbgPrint(MID_TRACE,("Leaving (Pending)\n"));
486 return WSA_IO_PENDING;
487 }
488
489 /* Re-enable Async Event */
490 SockReenableAsyncSelectEvent(Socket, FD_WRITE);
491
492 AFD_DbgPrint(MID_TRACE,("Leaving (Success, %d)\n", IOSB->Information));
493
494 return MsafdReturnWithErrno( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent );
495 }
496
497 int
498 WSPAPI
499 WSPSendTo(SOCKET Handle,
500 LPWSABUF lpBuffers,
501 DWORD dwBufferCount,
502 LPDWORD lpNumberOfBytesSent,
503 DWORD iFlags,
504 const struct sockaddr *SocketAddress,
505 int SocketAddressLength,
506 LPWSAOVERLAPPED lpOverlapped,
507 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
508 LPWSATHREADID lpThreadId,
509 LPINT lpErrno)
510 {
511 PIO_STATUS_BLOCK IOSB;
512 IO_STATUS_BLOCK DummyIOSB;
513 AFD_SEND_INFO_UDP SendInfo;
514 NTSTATUS Status;
515 PVOID APCContext;
516 PVOID APCFunction;
517 HANDLE Event = NULL;
518 PTRANSPORT_ADDRESS RemoteAddress;
519 PSOCKADDR BindAddress = NULL;
520 INT BindAddressLength;
521 HANDLE SockEvent;
522 PSOCKET_INFORMATION Socket;
523
524 /* Get the Socket Structure associate to this Socket */
525 Socket = GetSocketStructure(Handle);
526
527 /* Bind us First */
528 if (Socket->SharedData.State == SocketOpen)
529 {
530 /* Get the Wildcard Address */
531 BindAddressLength = Socket->HelperData->MaxWSAddressLength;
532 BindAddress = HeapAlloc(GlobalHeap, 0, BindAddressLength);
533 if (!BindAddress)
534 {
535 MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
536 return INVALID_SOCKET;
537 }
538
539 Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext,
540 BindAddress,
541 &BindAddressLength);
542 /* Bind it */
543 WSPBind(Handle, BindAddress, BindAddressLength, NULL);
544 }
545
546 RemoteAddress = HeapAlloc(GlobalHeap, 0, 0x6 + SocketAddressLength);
547 if (!RemoteAddress)
548 {
549 if (BindAddress != NULL)
550 {
551 HeapFree(GlobalHeap, 0, BindAddress);
552 }
553 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
554 }
555
556 Status = NtCreateEvent(&SockEvent,
557 GENERIC_READ | GENERIC_WRITE,
558 NULL, 1, FALSE);
559
560 if (!NT_SUCCESS(Status))
561 {
562 HeapFree(GlobalHeap, 0, RemoteAddress);
563 if (BindAddress != NULL)
564 {
565 HeapFree(GlobalHeap, 0, BindAddress);
566 }
567 return SOCKET_ERROR;
568 }
569
570 /* Set up Address in TDI Format */
571 RemoteAddress->TAAddressCount = 1;
572 RemoteAddress->Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family);
573 RtlCopyMemory(&RemoteAddress->Address[0].AddressType, SocketAddress, SocketAddressLength);
574
575 /* Set up Structure */
576 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
577 SendInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
578 SendInfo.BufferCount = dwBufferCount;
579 SendInfo.TdiConnection.RemoteAddress = RemoteAddress;
580 SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength;
581
582 /* Verifiy if we should use APC */
583 if (lpOverlapped == NULL)
584 {
585 /* Not using Overlapped structure, so use normal blocking on event */
586 APCContext = NULL;
587 APCFunction = NULL;
588 Event = SockEvent;
589 IOSB = &DummyIOSB;
590 }
591 else
592 {
593 if (lpCompletionRoutine == NULL)
594 {
595 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
596 APCContext = lpOverlapped;
597 APCFunction = NULL;
598 Event = lpOverlapped->hEvent;
599 }
600 else
601 {
602 /* Using Overlapped Structure and a Completition Routine, so use an APC */
603 /* Should be a private io completition function inside us */
604 APCFunction = NULL;
605 APCContext = lpCompletionRoutine;
606 SendInfo.AfdFlags |= AFD_SKIP_FIO;
607 }
608
609 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
610 SendInfo.AfdFlags |= AFD_OVERLAPPED;
611 }
612
613 /* Send IOCTL */
614 Status = NtDeviceIoControlFile((HANDLE)Handle,
615 Event ? Event : SockEvent,
616 APCFunction,
617 APCContext,
618 IOSB,
619 IOCTL_AFD_SEND_DATAGRAM,
620 &SendInfo,
621 sizeof(SendInfo),
622 NULL,
623 0);
624
625 /* Wait for completition of not overlapped */
626 if (Status == STATUS_PENDING && lpOverlapped == NULL)
627 {
628 /* BUGBUG, shouldn't wait infintely for send... */
629 WaitForSingleObject(SockEvent, INFINITE);
630 Status = IOSB->Status;
631 }
632
633 NtClose(SockEvent);
634 HeapFree(GlobalHeap, 0, RemoteAddress);
635 if (BindAddress != NULL)
636 {
637 HeapFree(GlobalHeap, 0, BindAddress);
638 }
639
640 if (Status == STATUS_PENDING)
641 return WSA_IO_PENDING;
642
643 /* Re-enable Async Event */
644 SockReenableAsyncSelectEvent(Socket, FD_WRITE);
645
646 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
647 }
648
649 INT
650 WSPAPI
651 WSPRecvDisconnect(IN SOCKET s,
652 OUT LPWSABUF lpInboundDisconnectData,
653 OUT LPINT lpErrno)
654 {
655 UNIMPLEMENTED
656 return 0;
657 }
658
659
660
661 INT
662 WSPAPI
663 WSPSendDisconnect(IN SOCKET s,
664 IN LPWSABUF lpOutboundDisconnectData,
665 OUT LPINT lpErrno)
666 {
667 UNIMPLEMENTED
668 return 0;
669 }
670
671 /* EOF */