7f27fd43eb013471c293206ac16a3851611c43c7
[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 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,
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,
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 MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
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 if (WSPBind(Handle, BindAddress, BindAddressLength, lpErrno) == SOCKET_ERROR)
544 return SOCKET_ERROR;
545 }
546
547 RemoteAddress = HeapAlloc(GlobalHeap, 0, 0x6 + SocketAddressLength);
548 if (!RemoteAddress)
549 {
550 if (BindAddress != NULL)
551 {
552 HeapFree(GlobalHeap, 0, BindAddress);
553 }
554 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL);
555 }
556
557 Status = NtCreateEvent(&SockEvent,
558 GENERIC_READ | GENERIC_WRITE,
559 NULL, 1, FALSE);
560
561 if (!NT_SUCCESS(Status))
562 {
563 HeapFree(GlobalHeap, 0, RemoteAddress);
564 if (BindAddress != NULL)
565 {
566 HeapFree(GlobalHeap, 0, BindAddress);
567 }
568 return SOCKET_ERROR;
569 }
570
571 /* Set up Address in TDI Format */
572 RemoteAddress->TAAddressCount = 1;
573 RemoteAddress->Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family);
574 RtlCopyMemory(&RemoteAddress->Address[0].AddressType, SocketAddress, SocketAddressLength);
575
576 /* Set up Structure */
577 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
578 SendInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
579 SendInfo.BufferCount = dwBufferCount;
580 SendInfo.TdiConnection.RemoteAddress = RemoteAddress;
581 SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength;
582
583 /* Verifiy if we should use APC */
584 if (lpOverlapped == NULL)
585 {
586 /* Not using Overlapped structure, so use normal blocking on event */
587 APCContext = NULL;
588 APCFunction = NULL;
589 Event = SockEvent;
590 IOSB = &DummyIOSB;
591 }
592 else
593 {
594 if (lpCompletionRoutine == NULL)
595 {
596 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
597 APCContext = lpOverlapped;
598 APCFunction = NULL;
599 Event = lpOverlapped->hEvent;
600 }
601 else
602 {
603 /* Using Overlapped Structure and a Completition Routine, so use an APC */
604 /* Should be a private io completition function inside us */
605 APCFunction = NULL;
606 APCContext = lpCompletionRoutine;
607 SendInfo.AfdFlags |= AFD_SKIP_FIO;
608 }
609
610 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
611 SendInfo.AfdFlags |= AFD_OVERLAPPED;
612 }
613
614 /* Send IOCTL */
615 Status = NtDeviceIoControlFile((HANDLE)Handle,
616 Event,
617 APCFunction,
618 APCContext,
619 IOSB,
620 IOCTL_AFD_SEND_DATAGRAM,
621 &SendInfo,
622 sizeof(SendInfo),
623 NULL,
624 0);
625
626 /* Wait for completition of not overlapped */
627 if (Status == STATUS_PENDING && lpOverlapped == NULL)
628 {
629 /* BUGBUG, shouldn't wait infintely for send... */
630 WaitForSingleObject(SockEvent, INFINITE);
631 Status = IOSB->Status;
632 }
633
634 NtClose(SockEvent);
635 HeapFree(GlobalHeap, 0, RemoteAddress);
636 if (BindAddress != NULL)
637 {
638 HeapFree(GlobalHeap, 0, BindAddress);
639 }
640
641 if (Status != STATUS_PENDING)
642 SockReenableAsyncSelectEvent(Socket, FD_WRITE);
643
644 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent);
645 }
646
647 INT
648 WSPAPI
649 WSPRecvDisconnect(IN SOCKET s,
650 OUT LPWSABUF lpInboundDisconnectData,
651 OUT LPINT lpErrno)
652 {
653 UNIMPLEMENTED
654 return 0;
655 }
656
657
658
659 INT
660 WSPAPI
661 WSPSendDisconnect(IN SOCKET s,
662 IN LPWSABUF lpOutboundDisconnectData,
663 OUT LPINT lpErrno)
664 {
665 UNIMPLEMENTED
666 return 0;
667 }
668
669 /* EOF */