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