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