- Update AFD's shared header
[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 UCHAR TdiBuffer[0x16];
520 PSOCKADDR BindAddress;
521 INT BindAddressLength;
522 HANDLE SockEvent;
523 PSOCKET_INFORMATION Socket;
524
525
526 /* Get the Socket Structure associate to this Socket*/
527 Socket = GetSocketStructure(Handle);
528
529 Status = NtCreateEvent( &SockEvent, GENERIC_READ | GENERIC_WRITE,
530 NULL, 1, FALSE );
531
532 if( !NT_SUCCESS(Status) )
533 return -1;
534
535 /* Bind us First */
536 if (Socket->SharedData.State == SocketOpen)
537 {
538 /* Get the Wildcard Address */
539 BindAddressLength = Socket->HelperData->MaxWSAddressLength;
540 BindAddress = HeapAlloc(GlobalHeap, 0, BindAddressLength);
541 if (!BindAddress)
542 {
543 MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL );
544 return INVALID_SOCKET;
545 }
546 Socket->HelperData->WSHGetWildcardSockaddr (Socket->HelperContext,
547 BindAddress,
548 &BindAddressLength);
549
550 /* Bind it */
551 WSPBind(Handle, BindAddress, BindAddressLength, NULL);
552 }
553
554 /* Set up Address in TDI Format */
555 RemoteAddress = (PTRANSPORT_ADDRESS)TdiBuffer;
556 RemoteAddress->TAAddressCount = 1;
557 RemoteAddress->Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family);
558 RtlCopyMemory(&RemoteAddress->Address[0].AddressType, SocketAddress, SocketAddressLength);
559
560 /* Set up Structure */
561 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers;
562 SendInfo.AfdFlags = Socket->SharedData.NonBlocking ? AFD_IMMEDIATE : 0;
563 SendInfo.BufferCount = dwBufferCount;
564 SendInfo.TdiConnection.RemoteAddress = RemoteAddress;
565 SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength;
566
567 /* Verifiy if we should use APC */
568 if (lpOverlapped == NULL)
569 {
570 /* Not using Overlapped structure, so use normal blocking on event */
571 APCContext = NULL;
572 APCFunction = NULL;
573 Event = SockEvent;
574 IOSB = &DummyIOSB;
575 }
576 else
577 {
578 if (lpCompletionRoutine == NULL)
579 {
580 /* Using Overlapped Structure, but no Completition Routine, so no need for APC */
581 APCContext = lpOverlapped;
582 APCFunction = NULL;
583 Event = lpOverlapped->hEvent;
584 }
585 else
586 {
587 /* Using Overlapped Structure and a Completition Routine, so use an APC */
588 APCFunction = NULL; // should be a private io completition function inside us
589 APCContext = lpCompletionRoutine;
590 SendInfo.AfdFlags |= AFD_SKIP_FIO;
591 }
592
593 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
594 SendInfo.AfdFlags |= AFD_OVERLAPPED;
595 }
596
597 /* Send IOCTL */
598 Status = NtDeviceIoControlFile((HANDLE)Handle,
599 Event ? Event : SockEvent,
600 APCFunction,
601 APCContext,
602 IOSB,
603 IOCTL_AFD_SEND_DATAGRAM,
604 &SendInfo,
605 sizeof(SendInfo),
606 NULL,
607 0);
608
609 /* Wait for completition of not overlapped */
610 if (Status == STATUS_PENDING && lpOverlapped == NULL)
611 {
612 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infintely for send...
613 Status = IOSB->Status;
614 }
615
616 NtClose( SockEvent );
617
618 if (Status == STATUS_PENDING)
619 return WSA_IO_PENDING;
620
621
622 /* Re-enable Async Event */
623 SockReenableAsyncSelectEvent(Socket, FD_WRITE);
624
625 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent );
626 }
627 INT
628 WSPAPI
629 WSPRecvDisconnect(IN SOCKET s,
630 OUT LPWSABUF lpInboundDisconnectData,
631 OUT LPINT lpErrno)
632 {
633 UNIMPLEMENTED
634 return 0;
635 }
636
637
638
639 INT
640 WSPAPI
641 WSPSendDisconnect(IN SOCKET s,
642 IN LPWSABUF lpOutboundDisconnectData,
643 OUT LPINT lpErrno)
644 {
645 UNIMPLEMENTED
646 return 0;
647 }
648
649 /* EOF */