- New winsock (part 2 of x)
[reactos.git] / dll / win32 / mswsock / msafd / recv.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Winsock 2 SPI
4 * FILE: lib/mswsock/lib/init.c
5 * PURPOSE: DLL Initialization
6 */
7
8 /* INCLUDES ******************************************************************/
9 #include "msafd.h"
10
11 /* DATA **********************************************************************/
12
13 /* FUNCTIONS *****************************************************************/
14
15 INT
16 WSPAPI
17 WSPRecv(SOCKET Handle,
18 LPWSABUF lpBuffers,
19 DWORD dwBufferCount,
20 LPDWORD lpNumberOfBytesRead,
21 LPDWORD ReceiveFlags,
22 LPWSAOVERLAPPED lpOverlapped,
23 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
24 LPWSATHREADID lpThreadId,
25 LPINT lpErrno)
26 {
27 PIO_STATUS_BLOCK IoStatusBlock;
28 IO_STATUS_BLOCK DummyIoStatusBlock;
29 AFD_RECV_INFO RecvInfo;
30 NTSTATUS Status;
31 PVOID APCContext;
32 PVOID ApcFunction;
33 HANDLE Event;
34 PWINSOCK_TEB_DATA ThreadData;
35 PSOCKET_INFORMATION Socket;
36 INT ErrorCode;
37 BOOLEAN ReturnValue;
38
39 /* Enter prolog */
40 ErrorCode = SockEnterApiFast(&ThreadData);
41 if (ErrorCode != NO_ERROR)
42 {
43 /* Fail */
44 *lpErrno = ErrorCode;
45 return SOCKET_ERROR;
46 }
47
48 /* Set up the Receive Structure */
49 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
50 RecvInfo.BufferCount = dwBufferCount;
51 RecvInfo.TdiFlags = 0;
52 RecvInfo.AfdFlags = 0;
53
54 /* Set the TDI Flags */
55 if (!(*ReceiveFlags))
56 {
57 /* Use normal TDI Receive */
58 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
59 }
60 else
61 {
62 /* Check for valid flags */
63 if ((*ReceiveFlags & ~(MSG_OOB | MSG_PEEK | MSG_PARTIAL)))
64 {
65 /* Fail */
66 ErrorCode = WSAEOPNOTSUPP;
67 goto error;
68 }
69
70 /* Check if OOB is being used */
71 if (*ReceiveFlags & MSG_OOB)
72 {
73 /* Use Expedited Receive for OOB */
74 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
75 }
76 else
77 {
78 /* Use normal receive */
79 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
80 }
81
82 /* Use Peek Receive if enabled */
83 if (*ReceiveFlags & MSG_PEEK) RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
84
85 /* Use Partial Receive if enabled */
86 if (*ReceiveFlags & MSG_PARTIAL) RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
87 }
88
89 /* Verifiy if we should use APC */
90 if (!lpOverlapped)
91 {
92 /* Not using Overlapped structure, so use normal blocking on event */
93 APCContext = NULL;
94 ApcFunction = NULL;
95 Event = ThreadData->EventHandle;
96 IoStatusBlock = &DummyIoStatusBlock;
97 }
98 else
99 {
100 /* Using apc, check if we have a completion routine */
101 if (!lpCompletionRoutine)
102 {
103 /* No need for APC */
104 APCContext = lpOverlapped;
105 ApcFunction = NULL;
106 Event = lpOverlapped->hEvent;
107 }
108 else
109 {
110 /* Use APC */
111 ApcFunction = SockIoCompletion;
112 APCContext = lpCompletionRoutine;
113 Event = NULL;
114
115 /* Skip Fast I/O */
116 RecvInfo.AfdFlags = AFD_SKIP_FIO;
117 }
118
119 /* Use the overlapped's structure buffer for the I/O Status Block */
120 IoStatusBlock = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
121
122 /* Make this an overlapped I/O in AFD */
123 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
124 }
125
126 /* Set is as Pending for now */
127 IoStatusBlock->Status = STATUS_PENDING;
128
129 /* Send IOCTL */
130 Status = NtDeviceIoControlFile((HANDLE)Handle,
131 Event,
132 ApcFunction,
133 APCContext,
134 IoStatusBlock,
135 IOCTL_AFD_RECV,
136 &RecvInfo,
137 sizeof(RecvInfo),
138 NULL,
139 0);
140
141 /* Increase the pending APC Count if we're using an APC */
142 if (!NT_ERROR(Status) && ApcFunction)
143 {
144 ThreadData->PendingAPCs++;
145 InterlockedIncrement(&SockProcessPendingAPCCount);
146 }
147
148 /* Wait for completition if not overlapped */
149 if ((Status == STATUS_PENDING) && !(lpOverlapped))
150 {
151 /* Wait for completion */
152 ReturnValue = SockWaitForSingleObject(Event,
153 Handle,
154 MAYBE_BLOCKING_HOOK,
155 RECV_TIMEOUT);
156
157 /* Check if the wait was successful */
158 if (ReturnValue)
159 {
160 /* Get new status */
161 Status = IoStatusBlock->Status;
162 }
163 else
164 {
165 /* Cancel the I/O */
166 SockCancelIo(Handle);
167
168 /* Get new status and normalize */
169 Status = IoStatusBlock->Status;
170 if (Status == STATUS_CANCELLED) Status = STATUS_IO_TIMEOUT;
171 }
172 }
173
174 /* Return the Flags */
175 *ReceiveFlags = 0;
176 switch (Status)
177 {
178 /* Success */
179 case STATUS_SUCCESS:
180 break;
181
182 /* Pending I/O */
183 case STATUS_PENDING:
184 ErrorCode = WSA_IO_PENDING;
185 goto error;
186
187 /* Buffer Overflow */
188 case STATUS_BUFFER_OVERFLOW:
189 /* Check if this was overlapped */
190 if (lpOverlapped)
191 {
192 /* Return without bytes read */
193 ErrorCode = WSA_IO_PENDING;
194 goto error;
195 }
196
197 /* Return failure with bytes read */
198 ErrorCode = WSAEMSGSIZE;
199 break;
200
201 /* OOB Receive */
202 case STATUS_RECEIVE_EXPEDITED:
203 *ReceiveFlags = MSG_OOB;
204 break;
205
206 /* Partial OOB Receive */
207 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
208 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
209 break;
210
211 /* Parial Receive */
212 case STATUS_RECEIVE_PARTIAL:
213 *ReceiveFlags = MSG_PARTIAL;
214 break;
215
216 /* Other NT Error */
217 default:
218 if (!NT_SUCCESS(Status))
219 {
220 /* Fail */
221 ErrorCode = NtStatusToSocketError(Status);
222 goto error;
223 }
224 break;
225 }
226
227 /* Return the number of bytes read */
228 *lpNumberOfBytesRead = PtrToUlong(IoStatusBlock->Information);
229
230 error:
231
232 /* Check if async select was active */
233 if (SockAsyncSelectCalled)
234 {
235 /* Get the socket */
236 Socket = SockFindAndReferenceSocket(Handle, TRUE);
237 if (Socket)
238 {
239 /* Lock it */
240 EnterCriticalSection(&Socket->Lock);
241
242 /* Check which event to re-enable */
243 if (RecvInfo.TdiFlags & TDI_RECEIVE_EXPEDITED)
244 {
245 /* Re-enable the OOB event */
246 SockReenableAsyncSelectEvent(Socket, FD_OOB);
247 }
248 else
249 {
250 /* Re-enable the regular read event */
251 SockReenableAsyncSelectEvent(Socket, FD_READ);
252 }
253
254 /* Unlock and dereference socket */
255 LeaveCriticalSection(&Socket->Lock);
256 SockDereferenceSocket(Socket);
257 }
258 }
259
260 /* Check for error */
261 if (ErrorCode != NO_ERROR)
262 {
263 /* Fail */
264 *lpErrno = ErrorCode;
265 return SOCKET_ERROR;
266 }
267
268 /* Return success */
269 return NO_ERROR;
270 }
271
272 INT
273 WSPAPI
274 WSPRecvFrom(SOCKET Handle,
275 LPWSABUF lpBuffers,
276 DWORD dwBufferCount,
277 LPDWORD lpNumberOfBytesRead,
278 LPDWORD ReceiveFlags,
279 PSOCKADDR SocketAddress,
280 PINT SocketAddressLength,
281 LPWSAOVERLAPPED lpOverlapped,
282 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
283 LPWSATHREADID lpThreadId,
284 LPINT lpErrno)
285 {
286 PIO_STATUS_BLOCK IoStatusBlock;
287 IO_STATUS_BLOCK DummyIoStatusBlock;
288 AFD_RECV_INFO_UDP RecvInfo;
289 NTSTATUS Status;
290 PVOID APCContext;
291 PVOID ApcFunction;
292 HANDLE Event;
293 PWINSOCK_TEB_DATA ThreadData;
294 PSOCKET_INFORMATION Socket;
295 INT ErrorCode;
296 BOOLEAN ReturnValue;
297
298 /* Enter prolog */
299 ErrorCode = SockEnterApiFast(&ThreadData);
300 if (ErrorCode != NO_ERROR)
301 {
302 /* Fail */
303 *lpErrno = ErrorCode;
304 return SOCKET_ERROR;
305 }
306
307 /* Get the socket */
308 Socket = SockFindAndReferenceSocket(Handle, TRUE);
309 if (!Socket)
310 {
311 /* Fail */
312 ErrorCode = WSAENOTSOCK;
313 goto error;
314 }
315
316 /* Fail if the socket isn't bound */
317 if (Socket->SharedData.State == SocketOpen)
318 {
319 /* Fail */
320 ErrorCode = WSAEINVAL;
321 goto error;
322 }
323
324 /* If this is an unconnected or non datagram socket */
325 if (!(MSAFD_IS_DGRAM_SOCK(Socket)) ||
326 (!SocketAddress && !SocketAddressLength))
327 {
328 /* Call WSP Recv */
329 SockDereferenceSocket(Socket);
330 return WSPRecv(Handle,
331 lpBuffers,
332 dwBufferCount,
333 lpNumberOfBytesRead,
334 ReceiveFlags,
335 lpOverlapped,
336 lpCompletionRoutine,
337 lpThreadId,
338 lpErrno);
339 }
340
341 /* If receive shutdown is enabled, fail */
342 if (Socket->SharedData.ReceiveShutdown)
343 {
344 /* Fail */
345 ErrorCode = WSAESHUTDOWN;
346 goto error;
347 }
348
349 /* Check for valid Socket Address (Length) flags */
350 if (!(SocketAddress) ^ (!SocketAddressLength || !(*SocketAddressLength)))
351 {
352 /* Fail */
353 ErrorCode = WSAEFAULT;
354 goto error;
355 }
356
357 /* Check for valid flags */
358 if ((*ReceiveFlags & ~(MSG_PEEK | MSG_PARTIAL)))
359 {
360 /* Fail */
361 ErrorCode = WSAEOPNOTSUPP;
362 goto error;
363 }
364
365 /* Check that the length is respected */
366 if (SocketAddressLength &&
367 (*SocketAddressLength < Socket->HelperData->MinWSAddressLength))
368 {
369 /* Fail */
370 ErrorCode = WSAEFAULT;
371 goto error;
372 }
373
374 /* Set up the Receive Structure */
375 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
376 RecvInfo.BufferCount = dwBufferCount;
377 RecvInfo.TdiFlags = TDI_RECEIVE_NORMAL;
378 RecvInfo.AfdFlags = 0;
379 RecvInfo.Address = SocketAddress;
380 RecvInfo.AddressLength = SocketAddressLength;
381
382 /* Use Peek Receive if enabled */
383 if (*ReceiveFlags & MSG_PEEK) RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
384
385 /* Use Partial Receive if enabled */
386 if (*ReceiveFlags & MSG_PARTIAL) RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
387
388 /* Verifiy if we should use APC */
389 if (!lpOverlapped)
390 {
391 /* Not using Overlapped structure, so use normal blocking on event */
392 APCContext = NULL;
393 ApcFunction = NULL;
394 Event = ThreadData->EventHandle;
395 IoStatusBlock = &DummyIoStatusBlock;
396 }
397 else
398 {
399 /* Using apc, check if we have a completion routine */
400 if (!lpCompletionRoutine)
401 {
402 /* No need for APC */
403 APCContext = lpOverlapped;
404 ApcFunction = NULL;
405 Event = lpOverlapped->hEvent;
406 }
407 else
408 {
409 /* Use APC */
410 ApcFunction = SockIoCompletion;
411 APCContext = lpCompletionRoutine;
412 Event = NULL;
413
414 /* Skip Fast I/O */
415 RecvInfo.AfdFlags = AFD_SKIP_FIO;
416 }
417
418 /* Use the overlapped's structure buffer for the I/O Status Block */
419 IoStatusBlock = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
420
421 /* Make this an overlapped I/O in AFD */
422 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
423 }
424
425 /* Set is as Pending for now */
426 IoStatusBlock->Status = STATUS_PENDING;
427
428 /* Send IOCTL */
429 Status = NtDeviceIoControlFile(Socket->WshContext.Handle,
430 Event,
431 ApcFunction,
432 APCContext,
433 IoStatusBlock,
434 IOCTL_AFD_RECV_DATAGRAM,
435 &RecvInfo,
436 sizeof(RecvInfo),
437 NULL,
438 0);
439
440 /* Increase the pending APC Count if we're using an APC */
441 if (!NT_ERROR(Status) && ApcFunction)
442 {
443 ThreadData->PendingAPCs++;
444 InterlockedIncrement(&SockProcessPendingAPCCount);
445 }
446
447 /* Wait for completition if not overlapped */
448 if ((Status == STATUS_PENDING) && !(lpOverlapped))
449 {
450 /* Wait for completion */
451 ReturnValue = SockWaitForSingleObject(Event,
452 Handle,
453 MAYBE_BLOCKING_HOOK,
454 RECV_TIMEOUT);
455
456 /* Check if the wait was successful */
457 if (ReturnValue)
458 {
459 /* Get new status */
460 Status = IoStatusBlock->Status;
461 }
462 else
463 {
464 /* Cancel the I/O */
465 SockCancelIo(Handle);
466
467 /* Get new status and normalize */
468 Status = IoStatusBlock->Status;
469 if (Status == STATUS_CANCELLED) Status = STATUS_IO_TIMEOUT;
470 }
471 }
472
473 /* Return the Flags */
474 *ReceiveFlags = 0;
475 switch (Status)
476 {
477 /* Success */
478 case STATUS_SUCCESS:
479 break;
480
481 /* Pending I/O */
482 case STATUS_PENDING:
483 ErrorCode = WSA_IO_PENDING;
484 goto error;
485
486 /* Buffer Overflow */
487 case STATUS_BUFFER_OVERFLOW:
488 /* Check if this was overlapped */
489 if (lpOverlapped)
490 {
491 /* Return without bytes read */
492 ErrorCode = WSA_IO_PENDING;
493 goto error;
494 }
495
496 /* Return failure with bytes read */
497 ErrorCode = WSAEMSGSIZE;
498 break;
499
500 /* OOB Receive */
501 case STATUS_RECEIVE_EXPEDITED:
502 *ReceiveFlags = MSG_OOB;
503 break;
504
505 /* Partial OOB Receive */
506 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
507 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
508 break;
509
510 /* Parial Receive */
511 case STATUS_RECEIVE_PARTIAL:
512 *ReceiveFlags = MSG_PARTIAL;
513 break;
514
515 /* Other NT Error */
516 default:
517 if (!NT_SUCCESS(Status))
518 {
519 /* Fail */
520 ErrorCode = NtStatusToSocketError(Status);
521 goto error;
522 }
523 break;
524 }
525
526 /* Return the number of bytes read */
527 *lpNumberOfBytesRead = PtrToUlong(IoStatusBlock->Information);
528
529 error:
530
531 /* Check if we have a socket here */
532 if (Socket)
533 {
534 /* Check if async select was active */
535 if (SockAsyncSelectCalled)
536 {
537 /* Lock the socket */
538 EnterCriticalSection(&Socket->Lock);
539
540 /* Re-enable the regular read event */
541 SockReenableAsyncSelectEvent(Socket, FD_READ);
542
543 /* Unlock socket */
544 LeaveCriticalSection(&Socket->Lock);
545 }
546
547 /* Dereference it */
548 SockDereferenceSocket(Socket);
549 }
550
551 /* Check for error */
552 if (ErrorCode != NO_ERROR)
553 {
554 /* Fail */
555 *lpErrno = ErrorCode;
556 return SOCKET_ERROR;
557 }
558
559 /* Return success */
560 return NO_ERROR;
561 }
562
563 /*
564 * COPYRIGHT: See COPYING in the top level directory
565 * PROJECT: ReactOS Winsock 2 SPI
566 * FILE: lib/mswsock/lib/init.c
567 * PURPOSE: DLL Initialization
568 */
569
570 /* INCLUDES ******************************************************************/
571 #include "msafd.h"
572
573 /* DATA **********************************************************************/
574
575 /* FUNCTIONS *****************************************************************/
576
577 INT
578 WSPAPI
579 WSPRecv(SOCKET Handle,
580 LPWSABUF lpBuffers,
581 DWORD dwBufferCount,
582 LPDWORD lpNumberOfBytesRead,
583 LPDWORD ReceiveFlags,
584 LPWSAOVERLAPPED lpOverlapped,
585 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
586 LPWSATHREADID lpThreadId,
587 LPINT lpErrno)
588 {
589 PIO_STATUS_BLOCK IoStatusBlock;
590 IO_STATUS_BLOCK DummyIoStatusBlock;
591 AFD_RECV_INFO RecvInfo;
592 NTSTATUS Status;
593 PVOID APCContext;
594 PVOID ApcFunction;
595 HANDLE Event;
596 PWINSOCK_TEB_DATA ThreadData;
597 PSOCKET_INFORMATION Socket;
598 INT ErrorCode;
599 BOOLEAN ReturnValue;
600
601 /* Enter prolog */
602 ErrorCode = SockEnterApiFast(&ThreadData);
603 if (ErrorCode != NO_ERROR)
604 {
605 /* Fail */
606 *lpErrno = ErrorCode;
607 return SOCKET_ERROR;
608 }
609
610 /* Set up the Receive Structure */
611 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
612 RecvInfo.BufferCount = dwBufferCount;
613 RecvInfo.TdiFlags = 0;
614 RecvInfo.AfdFlags = 0;
615
616 /* Set the TDI Flags */
617 if (!(*ReceiveFlags))
618 {
619 /* Use normal TDI Receive */
620 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
621 }
622 else
623 {
624 /* Check for valid flags */
625 if ((*ReceiveFlags & ~(MSG_OOB | MSG_PEEK | MSG_PARTIAL)))
626 {
627 /* Fail */
628 ErrorCode = WSAEOPNOTSUPP;
629 goto error;
630 }
631
632 /* Check if OOB is being used */
633 if (*ReceiveFlags & MSG_OOB)
634 {
635 /* Use Expedited Receive for OOB */
636 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
637 }
638 else
639 {
640 /* Use normal receive */
641 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
642 }
643
644 /* Use Peek Receive if enabled */
645 if (*ReceiveFlags & MSG_PEEK) RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
646
647 /* Use Partial Receive if enabled */
648 if (*ReceiveFlags & MSG_PARTIAL) RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
649 }
650
651 /* Verifiy if we should use APC */
652 if (!lpOverlapped)
653 {
654 /* Not using Overlapped structure, so use normal blocking on event */
655 APCContext = NULL;
656 ApcFunction = NULL;
657 Event = ThreadData->EventHandle;
658 IoStatusBlock = &DummyIoStatusBlock;
659 }
660 else
661 {
662 /* Using apc, check if we have a completion routine */
663 if (!lpCompletionRoutine)
664 {
665 /* No need for APC */
666 APCContext = lpOverlapped;
667 ApcFunction = NULL;
668 Event = lpOverlapped->hEvent;
669 }
670 else
671 {
672 /* Use APC */
673 ApcFunction = SockIoCompletion;
674 APCContext = lpCompletionRoutine;
675 Event = NULL;
676
677 /* Skip Fast I/O */
678 RecvInfo.AfdFlags = AFD_SKIP_FIO;
679 }
680
681 /* Use the overlapped's structure buffer for the I/O Status Block */
682 IoStatusBlock = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
683
684 /* Make this an overlapped I/O in AFD */
685 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
686 }
687
688 /* Set is as Pending for now */
689 IoStatusBlock->Status = STATUS_PENDING;
690
691 /* Send IOCTL */
692 Status = NtDeviceIoControlFile((HANDLE)Handle,
693 Event,
694 ApcFunction,
695 APCContext,
696 IoStatusBlock,
697 IOCTL_AFD_RECV,
698 &RecvInfo,
699 sizeof(RecvInfo),
700 NULL,
701 0);
702
703 /* Increase the pending APC Count if we're using an APC */
704 if (!NT_ERROR(Status) && ApcFunction)
705 {
706 ThreadData->PendingAPCs++;
707 InterlockedIncrement(&SockProcessPendingAPCCount);
708 }
709
710 /* Wait for completition if not overlapped */
711 if ((Status == STATUS_PENDING) && !(lpOverlapped))
712 {
713 /* Wait for completion */
714 ReturnValue = SockWaitForSingleObject(Event,
715 Handle,
716 MAYBE_BLOCKING_HOOK,
717 RECV_TIMEOUT);
718
719 /* Check if the wait was successful */
720 if (ReturnValue)
721 {
722 /* Get new status */
723 Status = IoStatusBlock->Status;
724 }
725 else
726 {
727 /* Cancel the I/O */
728 SockCancelIo(Handle);
729
730 /* Get new status and normalize */
731 Status = IoStatusBlock->Status;
732 if (Status == STATUS_CANCELLED) Status = STATUS_IO_TIMEOUT;
733 }
734 }
735
736 /* Return the Flags */
737 *ReceiveFlags = 0;
738 switch (Status)
739 {
740 /* Success */
741 case STATUS_SUCCESS:
742 break;
743
744 /* Pending I/O */
745 case STATUS_PENDING:
746 ErrorCode = WSA_IO_PENDING;
747 goto error;
748
749 /* Buffer Overflow */
750 case STATUS_BUFFER_OVERFLOW:
751 /* Check if this was overlapped */
752 if (lpOverlapped)
753 {
754 /* Return without bytes read */
755 ErrorCode = WSA_IO_PENDING;
756 goto error;
757 }
758
759 /* Return failure with bytes read */
760 ErrorCode = WSAEMSGSIZE;
761 break;
762
763 /* OOB Receive */
764 case STATUS_RECEIVE_EXPEDITED:
765 *ReceiveFlags = MSG_OOB;
766 break;
767
768 /* Partial OOB Receive */
769 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
770 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
771 break;
772
773 /* Parial Receive */
774 case STATUS_RECEIVE_PARTIAL:
775 *ReceiveFlags = MSG_PARTIAL;
776 break;
777
778 /* Other NT Error */
779 default:
780 if (!NT_SUCCESS(Status))
781 {
782 /* Fail */
783 ErrorCode = NtStatusToSocketError(Status);
784 goto error;
785 }
786 break;
787 }
788
789 /* Return the number of bytes read */
790 *lpNumberOfBytesRead = PtrToUlong(IoStatusBlock->Information);
791
792 error:
793
794 /* Check if async select was active */
795 if (SockAsyncSelectCalled)
796 {
797 /* Get the socket */
798 Socket = SockFindAndReferenceSocket(Handle, TRUE);
799 if (Socket)
800 {
801 /* Lock it */
802 EnterCriticalSection(&Socket->Lock);
803
804 /* Check which event to re-enable */
805 if (RecvInfo.TdiFlags & TDI_RECEIVE_EXPEDITED)
806 {
807 /* Re-enable the OOB event */
808 SockReenableAsyncSelectEvent(Socket, FD_OOB);
809 }
810 else
811 {
812 /* Re-enable the regular read event */
813 SockReenableAsyncSelectEvent(Socket, FD_READ);
814 }
815
816 /* Unlock and dereference socket */
817 LeaveCriticalSection(&Socket->Lock);
818 SockDereferenceSocket(Socket);
819 }
820 }
821
822 /* Check for error */
823 if (ErrorCode != NO_ERROR)
824 {
825 /* Fail */
826 *lpErrno = ErrorCode;
827 return SOCKET_ERROR;
828 }
829
830 /* Return success */
831 return NO_ERROR;
832 }
833
834 INT
835 WSPAPI
836 WSPRecvFrom(SOCKET Handle,
837 LPWSABUF lpBuffers,
838 DWORD dwBufferCount,
839 LPDWORD lpNumberOfBytesRead,
840 LPDWORD ReceiveFlags,
841 PSOCKADDR SocketAddress,
842 PINT SocketAddressLength,
843 LPWSAOVERLAPPED lpOverlapped,
844 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
845 LPWSATHREADID lpThreadId,
846 LPINT lpErrno)
847 {
848 PIO_STATUS_BLOCK IoStatusBlock;
849 IO_STATUS_BLOCK DummyIoStatusBlock;
850 AFD_RECV_INFO_UDP RecvInfo;
851 NTSTATUS Status;
852 PVOID APCContext;
853 PVOID ApcFunction;
854 HANDLE Event;
855 PWINSOCK_TEB_DATA ThreadData;
856 PSOCKET_INFORMATION Socket;
857 INT ErrorCode;
858 BOOLEAN ReturnValue;
859
860 /* Enter prolog */
861 ErrorCode = SockEnterApiFast(&ThreadData);
862 if (ErrorCode != NO_ERROR)
863 {
864 /* Fail */
865 *lpErrno = ErrorCode;
866 return SOCKET_ERROR;
867 }
868
869 /* Get the socket */
870 Socket = SockFindAndReferenceSocket(Handle, TRUE);
871 if (!Socket)
872 {
873 /* Fail */
874 ErrorCode = WSAENOTSOCK;
875 goto error;
876 }
877
878 /* Fail if the socket isn't bound */
879 if (Socket->SharedData.State == SocketOpen)
880 {
881 /* Fail */
882 ErrorCode = WSAEINVAL;
883 goto error;
884 }
885
886 /* If this is an unconnected or non datagram socket */
887 if (!(MSAFD_IS_DGRAM_SOCK(Socket)) ||
888 (!SocketAddress && !SocketAddressLength))
889 {
890 /* Call WSP Recv */
891 SockDereferenceSocket(Socket);
892 return WSPRecv(Handle,
893 lpBuffers,
894 dwBufferCount,
895 lpNumberOfBytesRead,
896 ReceiveFlags,
897 lpOverlapped,
898 lpCompletionRoutine,
899 lpThreadId,
900 lpErrno);
901 }
902
903 /* If receive shutdown is enabled, fail */
904 if (Socket->SharedData.ReceiveShutdown)
905 {
906 /* Fail */
907 ErrorCode = WSAESHUTDOWN;
908 goto error;
909 }
910
911 /* Check for valid Socket Address (Length) flags */
912 if (!(SocketAddress) ^ (!SocketAddressLength || !(*SocketAddressLength)))
913 {
914 /* Fail */
915 ErrorCode = WSAEFAULT;
916 goto error;
917 }
918
919 /* Check for valid flags */
920 if ((*ReceiveFlags & ~(MSG_PEEK | MSG_PARTIAL)))
921 {
922 /* Fail */
923 ErrorCode = WSAEOPNOTSUPP;
924 goto error;
925 }
926
927 /* Check that the length is respected */
928 if (SocketAddressLength &&
929 (*SocketAddressLength < Socket->HelperData->MinWSAddressLength))
930 {
931 /* Fail */
932 ErrorCode = WSAEFAULT;
933 goto error;
934 }
935
936 /* Set up the Receive Structure */
937 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
938 RecvInfo.BufferCount = dwBufferCount;
939 RecvInfo.TdiFlags = TDI_RECEIVE_NORMAL;
940 RecvInfo.AfdFlags = 0;
941 RecvInfo.Address = SocketAddress;
942 RecvInfo.AddressLength = SocketAddressLength;
943
944 /* Use Peek Receive if enabled */
945 if (*ReceiveFlags & MSG_PEEK) RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
946
947 /* Use Partial Receive if enabled */
948 if (*ReceiveFlags & MSG_PARTIAL) RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
949
950 /* Verifiy if we should use APC */
951 if (!lpOverlapped)
952 {
953 /* Not using Overlapped structure, so use normal blocking on event */
954 APCContext = NULL;
955 ApcFunction = NULL;
956 Event = ThreadData->EventHandle;
957 IoStatusBlock = &DummyIoStatusBlock;
958 }
959 else
960 {
961 /* Using apc, check if we have a completion routine */
962 if (!lpCompletionRoutine)
963 {
964 /* No need for APC */
965 APCContext = lpOverlapped;
966 ApcFunction = NULL;
967 Event = lpOverlapped->hEvent;
968 }
969 else
970 {
971 /* Use APC */
972 ApcFunction = SockIoCompletion;
973 APCContext = lpCompletionRoutine;
974 Event = NULL;
975
976 /* Skip Fast I/O */
977 RecvInfo.AfdFlags = AFD_SKIP_FIO;
978 }
979
980 /* Use the overlapped's structure buffer for the I/O Status Block */
981 IoStatusBlock = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
982
983 /* Make this an overlapped I/O in AFD */
984 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
985 }
986
987 /* Set is as Pending for now */
988 IoStatusBlock->Status = STATUS_PENDING;
989
990 /* Send IOCTL */
991 Status = NtDeviceIoControlFile(Socket->WshContext.Handle,
992 Event,
993 ApcFunction,
994 APCContext,
995 IoStatusBlock,
996 IOCTL_AFD_RECV_DATAGRAM,
997 &RecvInfo,
998 sizeof(RecvInfo),
999 NULL,
1000 0);
1001
1002 /* Increase the pending APC Count if we're using an APC */
1003 if (!NT_ERROR(Status) && ApcFunction)
1004 {
1005 ThreadData->PendingAPCs++;
1006 InterlockedIncrement(&SockProcessPendingAPCCount);
1007 }
1008
1009 /* Wait for completition if not overlapped */
1010 if ((Status == STATUS_PENDING) && !(lpOverlapped))
1011 {
1012 /* Wait for completion */
1013 ReturnValue = SockWaitForSingleObject(Event,
1014 Handle,
1015 MAYBE_BLOCKING_HOOK,
1016 RECV_TIMEOUT);
1017
1018 /* Check if the wait was successful */
1019 if (ReturnValue)
1020 {
1021 /* Get new status */
1022 Status = IoStatusBlock->Status;
1023 }
1024 else
1025 {
1026 /* Cancel the I/O */
1027 SockCancelIo(Handle);
1028
1029 /* Get new status and normalize */
1030 Status = IoStatusBlock->Status;
1031 if (Status == STATUS_CANCELLED) Status = STATUS_IO_TIMEOUT;
1032 }
1033 }
1034
1035 /* Return the Flags */
1036 *ReceiveFlags = 0;
1037 switch (Status)
1038 {
1039 /* Success */
1040 case STATUS_SUCCESS:
1041 break;
1042
1043 /* Pending I/O */
1044 case STATUS_PENDING:
1045 ErrorCode = WSA_IO_PENDING;
1046 goto error;
1047
1048 /* Buffer Overflow */
1049 case STATUS_BUFFER_OVERFLOW:
1050 /* Check if this was overlapped */
1051 if (lpOverlapped)
1052 {
1053 /* Return without bytes read */
1054 ErrorCode = WSA_IO_PENDING;
1055 goto error;
1056 }
1057
1058 /* Return failure with bytes read */
1059 ErrorCode = WSAEMSGSIZE;
1060 break;
1061
1062 /* OOB Receive */
1063 case STATUS_RECEIVE_EXPEDITED:
1064 *ReceiveFlags = MSG_OOB;
1065 break;
1066
1067 /* Partial OOB Receive */
1068 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
1069 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
1070 break;
1071
1072 /* Parial Receive */
1073 case STATUS_RECEIVE_PARTIAL:
1074 *ReceiveFlags = MSG_PARTIAL;
1075 break;
1076
1077 /* Other NT Error */
1078 default:
1079 if (!NT_SUCCESS(Status))
1080 {
1081 /* Fail */
1082 ErrorCode = NtStatusToSocketError(Status);
1083 goto error;
1084 }
1085 break;
1086 }
1087
1088 /* Return the number of bytes read */
1089 *lpNumberOfBytesRead = PtrToUlong(IoStatusBlock->Information);
1090
1091 error:
1092
1093 /* Check if we have a socket here */
1094 if (Socket)
1095 {
1096 /* Check if async select was active */
1097 if (SockAsyncSelectCalled)
1098 {
1099 /* Lock the socket */
1100 EnterCriticalSection(&Socket->Lock);
1101
1102 /* Re-enable the regular read event */
1103 SockReenableAsyncSelectEvent(Socket, FD_READ);
1104
1105 /* Unlock socket */
1106 LeaveCriticalSection(&Socket->Lock);
1107 }
1108
1109 /* Dereference it */
1110 SockDereferenceSocket(Socket);
1111 }
1112
1113 /* Check for error */
1114 if (ErrorCode != NO_ERROR)
1115 {
1116 /* Fail */
1117 *lpErrno = ErrorCode;
1118 return SOCKET_ERROR;
1119 }
1120
1121 /* Return success */
1122 return NO_ERROR;
1123 }
1124
1125 /*
1126 * COPYRIGHT: See COPYING in the top level directory
1127 * PROJECT: ReactOS Winsock 2 SPI
1128 * FILE: lib/mswsock/lib/init.c
1129 * PURPOSE: DLL Initialization
1130 */
1131
1132 /* INCLUDES ******************************************************************/
1133 #include "msafd.h"
1134
1135 /* DATA **********************************************************************/
1136
1137 /* FUNCTIONS *****************************************************************/
1138
1139 INT
1140 WSPAPI
1141 WSPRecv(SOCKET Handle,
1142 LPWSABUF lpBuffers,
1143 DWORD dwBufferCount,
1144 LPDWORD lpNumberOfBytesRead,
1145 LPDWORD ReceiveFlags,
1146 LPWSAOVERLAPPED lpOverlapped,
1147 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1148 LPWSATHREADID lpThreadId,
1149 LPINT lpErrno)
1150 {
1151 PIO_STATUS_BLOCK IoStatusBlock;
1152 IO_STATUS_BLOCK DummyIoStatusBlock;
1153 AFD_RECV_INFO RecvInfo;
1154 NTSTATUS Status;
1155 PVOID APCContext;
1156 PVOID ApcFunction;
1157 HANDLE Event;
1158 PWINSOCK_TEB_DATA ThreadData;
1159 PSOCKET_INFORMATION Socket;
1160 INT ErrorCode;
1161 BOOLEAN ReturnValue;
1162
1163 /* Enter prolog */
1164 ErrorCode = SockEnterApiFast(&ThreadData);
1165 if (ErrorCode != NO_ERROR)
1166 {
1167 /* Fail */
1168 *lpErrno = ErrorCode;
1169 return SOCKET_ERROR;
1170 }
1171
1172 /* Set up the Receive Structure */
1173 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
1174 RecvInfo.BufferCount = dwBufferCount;
1175 RecvInfo.TdiFlags = 0;
1176 RecvInfo.AfdFlags = 0;
1177
1178 /* Set the TDI Flags */
1179 if (!(*ReceiveFlags))
1180 {
1181 /* Use normal TDI Receive */
1182 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
1183 }
1184 else
1185 {
1186 /* Check for valid flags */
1187 if ((*ReceiveFlags & ~(MSG_OOB | MSG_PEEK | MSG_PARTIAL)))
1188 {
1189 /* Fail */
1190 ErrorCode = WSAEOPNOTSUPP;
1191 goto error;
1192 }
1193
1194 /* Check if OOB is being used */
1195 if (*ReceiveFlags & MSG_OOB)
1196 {
1197 /* Use Expedited Receive for OOB */
1198 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
1199 }
1200 else
1201 {
1202 /* Use normal receive */
1203 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
1204 }
1205
1206 /* Use Peek Receive if enabled */
1207 if (*ReceiveFlags & MSG_PEEK) RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
1208
1209 /* Use Partial Receive if enabled */
1210 if (*ReceiveFlags & MSG_PARTIAL) RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
1211 }
1212
1213 /* Verifiy if we should use APC */
1214 if (!lpOverlapped)
1215 {
1216 /* Not using Overlapped structure, so use normal blocking on event */
1217 APCContext = NULL;
1218 ApcFunction = NULL;
1219 Event = ThreadData->EventHandle;
1220 IoStatusBlock = &DummyIoStatusBlock;
1221 }
1222 else
1223 {
1224 /* Using apc, check if we have a completion routine */
1225 if (!lpCompletionRoutine)
1226 {
1227 /* No need for APC */
1228 APCContext = lpOverlapped;
1229 ApcFunction = NULL;
1230 Event = lpOverlapped->hEvent;
1231 }
1232 else
1233 {
1234 /* Use APC */
1235 ApcFunction = SockIoCompletion;
1236 APCContext = lpCompletionRoutine;
1237 Event = NULL;
1238
1239 /* Skip Fast I/O */
1240 RecvInfo.AfdFlags = AFD_SKIP_FIO;
1241 }
1242
1243 /* Use the overlapped's structure buffer for the I/O Status Block */
1244 IoStatusBlock = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
1245
1246 /* Make this an overlapped I/O in AFD */
1247 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
1248 }
1249
1250 /* Set is as Pending for now */
1251 IoStatusBlock->Status = STATUS_PENDING;
1252
1253 /* Send IOCTL */
1254 Status = NtDeviceIoControlFile((HANDLE)Handle,
1255 Event,
1256 ApcFunction,
1257 APCContext,
1258 IoStatusBlock,
1259 IOCTL_AFD_RECV,
1260 &RecvInfo,
1261 sizeof(RecvInfo),
1262 NULL,
1263 0);
1264
1265 /* Increase the pending APC Count if we're using an APC */
1266 if (!NT_ERROR(Status) && ApcFunction)
1267 {
1268 ThreadData->PendingAPCs++;
1269 InterlockedIncrement(&SockProcessPendingAPCCount);
1270 }
1271
1272 /* Wait for completition if not overlapped */
1273 if ((Status == STATUS_PENDING) && !(lpOverlapped))
1274 {
1275 /* Wait for completion */
1276 ReturnValue = SockWaitForSingleObject(Event,
1277 Handle,
1278 MAYBE_BLOCKING_HOOK,
1279 RECV_TIMEOUT);
1280
1281 /* Check if the wait was successful */
1282 if (ReturnValue)
1283 {
1284 /* Get new status */
1285 Status = IoStatusBlock->Status;
1286 }
1287 else
1288 {
1289 /* Cancel the I/O */
1290 SockCancelIo(Handle);
1291
1292 /* Get new status and normalize */
1293 Status = IoStatusBlock->Status;
1294 if (Status == STATUS_CANCELLED) Status = STATUS_IO_TIMEOUT;
1295 }
1296 }
1297
1298 /* Return the Flags */
1299 *ReceiveFlags = 0;
1300 switch (Status)
1301 {
1302 /* Success */
1303 case STATUS_SUCCESS:
1304 break;
1305
1306 /* Pending I/O */
1307 case STATUS_PENDING:
1308 ErrorCode = WSA_IO_PENDING;
1309 goto error;
1310
1311 /* Buffer Overflow */
1312 case STATUS_BUFFER_OVERFLOW:
1313 /* Check if this was overlapped */
1314 if (lpOverlapped)
1315 {
1316 /* Return without bytes read */
1317 ErrorCode = WSA_IO_PENDING;
1318 goto error;
1319 }
1320
1321 /* Return failure with bytes read */
1322 ErrorCode = WSAEMSGSIZE;
1323 break;
1324
1325 /* OOB Receive */
1326 case STATUS_RECEIVE_EXPEDITED:
1327 *ReceiveFlags = MSG_OOB;
1328 break;
1329
1330 /* Partial OOB Receive */
1331 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
1332 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
1333 break;
1334
1335 /* Parial Receive */
1336 case STATUS_RECEIVE_PARTIAL:
1337 *ReceiveFlags = MSG_PARTIAL;
1338 break;
1339
1340 /* Other NT Error */
1341 default:
1342 if (!NT_SUCCESS(Status))
1343 {
1344 /* Fail */
1345 ErrorCode = NtStatusToSocketError(Status);
1346 goto error;
1347 }
1348 break;
1349 }
1350
1351 /* Return the number of bytes read */
1352 *lpNumberOfBytesRead = PtrToUlong(IoStatusBlock->Information);
1353
1354 error:
1355
1356 /* Check if async select was active */
1357 if (SockAsyncSelectCalled)
1358 {
1359 /* Get the socket */
1360 Socket = SockFindAndReferenceSocket(Handle, TRUE);
1361 if (Socket)
1362 {
1363 /* Lock it */
1364 EnterCriticalSection(&Socket->Lock);
1365
1366 /* Check which event to re-enable */
1367 if (RecvInfo.TdiFlags & TDI_RECEIVE_EXPEDITED)
1368 {
1369 /* Re-enable the OOB event */
1370 SockReenableAsyncSelectEvent(Socket, FD_OOB);
1371 }
1372 else
1373 {
1374 /* Re-enable the regular read event */
1375 SockReenableAsyncSelectEvent(Socket, FD_READ);
1376 }
1377
1378 /* Unlock and dereference socket */
1379 LeaveCriticalSection(&Socket->Lock);
1380 SockDereferenceSocket(Socket);
1381 }
1382 }
1383
1384 /* Check for error */
1385 if (ErrorCode != NO_ERROR)
1386 {
1387 /* Fail */
1388 *lpErrno = ErrorCode;
1389 return SOCKET_ERROR;
1390 }
1391
1392 /* Return success */
1393 return NO_ERROR;
1394 }
1395
1396 INT
1397 WSPAPI
1398 WSPRecvFrom(SOCKET Handle,
1399 LPWSABUF lpBuffers,
1400 DWORD dwBufferCount,
1401 LPDWORD lpNumberOfBytesRead,
1402 LPDWORD ReceiveFlags,
1403 PSOCKADDR SocketAddress,
1404 PINT SocketAddressLength,
1405 LPWSAOVERLAPPED lpOverlapped,
1406 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1407 LPWSATHREADID lpThreadId,
1408 LPINT lpErrno)
1409 {
1410 PIO_STATUS_BLOCK IoStatusBlock;
1411 IO_STATUS_BLOCK DummyIoStatusBlock;
1412 AFD_RECV_INFO_UDP RecvInfo;
1413 NTSTATUS Status;
1414 PVOID APCContext;
1415 PVOID ApcFunction;
1416 HANDLE Event;
1417 PWINSOCK_TEB_DATA ThreadData;
1418 PSOCKET_INFORMATION Socket;
1419 INT ErrorCode;
1420 BOOLEAN ReturnValue;
1421
1422 /* Enter prolog */
1423 ErrorCode = SockEnterApiFast(&ThreadData);
1424 if (ErrorCode != NO_ERROR)
1425 {
1426 /* Fail */
1427 *lpErrno = ErrorCode;
1428 return SOCKET_ERROR;
1429 }
1430
1431 /* Get the socket */
1432 Socket = SockFindAndReferenceSocket(Handle, TRUE);
1433 if (!Socket)
1434 {
1435 /* Fail */
1436 ErrorCode = WSAENOTSOCK;
1437 goto error;
1438 }
1439
1440 /* Fail if the socket isn't bound */
1441 if (Socket->SharedData.State == SocketOpen)
1442 {
1443 /* Fail */
1444 ErrorCode = WSAEINVAL;
1445 goto error;
1446 }
1447
1448 /* If this is an unconnected or non datagram socket */
1449 if (!(MSAFD_IS_DGRAM_SOCK(Socket)) ||
1450 (!SocketAddress && !SocketAddressLength))
1451 {
1452 /* Call WSP Recv */
1453 SockDereferenceSocket(Socket);
1454 return WSPRecv(Handle,
1455 lpBuffers,
1456 dwBufferCount,
1457 lpNumberOfBytesRead,
1458 ReceiveFlags,
1459 lpOverlapped,
1460 lpCompletionRoutine,
1461 lpThreadId,
1462 lpErrno);
1463 }
1464
1465 /* If receive shutdown is enabled, fail */
1466 if (Socket->SharedData.ReceiveShutdown)
1467 {
1468 /* Fail */
1469 ErrorCode = WSAESHUTDOWN;
1470 goto error;
1471 }
1472
1473 /* Check for valid Socket Address (Length) flags */
1474 if (!(SocketAddress) ^ (!SocketAddressLength || !(*SocketAddressLength)))
1475 {
1476 /* Fail */
1477 ErrorCode = WSAEFAULT;
1478 goto error;
1479 }
1480
1481 /* Check for valid flags */
1482 if ((*ReceiveFlags & ~(MSG_PEEK | MSG_PARTIAL)))
1483 {
1484 /* Fail */
1485 ErrorCode = WSAEOPNOTSUPP;
1486 goto error;
1487 }
1488
1489 /* Check that the length is respected */
1490 if (SocketAddressLength &&
1491 (*SocketAddressLength < Socket->HelperData->MinWSAddressLength))
1492 {
1493 /* Fail */
1494 ErrorCode = WSAEFAULT;
1495 goto error;
1496 }
1497
1498 /* Set up the Receive Structure */
1499 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
1500 RecvInfo.BufferCount = dwBufferCount;
1501 RecvInfo.TdiFlags = TDI_RECEIVE_NORMAL;
1502 RecvInfo.AfdFlags = 0;
1503 RecvInfo.Address = SocketAddress;
1504 RecvInfo.AddressLength = SocketAddressLength;
1505
1506 /* Use Peek Receive if enabled */
1507 if (*ReceiveFlags & MSG_PEEK) RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
1508
1509 /* Use Partial Receive if enabled */
1510 if (*ReceiveFlags & MSG_PARTIAL) RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
1511
1512 /* Verifiy if we should use APC */
1513 if (!lpOverlapped)
1514 {
1515 /* Not using Overlapped structure, so use normal blocking on event */
1516 APCContext = NULL;
1517 ApcFunction = NULL;
1518 Event = ThreadData->EventHandle;
1519 IoStatusBlock = &DummyIoStatusBlock;
1520 }
1521 else
1522 {
1523 /* Using apc, check if we have a completion routine */
1524 if (!lpCompletionRoutine)
1525 {
1526 /* No need for APC */
1527 APCContext = lpOverlapped;
1528 ApcFunction = NULL;
1529 Event = lpOverlapped->hEvent;
1530 }
1531 else
1532 {
1533 /* Use APC */
1534 ApcFunction = SockIoCompletion;
1535 APCContext = lpCompletionRoutine;
1536 Event = NULL;
1537
1538 /* Skip Fast I/O */
1539 RecvInfo.AfdFlags = AFD_SKIP_FIO;
1540 }
1541
1542 /* Use the overlapped's structure buffer for the I/O Status Block */
1543 IoStatusBlock = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
1544
1545 /* Make this an overlapped I/O in AFD */
1546 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
1547 }
1548
1549 /* Set is as Pending for now */
1550 IoStatusBlock->Status = STATUS_PENDING;
1551
1552 /* Send IOCTL */
1553 Status = NtDeviceIoControlFile(Socket->WshContext.Handle,
1554 Event,
1555 ApcFunction,
1556 APCContext,
1557 IoStatusBlock,
1558 IOCTL_AFD_RECV_DATAGRAM,
1559 &RecvInfo,
1560 sizeof(RecvInfo),
1561 NULL,
1562 0);
1563
1564 /* Increase the pending APC Count if we're using an APC */
1565 if (!NT_ERROR(Status) && ApcFunction)
1566 {
1567 ThreadData->PendingAPCs++;
1568 InterlockedIncrement(&SockProcessPendingAPCCount);
1569 }
1570
1571 /* Wait for completition if not overlapped */
1572 if ((Status == STATUS_PENDING) && !(lpOverlapped))
1573 {
1574 /* Wait for completion */
1575 ReturnValue = SockWaitForSingleObject(Event,
1576 Handle,
1577 MAYBE_BLOCKING_HOOK,
1578 RECV_TIMEOUT);
1579
1580 /* Check if the wait was successful */
1581 if (ReturnValue)
1582 {
1583 /* Get new status */
1584 Status = IoStatusBlock->Status;
1585 }
1586 else
1587 {
1588 /* Cancel the I/O */
1589 SockCancelIo(Handle);
1590
1591 /* Get new status and normalize */
1592 Status = IoStatusBlock->Status;
1593 if (Status == STATUS_CANCELLED) Status = STATUS_IO_TIMEOUT;
1594 }
1595 }
1596
1597 /* Return the Flags */
1598 *ReceiveFlags = 0;
1599 switch (Status)
1600 {
1601 /* Success */
1602 case STATUS_SUCCESS:
1603 break;
1604
1605 /* Pending I/O */
1606 case STATUS_PENDING:
1607 ErrorCode = WSA_IO_PENDING;
1608 goto error;
1609
1610 /* Buffer Overflow */
1611 case STATUS_BUFFER_OVERFLOW:
1612 /* Check if this was overlapped */
1613 if (lpOverlapped)
1614 {
1615 /* Return without bytes read */
1616 ErrorCode = WSA_IO_PENDING;
1617 goto error;
1618 }
1619
1620 /* Return failure with bytes read */
1621 ErrorCode = WSAEMSGSIZE;
1622 break;
1623
1624 /* OOB Receive */
1625 case STATUS_RECEIVE_EXPEDITED:
1626 *ReceiveFlags = MSG_OOB;
1627 break;
1628
1629 /* Partial OOB Receive */
1630 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
1631 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
1632 break;
1633
1634 /* Parial Receive */
1635 case STATUS_RECEIVE_PARTIAL:
1636 *ReceiveFlags = MSG_PARTIAL;
1637 break;
1638
1639 /* Other NT Error */
1640 default:
1641 if (!NT_SUCCESS(Status))
1642 {
1643 /* Fail */
1644 ErrorCode = NtStatusToSocketError(Status);
1645 goto error;
1646 }
1647 break;
1648 }
1649
1650 /* Return the number of bytes read */
1651 *lpNumberOfBytesRead = PtrToUlong(IoStatusBlock->Information);
1652
1653 error:
1654
1655 /* Check if we have a socket here */
1656 if (Socket)
1657 {
1658 /* Check if async select was active */
1659 if (SockAsyncSelectCalled)
1660 {
1661 /* Lock the socket */
1662 EnterCriticalSection(&Socket->Lock);
1663
1664 /* Re-enable the regular read event */
1665 SockReenableAsyncSelectEvent(Socket, FD_READ);
1666
1667 /* Unlock socket */
1668 LeaveCriticalSection(&Socket->Lock);
1669 }
1670
1671 /* Dereference it */
1672 SockDereferenceSocket(Socket);
1673 }
1674
1675 /* Check for error */
1676 if (ErrorCode != NO_ERROR)
1677 {
1678 /* Fail */
1679 *lpErrno = ErrorCode;
1680 return SOCKET_ERROR;
1681 }
1682
1683 /* Return success */
1684 return NO_ERROR;
1685 }
1686
1687 /*
1688 * COPYRIGHT: See COPYING in the top level directory
1689 * PROJECT: ReactOS Winsock 2 SPI
1690 * FILE: lib/mswsock/lib/init.c
1691 * PURPOSE: DLL Initialization
1692 */
1693
1694 /* INCLUDES ******************************************************************/
1695 #include "msafd.h"
1696
1697 /* DATA **********************************************************************/
1698
1699 /* FUNCTIONS *****************************************************************/
1700
1701 INT
1702 WSPAPI
1703 WSPRecv(SOCKET Handle,
1704 LPWSABUF lpBuffers,
1705 DWORD dwBufferCount,
1706 LPDWORD lpNumberOfBytesRead,
1707 LPDWORD ReceiveFlags,
1708 LPWSAOVERLAPPED lpOverlapped,
1709 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1710 LPWSATHREADID lpThreadId,
1711 LPINT lpErrno)
1712 {
1713 PIO_STATUS_BLOCK IoStatusBlock;
1714 IO_STATUS_BLOCK DummyIoStatusBlock;
1715 AFD_RECV_INFO RecvInfo;
1716 NTSTATUS Status;
1717 PVOID APCContext;
1718 PVOID ApcFunction;
1719 HANDLE Event;
1720 PWINSOCK_TEB_DATA ThreadData;
1721 PSOCKET_INFORMATION Socket;
1722 INT ErrorCode;
1723 BOOLEAN ReturnValue;
1724
1725 /* Enter prolog */
1726 ErrorCode = SockEnterApiFast(&ThreadData);
1727 if (ErrorCode != NO_ERROR)
1728 {
1729 /* Fail */
1730 *lpErrno = ErrorCode;
1731 return SOCKET_ERROR;
1732 }
1733
1734 /* Set up the Receive Structure */
1735 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
1736 RecvInfo.BufferCount = dwBufferCount;
1737 RecvInfo.TdiFlags = 0;
1738 RecvInfo.AfdFlags = 0;
1739
1740 /* Set the TDI Flags */
1741 if (!(*ReceiveFlags))
1742 {
1743 /* Use normal TDI Receive */
1744 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
1745 }
1746 else
1747 {
1748 /* Check for valid flags */
1749 if ((*ReceiveFlags & ~(MSG_OOB | MSG_PEEK | MSG_PARTIAL)))
1750 {
1751 /* Fail */
1752 ErrorCode = WSAEOPNOTSUPP;
1753 goto error;
1754 }
1755
1756 /* Check if OOB is being used */
1757 if (*ReceiveFlags & MSG_OOB)
1758 {
1759 /* Use Expedited Receive for OOB */
1760 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED;
1761 }
1762 else
1763 {
1764 /* Use normal receive */
1765 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL;
1766 }
1767
1768 /* Use Peek Receive if enabled */
1769 if (*ReceiveFlags & MSG_PEEK) RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
1770
1771 /* Use Partial Receive if enabled */
1772 if (*ReceiveFlags & MSG_PARTIAL) RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
1773 }
1774
1775 /* Verifiy if we should use APC */
1776 if (!lpOverlapped)
1777 {
1778 /* Not using Overlapped structure, so use normal blocking on event */
1779 APCContext = NULL;
1780 ApcFunction = NULL;
1781 Event = ThreadData->EventHandle;
1782 IoStatusBlock = &DummyIoStatusBlock;
1783 }
1784 else
1785 {
1786 /* Using apc, check if we have a completion routine */
1787 if (!lpCompletionRoutine)
1788 {
1789 /* No need for APC */
1790 APCContext = lpOverlapped;
1791 ApcFunction = NULL;
1792 Event = lpOverlapped->hEvent;
1793 }
1794 else
1795 {
1796 /* Use APC */
1797 ApcFunction = SockIoCompletion;
1798 APCContext = lpCompletionRoutine;
1799 Event = NULL;
1800
1801 /* Skip Fast I/O */
1802 RecvInfo.AfdFlags = AFD_SKIP_FIO;
1803 }
1804
1805 /* Use the overlapped's structure buffer for the I/O Status Block */
1806 IoStatusBlock = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
1807
1808 /* Make this an overlapped I/O in AFD */
1809 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
1810 }
1811
1812 /* Set is as Pending for now */
1813 IoStatusBlock->Status = STATUS_PENDING;
1814
1815 /* Send IOCTL */
1816 Status = NtDeviceIoControlFile((HANDLE)Handle,
1817 Event,
1818 ApcFunction,
1819 APCContext,
1820 IoStatusBlock,
1821 IOCTL_AFD_RECV,
1822 &RecvInfo,
1823 sizeof(RecvInfo),
1824 NULL,
1825 0);
1826
1827 /* Increase the pending APC Count if we're using an APC */
1828 if (!NT_ERROR(Status) && ApcFunction)
1829 {
1830 ThreadData->PendingAPCs++;
1831 InterlockedIncrement(&SockProcessPendingAPCCount);
1832 }
1833
1834 /* Wait for completition if not overlapped */
1835 if ((Status == STATUS_PENDING) && !(lpOverlapped))
1836 {
1837 /* Wait for completion */
1838 ReturnValue = SockWaitForSingleObject(Event,
1839 Handle,
1840 MAYBE_BLOCKING_HOOK,
1841 RECV_TIMEOUT);
1842
1843 /* Check if the wait was successful */
1844 if (ReturnValue)
1845 {
1846 /* Get new status */
1847 Status = IoStatusBlock->Status;
1848 }
1849 else
1850 {
1851 /* Cancel the I/O */
1852 SockCancelIo(Handle);
1853
1854 /* Get new status and normalize */
1855 Status = IoStatusBlock->Status;
1856 if (Status == STATUS_CANCELLED) Status = STATUS_IO_TIMEOUT;
1857 }
1858 }
1859
1860 /* Return the Flags */
1861 *ReceiveFlags = 0;
1862 switch (Status)
1863 {
1864 /* Success */
1865 case STATUS_SUCCESS:
1866 break;
1867
1868 /* Pending I/O */
1869 case STATUS_PENDING:
1870 ErrorCode = WSA_IO_PENDING;
1871 goto error;
1872
1873 /* Buffer Overflow */
1874 case STATUS_BUFFER_OVERFLOW:
1875 /* Check if this was overlapped */
1876 if (lpOverlapped)
1877 {
1878 /* Return without bytes read */
1879 ErrorCode = WSA_IO_PENDING;
1880 goto error;
1881 }
1882
1883 /* Return failure with bytes read */
1884 ErrorCode = WSAEMSGSIZE;
1885 break;
1886
1887 /* OOB Receive */
1888 case STATUS_RECEIVE_EXPEDITED:
1889 *ReceiveFlags = MSG_OOB;
1890 break;
1891
1892 /* Partial OOB Receive */
1893 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
1894 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
1895 break;
1896
1897 /* Parial Receive */
1898 case STATUS_RECEIVE_PARTIAL:
1899 *ReceiveFlags = MSG_PARTIAL;
1900 break;
1901
1902 /* Other NT Error */
1903 default:
1904 if (!NT_SUCCESS(Status))
1905 {
1906 /* Fail */
1907 ErrorCode = NtStatusToSocketError(Status);
1908 goto error;
1909 }
1910 break;
1911 }
1912
1913 /* Return the number of bytes read */
1914 *lpNumberOfBytesRead = PtrToUlong(IoStatusBlock->Information);
1915
1916 error:
1917
1918 /* Check if async select was active */
1919 if (SockAsyncSelectCalled)
1920 {
1921 /* Get the socket */
1922 Socket = SockFindAndReferenceSocket(Handle, TRUE);
1923 if (Socket)
1924 {
1925 /* Lock it */
1926 EnterCriticalSection(&Socket->Lock);
1927
1928 /* Check which event to re-enable */
1929 if (RecvInfo.TdiFlags & TDI_RECEIVE_EXPEDITED)
1930 {
1931 /* Re-enable the OOB event */
1932 SockReenableAsyncSelectEvent(Socket, FD_OOB);
1933 }
1934 else
1935 {
1936 /* Re-enable the regular read event */
1937 SockReenableAsyncSelectEvent(Socket, FD_READ);
1938 }
1939
1940 /* Unlock and dereference socket */
1941 LeaveCriticalSection(&Socket->Lock);
1942 SockDereferenceSocket(Socket);
1943 }
1944 }
1945
1946 /* Check for error */
1947 if (ErrorCode != NO_ERROR)
1948 {
1949 /* Fail */
1950 *lpErrno = ErrorCode;
1951 return SOCKET_ERROR;
1952 }
1953
1954 /* Return success */
1955 return NO_ERROR;
1956 }
1957
1958 INT
1959 WSPAPI
1960 WSPRecvFrom(SOCKET Handle,
1961 LPWSABUF lpBuffers,
1962 DWORD dwBufferCount,
1963 LPDWORD lpNumberOfBytesRead,
1964 LPDWORD ReceiveFlags,
1965 PSOCKADDR SocketAddress,
1966 PINT SocketAddressLength,
1967 LPWSAOVERLAPPED lpOverlapped,
1968 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
1969 LPWSATHREADID lpThreadId,
1970 LPINT lpErrno)
1971 {
1972 PIO_STATUS_BLOCK IoStatusBlock;
1973 IO_STATUS_BLOCK DummyIoStatusBlock;
1974 AFD_RECV_INFO_UDP RecvInfo;
1975 NTSTATUS Status;
1976 PVOID APCContext;
1977 PVOID ApcFunction;
1978 HANDLE Event;
1979 PWINSOCK_TEB_DATA ThreadData;
1980 PSOCKET_INFORMATION Socket;
1981 INT ErrorCode;
1982 BOOLEAN ReturnValue;
1983
1984 /* Enter prolog */
1985 ErrorCode = SockEnterApiFast(&ThreadData);
1986 if (ErrorCode != NO_ERROR)
1987 {
1988 /* Fail */
1989 *lpErrno = ErrorCode;
1990 return SOCKET_ERROR;
1991 }
1992
1993 /* Get the socket */
1994 Socket = SockFindAndReferenceSocket(Handle, TRUE);
1995 if (!Socket)
1996 {
1997 /* Fail */
1998 ErrorCode = WSAENOTSOCK;
1999 goto error;
2000 }
2001
2002 /* Fail if the socket isn't bound */
2003 if (Socket->SharedData.State == SocketOpen)
2004 {
2005 /* Fail */
2006 ErrorCode = WSAEINVAL;
2007 goto error;
2008 }
2009
2010 /* If this is an unconnected or non datagram socket */
2011 if (!(MSAFD_IS_DGRAM_SOCK(Socket)) ||
2012 (!SocketAddress && !SocketAddressLength))
2013 {
2014 /* Call WSP Recv */
2015 SockDereferenceSocket(Socket);
2016 return WSPRecv(Handle,
2017 lpBuffers,
2018 dwBufferCount,
2019 lpNumberOfBytesRead,
2020 ReceiveFlags,
2021 lpOverlapped,
2022 lpCompletionRoutine,
2023 lpThreadId,
2024 lpErrno);
2025 }
2026
2027 /* If receive shutdown is enabled, fail */
2028 if (Socket->SharedData.ReceiveShutdown)
2029 {
2030 /* Fail */
2031 ErrorCode = WSAESHUTDOWN;
2032 goto error;
2033 }
2034
2035 /* Check for valid Socket Address (Length) flags */
2036 if (!(SocketAddress) ^ (!SocketAddressLength || !(*SocketAddressLength)))
2037 {
2038 /* Fail */
2039 ErrorCode = WSAEFAULT;
2040 goto error;
2041 }
2042
2043 /* Check for valid flags */
2044 if ((*ReceiveFlags & ~(MSG_PEEK | MSG_PARTIAL)))
2045 {
2046 /* Fail */
2047 ErrorCode = WSAEOPNOTSUPP;
2048 goto error;
2049 }
2050
2051 /* Check that the length is respected */
2052 if (SocketAddressLength &&
2053 (*SocketAddressLength < Socket->HelperData->MinWSAddressLength))
2054 {
2055 /* Fail */
2056 ErrorCode = WSAEFAULT;
2057 goto error;
2058 }
2059
2060 /* Set up the Receive Structure */
2061 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
2062 RecvInfo.BufferCount = dwBufferCount;
2063 RecvInfo.TdiFlags = TDI_RECEIVE_NORMAL;
2064 RecvInfo.AfdFlags = 0;
2065 RecvInfo.Address = SocketAddress;
2066 RecvInfo.AddressLength = SocketAddressLength;
2067
2068 /* Use Peek Receive if enabled */
2069 if (*ReceiveFlags & MSG_PEEK) RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK;
2070
2071 /* Use Partial Receive if enabled */
2072 if (*ReceiveFlags & MSG_PARTIAL) RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL;
2073
2074 /* Verifiy if we should use APC */
2075 if (!lpOverlapped)
2076 {
2077 /* Not using Overlapped structure, so use normal blocking on event */
2078 APCContext = NULL;
2079 ApcFunction = NULL;
2080 Event = ThreadData->EventHandle;
2081 IoStatusBlock = &DummyIoStatusBlock;
2082 }
2083 else
2084 {
2085 /* Using apc, check if we have a completion routine */
2086 if (!lpCompletionRoutine)
2087 {
2088 /* No need for APC */
2089 APCContext = lpOverlapped;
2090 ApcFunction = NULL;
2091 Event = lpOverlapped->hEvent;
2092 }
2093 else
2094 {
2095 /* Use APC */
2096 ApcFunction = SockIoCompletion;
2097 APCContext = lpCompletionRoutine;
2098 Event = NULL;
2099
2100 /* Skip Fast I/O */
2101 RecvInfo.AfdFlags = AFD_SKIP_FIO;
2102 }
2103
2104 /* Use the overlapped's structure buffer for the I/O Status Block */
2105 IoStatusBlock = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
2106
2107 /* Make this an overlapped I/O in AFD */
2108 RecvInfo.AfdFlags |= AFD_OVERLAPPED;
2109 }
2110
2111 /* Set is as Pending for now */
2112 IoStatusBlock->Status = STATUS_PENDING;
2113
2114 /* Send IOCTL */
2115 Status = NtDeviceIoControlFile(Socket->WshContext.Handle,
2116 Event,
2117 ApcFunction,
2118 APCContext,
2119 IoStatusBlock,
2120 IOCTL_AFD_RECV_DATAGRAM,
2121 &RecvInfo,
2122 sizeof(RecvInfo),
2123 NULL,
2124 0);
2125
2126 /* Increase the pending APC Count if we're using an APC */
2127 if (!NT_ERROR(Status) && ApcFunction)
2128 {
2129 ThreadData->PendingAPCs++;
2130 InterlockedIncrement(&SockProcessPendingAPCCount);
2131 }
2132
2133 /* Wait for completition if not overlapped */
2134 if ((Status == STATUS_PENDING) && !(lpOverlapped))
2135 {
2136 /* Wait for completion */
2137 ReturnValue = SockWaitForSingleObject(Event,
2138 Handle,
2139 MAYBE_BLOCKING_HOOK,
2140 RECV_TIMEOUT);
2141
2142 /* Check if the wait was successful */
2143 if (ReturnValue)
2144 {
2145 /* Get new status */
2146 Status = IoStatusBlock->Status;
2147 }
2148 else
2149 {
2150 /* Cancel the I/O */
2151 SockCancelIo(Handle);
2152
2153 /* Get new status and normalize */
2154 Status = IoStatusBlock->Status;
2155 if (Status == STATUS_CANCELLED) Status = STATUS_IO_TIMEOUT;
2156 }
2157 }
2158
2159 /* Return the Flags */
2160 *ReceiveFlags = 0;
2161 switch (Status)
2162 {
2163 /* Success */
2164 case STATUS_SUCCESS:
2165 break;
2166
2167 /* Pending I/O */
2168 case STATUS_PENDING:
2169 ErrorCode = WSA_IO_PENDING;
2170 goto error;
2171
2172 /* Buffer Overflow */
2173 case STATUS_BUFFER_OVERFLOW:
2174 /* Check if this was overlapped */
2175 if (lpOverlapped)
2176 {
2177 /* Return without bytes read */
2178 ErrorCode = WSA_IO_PENDING;
2179 goto error;
2180 }
2181
2182 /* Return failure with bytes read */
2183 ErrorCode = WSAEMSGSIZE;
2184 break;
2185
2186 /* OOB Receive */
2187 case STATUS_RECEIVE_EXPEDITED:
2188 *ReceiveFlags = MSG_OOB;
2189 break;
2190
2191 /* Partial OOB Receive */
2192 case STATUS_RECEIVE_PARTIAL_EXPEDITED:
2193 *ReceiveFlags = MSG_PARTIAL | MSG_OOB;
2194 break;
2195
2196 /* Parial Receive */
2197 case STATUS_RECEIVE_PARTIAL:
2198 *ReceiveFlags = MSG_PARTIAL;
2199 break;
2200
2201 /* Other NT Error */
2202 default:
2203 if (!NT_SUCCESS(Status))
2204 {
2205 /* Fail */
2206 ErrorCode = NtStatusToSocketError(Status);
2207 goto error;
2208 }
2209 break;
2210 }
2211
2212 /* Return the number of bytes read */
2213 *lpNumberOfBytesRead = PtrToUlong(IoStatusBlock->Information);
2214
2215 error:
2216
2217 /* Check if we have a socket here */
2218 if (Socket)
2219 {
2220 /* Check if async select was active */
2221 if (SockAsyncSelectCalled)
2222 {
2223 /* Lock the socket */
2224 EnterCriticalSection(&Socket->Lock);
2225
2226 /* Re-enable the regular read event */
2227 SockReenableAsyncSelectEvent(Socket, FD_READ);
2228
2229 /* Unlock socket */
2230 LeaveCriticalSection(&Socket->Lock);
2231 }
2232
2233 /* Dereference it */
2234 SockDereferenceSocket(Socket);
2235 }
2236
2237 /* Check for error */
2238 if (ErrorCode != NO_ERROR)
2239 {
2240 /* Fail */
2241 *lpErrno = ErrorCode;
2242 return SOCKET_ERROR;
2243 }
2244
2245 /* Return success */
2246 return NO_ERROR;
2247 }
2248