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