[MSAFD]
[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,
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 if (Status == STATUS_PENDING)
213 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead);
214
215 switch (Status)
216 {
217 case STATUS_RECEIVE_EXPEDITED:
218 *ReceiveFlags = MSG_OOB;
219 break;
220 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
221 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
222 break;
223 case STATUS_RECEIVE_PARTIAL:
224 *ReceiveFlags = MSG_PARTIAL;
225 break;
226 }
227
228 /* Re-enable Async Event */
229 if (*ReceiveFlags & MSG_OOB)
230 {
231 SockReenableAsyncSelectEvent(Socket, FD_OOB);
232 }
233 else
234 {
235 SockReenableAsyncSelectEvent(Socket, FD_READ);
236 }
237
238 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
239 }
240
241 int
242 WSPAPI
243 WSPRecvFrom(SOCKET Handle,
244 LPWSABUF lpBuffers,
245 DWORD dwBufferCount,
246 LPDWORD lpNumberOfBytesRead,
247 LPDWORD ReceiveFlags,
248 struct sockaddr *SocketAddress,
249 int *SocketAddressLength,
250 LPWSAOVERLAPPED lpOverlapped,
251 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
252 LPWSATHREADID lpThreadId,
253 LPINT lpErrno )
254 {
255 PIO_STATUS_BLOCK IOSB;
256 IO_STATUS_BLOCK DummyIOSB;
257 AFD_RECV_INFO_UDP RecvInfo;
258 NTSTATUS Status;
259 PVOID APCContext;
260 PVOID APCFunction;
261 HANDLE Event = NULL;
262 HANDLE SockEvent;
263 PSOCKET_INFORMATION Socket;
264
265 /* Get the Socket Structure associate to this Socket*/
266 Socket = GetSocketStructure(Handle);
267
268 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
269 NULL, 1, FALSE );
270
271 if( !NT_SUCCESS(Status) )
272 return -1;
273
274 /* Set up the Receive Structure */
275 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
276 RecvInfo.BufferCount = dwBufferCount;
277 RecvInfo.TdiFlags = 0;
278 RecvInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
279 RecvInfo.AddressLength = SocketAddressLength;
280 RecvInfo.Address = SocketAddress;
281
282 /* Set the TDI Flags */
283 if (*ReceiveFlags == 0)
284 {
285 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
286 }
287 else
288 {
289 if (*ReceiveFlags & MSG_OOB)
290 {
291 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
292 }
293
294 if (*ReceiveFlags & MSG_PEEK)
295 {
296 RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
297 }
298
299 if (*ReceiveFlags & MSG_PARTIAL)
300 {
301 RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
302 }
303 }
304
305 /* Verifiy if we should use APC */
306
307 if (lpOverlapped == NULL)
308 {
309 /* Not using Overlapped structure, so use normal blocking on event */
310 APCContext = NULL;
311 APCFunction = NULL;
312 Event = SockEvent;
313 IOSB = &DummyIOSB;
314 }
315 else
316 {
317 if (lpCompletionRoutine == NULL)
318 {
319 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
320 APCContext = lpOverlapped;
321 APCFunction = NULL;
322 Event = lpOverlapped->hEvent;
323 }
324 else
325 {
326 /* Using Overlapped Structure and a Completition Routine, so use an APC */
327 APCFunction = NULL; // should be a private io completition function inside us
328 APCContext = lpCompletionRoutine;
329 RecvInfo.AfdFlags |= AFD_SKIP_FIO;
330 }
331
332 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
333 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
334 }
335
336 IOSB->Status = STATUS_PENDING;
337
338 /* Send IOCTL */
339 Status = NtDeviceIoControlFile((HANDLE)Handle,
340 Event,
341 APCFunction,
342 APCContext,
343 IOSB,
344 IOCTL_AFD_RECV_DATAGRAM,
345 &RecvInfo,
346 sizeof(RecvInfo),
347 NULL,
348 0);
349
350 /* Wait for completition of not overlapped */
351 if (Status == STATUS_PENDING && lpOverlapped == NULL)
352 {
353 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infintely for receive...
354 Status = IOSB->Status;
355 }
356
357 NtClose( SockEvent );
358
359 /* Return the Flags */
360 *ReceiveFlags = 0;
361
362 if (Status == STATUS_PENDING)
363 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead);
364
365 switch (Status)
366 {
367 case STATUS_RECEIVE_EXPEDITED: *ReceiveFlags = MSG_OOB;
368 break;
369 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
370 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
371 break;
372 case STATUS_RECEIVE_PARTIAL:
373 *ReceiveFlags = MSG_PARTIAL;
374 break;
375 }
376
377 /* Re-enable Async Event */
378 SockReenableAsyncSelectEvent(Socket, FD_READ);
379
380 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead );
381 }
382
383
384 int
385 WSPAPI
386 WSPSend(SOCKET Handle,
387 LPWSABUF lpBuffers,
388 DWORD dwBufferCount,
389 LPDWORD lpNumberOfBytesSent,
390 DWORD iFlags,
391 LPWSAOVERLAPPED lpOverlapped,
392 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
393 LPWSATHREADID lpThreadId,
394 LPINT lpErrno)
395 {
396 PIO_STATUS_BLOCK IOSB;
397 IO_STATUS_BLOCK DummyIOSB;
398 AFD_SEND_INFO SendInfo;
399 NTSTATUS Status;
400 PVOID APCContext;
401 PVOID APCFunction;
402 HANDLE Event = NULL;
403 HANDLE SockEvent;
404 PSOCKET_INFORMATION Socket;
405
406 /* Get the Socket Structure associate to this Socket*/
407 Socket = GetSocketStructure(Handle);
408
409 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
410 NULL, 1, FALSE );
411
412 if( !NT_SUCCESS(Status) )
413 return -1;
414
415 AFD_DbgPrint(MID_TRACE,("Called\n"));
416
417 /* Set up the Send Structure */
418 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
419 SendInfo.BufferCount = dwBufferCount;
420 SendInfo.TdiFlags = 0;
421 SendInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
422
423 /* Set the TDI Flags */
424 if (iFlags)
425 {
426 if (iFlags & MSG_OOB)
427 {
428 SendInfo.TdiFlags |= TDI_SEND_EXPEDITED;
429 }
430 if (iFlags & MSG_PARTIAL)
431 {
432 SendInfo.TdiFlags |= TDI_SEND_PARTIAL;
433 }
434 }
435
436 /* Verifiy if we should use APC */
437 if (lpOverlapped == NULL)
438 {
439 /* Not using Overlapped structure, so use normal blocking on event */
440 APCContext = NULL;
441 APCFunction = NULL;
442 Event = SockEvent;
443 IOSB = &DummyIOSB;
444 }
445 else
446 {
447 if (lpCompletionRoutine == NULL)
448 {
449 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
450 APCContext = lpOverlapped;
451 APCFunction = NULL;
452 Event = lpOverlapped->hEvent;
453 }
454 else
455 {
456 /* Using Overlapped Structure and a Completition Routine, so use an APC */
457 APCFunction = NULL; // should be a private io completition function inside us
458 APCContext = lpCompletionRoutine;
459 SendInfo.AfdFlags |= AFD_SKIP_FIO;
460 }
461
462 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
463 SendInfo.AfdFlags |= AFD_OVERLAPPED;
464 }
465
466 IOSB->Status = STATUS_PENDING;
467
468 /* Send IOCTL */
469 Status = NtDeviceIoControlFile((HANDLE)Handle,
470 Event,
471 APCFunction,
472 APCContext,
473 IOSB,
474 IOCTL_AFD_SEND,
475 &SendInfo,
476 sizeof(SendInfo),
477 NULL,
478 0);
479
480 /* Wait for completition of not overlapped */
481 if (Status == STATUS_PENDING && lpOverlapped == NULL)
482 {
483 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infintely for send...
484 Status = IOSB->Status;
485 }
486
487 NtClose( SockEvent );
488
489 if (Status == STATUS_PENDING)
490 {
491 AFD_DbgPrint(MID_TRACE,("Leaving (Pending)\n"));
492 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
493 }
494
495 /* Re-enable Async Event */
496 SockReenableAsyncSelectEvent(Socket, FD_WRITE);
497
498 AFD_DbgPrint(MID_TRACE,("Leaving (Success, %d)\n", IOSB->Information));
499
500 return MsafdReturnWithErrno( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent );
501 }
502
503 int
504 WSPAPI
505 WSPSendTo(SOCKET Handle,
506 LPWSABUF lpBuffers,
507 DWORD dwBufferCount,
508 LPDWORD lpNumberOfBytesSent,
509 DWORD iFlags,
510 const struct sockaddr *SocketAddress,
511 int SocketAddressLength,
512 LPWSAOVERLAPPED lpOverlapped,
513 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
514 LPWSATHREADID lpThreadId,
515 LPINT lpErrno)
516 {
517 PIO_STATUS_BLOCK IOSB;
518 IO_STATUS_BLOCK DummyIOSB;
519 AFD_SEND_INFO_UDP SendInfo;
520 NTSTATUS Status;
521 PVOID APCContext;
522 PVOID APCFunction;
523 HANDLE Event = NULL;
524 PTRANSPORT_ADDRESS RemoteAddress;
525 PSOCKADDR BindAddress = NULL;
526 INT BindAddressLength;
527 HANDLE SockEvent;
528 PSOCKET_INFORMATION Socket;
529
530 /* Get the Socket Structure associate to this Socket */
531 Socket = GetSocketStructure(Handle);
532
533 /* Bind us First */
534 if (Socket->SharedData.State == SocketOpen)
535 {
536 /* Get the Wildcard Address */
537 BindAddressLength = Socket->HelperData->MaxWSAddressLength;
538 BindAddress = HeapAlloc(GlobalHeap, 0, BindAddressLength);
539 if (!BindAddress)
540 {
541 MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
542 return INVALID_SOCKET;
543 }
544
545 Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext,
546 BindAddress,
547 &BindAddressLength);
548 /* Bind it */
549 if (WSPBind(Handle, BindAddress, BindAddressLength, lpErrno) == SOCKET_ERROR)
550 return SOCKET_ERROR;
551 }
552
553 RemoteAddress = HeapAlloc(GlobalHeap, 0, 0x6 + SocketAddressLength);
554 if (!RemoteAddress)
555 {
556 if (BindAddress != NULL)
557 {
558 HeapFree(GlobalHeap, 0, BindAddress);
559 }
560 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
561 }
562
563 Status = NtCreateEvent(&SockEvent,
564 GENERIC_READ | GENERIC_WRITE,
565 NULL, 1, FALSE);
566
567 if (!NT_SUCCESS(Status))
568 {
569 HeapFree(GlobalHeap, 0, RemoteAddress);
570 if (BindAddress != NULL)
571 {
572 HeapFree(GlobalHeap, 0, BindAddress);
573 }
574 return SOCKET_ERROR;
575 }
576
577 /* Set up Address in TDI Format */
578 RemoteAddress->TAAddressCount = 1;
579 RemoteAddress->Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family);
580 RtlCopyMemory(&RemoteAddress->Address[0].AddressType, SocketAddress, SocketAddressLength);
581
582 /* Set up Structure */
583 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
584 SendInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
585 SendInfo.BufferCount = dwBufferCount;
586 SendInfo.TdiConnection.RemoteAddress = RemoteAddress;
587 SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength;
588
589 /* Verifiy if we should use APC */
590 if (lpOverlapped == NULL)
591 {
592 /* Not using Overlapped structure, so use normal blocking on event */
593 APCContext = NULL;
594 APCFunction = NULL;
595 Event = SockEvent;
596 IOSB = &DummyIOSB;
597 }
598 else
599 {
600 if (lpCompletionRoutine == NULL)
601 {
602 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
603 APCContext = lpOverlapped;
604 APCFunction = NULL;
605 Event = lpOverlapped->hEvent;
606 }
607 else
608 {
609 /* Using Overlapped Structure and a Completition Routine, so use an APC */
610 /* Should be a private io completition function inside us */
611 APCFunction = NULL;
612 APCContext = lpCompletionRoutine;
613 SendInfo.AfdFlags |= AFD_SKIP_FIO;
614 }
615
616 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
617 SendInfo.AfdFlags |= AFD_OVERLAPPED;
618 }
619
620 /* Send IOCTL */
621 Status = NtDeviceIoControlFile((HANDLE)Handle,
622 Event,
623 APCFunction,
624 APCContext,
625 IOSB,
626 IOCTL_AFD_SEND_DATAGRAM,
627 &SendInfo,
628 sizeof(SendInfo),
629 NULL,
630 0);
631
632 /* Wait for completition of not overlapped */
633 if (Status == STATUS_PENDING && lpOverlapped == NULL)
634 {
635 /* BUGBUG, shouldn't wait infintely for send... */
636 WaitForSingleObject(SockEvent, INFINITE);
637 Status = IOSB->Status;
638 }
639
640 NtClose(SockEvent);
641 HeapFree(GlobalHeap, 0, RemoteAddress);
642 if (BindAddress != NULL)
643 {
644 HeapFree(GlobalHeap, 0, BindAddress);
645 }
646
647 if (Status != STATUS_PENDING)
648 SockReenableAsyncSelectEvent(Socket, FD_WRITE);
649
650 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
651 }
652
653 INT
654 WSPAPI
655 WSPRecvDisconnect(IN SOCKET s,
656 OUT LPWSABUF lpInboundDisconnectData,
657 OUT LPINT lpErrno)
658 {
659 UNIMPLEMENTED
660 return 0;
661 }
662
663
664
665 INT
666 WSPAPI
667 WSPSendDisconnect(IN SOCKET s,
668 IN LPWSABUF lpOutboundDisconnectData,
669 OUT LPINT lpErrno)
670 {
671 UNIMPLEMENTED
672 return 0;
673 }
674
675 /* EOF */