1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Ancillary Function Driver DLL 4 * FILE: dll/win32/msafd/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 INT 16 WSPAPI 17 WSPAsyncSelect(IN SOCKET Handle, 18 IN HWND hWnd, 19 IN UINT wMsg, 20 IN LONG lEvent, 21 OUT LPINT lpErrno) 22 { 23 PSOCKET_INFORMATION Socket = NULL; 24 PASYNC_DATA AsyncData; 25 BOOLEAN BlockMode; 26 27 /* Get the Socket Structure associated to this Socket */ 28 Socket = GetSocketStructure(Handle); 29 if (!Socket) 30 { 31 *lpErrno = WSAENOTSOCK; 32 return SOCKET_ERROR; 33 } 34 35 /* Allocate the Async Data Structure to pass on to the Thread later */ 36 AsyncData = HeapAlloc(GetProcessHeap(), 0, sizeof(*AsyncData)); 37 if (!AsyncData) 38 { 39 MsafdReturnWithErrno( STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL ); 40 return INVALID_SOCKET; 41 } 42 43 /* Change the Socket to Non Blocking */ 44 BlockMode = TRUE; 45 SetSocketInformation(Socket, AFD_INFO_BLOCKING_MODE, &BlockMode, NULL, NULL, NULL, NULL); 46 Socket->SharedData->NonBlocking = TRUE; 47 48 /* Deactivate WSPEventSelect */ 49 if (Socket->SharedData->AsyncEvents) 50 { 51 if (WSPEventSelect(Handle, NULL, 0, lpErrno) == SOCKET_ERROR) 52 { 53 HeapFree(GetProcessHeap(), 0, AsyncData); 54 return SOCKET_ERROR; 55 } 56 } 57 58 /* Create the Asynch Thread if Needed */ 59 SockCreateOrReferenceAsyncThread(); 60 61 /* Open a Handle to AFD's Async Helper */ 62 SockGetAsyncSelectHelperAfdHandle(); 63 64 /* Store Socket Data */ 65 Socket->SharedData->hWnd = hWnd; 66 Socket->SharedData->wMsg = wMsg; 67 Socket->SharedData->AsyncEvents = lEvent; 68 Socket->SharedData->AsyncDisabledEvents = 0; 69 Socket->SharedData->SequenceNumber++; 70 71 /* Return if there are no more Events */ 72 if ((Socket->SharedData->AsyncEvents & (~Socket->SharedData->AsyncDisabledEvents)) == 0) 73 { 74 HeapFree(GetProcessHeap(), 0, AsyncData); 75 return 0; 76 } 77 78 /* Set up the Async Data */ 79 AsyncData->ParentSocket = Socket; 80 AsyncData->SequenceNumber = Socket->SharedData->SequenceNumber; 81 82 /* Begin Async Select by using I/O Completion */ 83 NtSetIoCompletion(SockAsyncCompletionPort, 84 (PVOID)&SockProcessQueuedAsyncSelect, 85 AsyncData, 86 0, 87 0); 88 89 /* Return */ 90 return ERROR_SUCCESS; 91 } 92 93 94 BOOL 95 WSPAPI 96 WSPGetOverlappedResult( 97 IN SOCKET Handle, 98 IN LPWSAOVERLAPPED lpOverlapped, 99 OUT LPDWORD lpdwBytes, 100 IN BOOL fWait, 101 OUT LPDWORD lpdwFlags, 102 OUT LPINT lpErrno) 103 { 104 PSOCKET_INFORMATION Socket; 105 BOOL Ret; 106 107 TRACE("Called (%x)\n", Handle); 108 109 /* Get the Socket Structure associate to this Socket*/ 110 Socket = GetSocketStructure(Handle); 111 if (!Socket) 112 { 113 if(lpErrno) 114 *lpErrno = WSAENOTSOCK; 115 return FALSE; 116 } 117 if (!lpOverlapped || !lpdwBytes || !lpdwFlags) 118 { 119 if (lpErrno) 120 *lpErrno = WSAEFAULT; 121 return FALSE; 122 } 123 Ret = GetOverlappedResult((HANDLE)Handle, lpOverlapped, lpdwBytes, fWait); 124 125 if (Ret) 126 { 127 *lpdwFlags = 0; 128 129 /* Re-enable Async Event */ 130 SockReenableAsyncSelectEvent(Socket, FD_OOB); 131 SockReenableAsyncSelectEvent(Socket, FD_WRITE); 132 SockReenableAsyncSelectEvent(Socket, FD_READ); 133 } 134 135 return Ret; 136 } 137 138 VOID 139 NTAPI 140 AfdAPC(PVOID ApcContext, 141 PIO_STATUS_BLOCK IoStatusBlock, 142 ULONG Reserved) 143 { 144 PAFDAPCCONTEXT Context = ApcContext; 145 146 /* Re-enable Async Event */ 147 SockReenableAsyncSelectEvent(Context->lpSocket, FD_OOB); 148 SockReenableAsyncSelectEvent(Context->lpSocket, FD_READ); 149 SockReenableAsyncSelectEvent(Context->lpSocket, FD_WRITE); 150 151 Context->lpCompletionRoutine(IoStatusBlock->Status, IoStatusBlock->Information, Context->lpOverlapped, 0); 152 HeapFree(GlobalHeap, 0, ApcContext); 153 } 154 155 int 156 WSPAPI 157 WSPRecv(SOCKET Handle, 158 LPWSABUF lpBuffers, 159 DWORD dwBufferCount, 160 LPDWORD lpNumberOfBytesRead, 161 LPDWORD ReceiveFlags, 162 LPWSAOVERLAPPED lpOverlapped, 163 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, 164 LPWSATHREADID lpThreadId, 165 LPINT lpErrno) 166 { 167 PIO_STATUS_BLOCK IOSB; 168 IO_STATUS_BLOCK DummyIOSB; 169 AFD_RECV_INFO RecvInfo; 170 NTSTATUS Status; 171 PVOID APCContext; 172 PIO_APC_ROUTINE APCFunction; 173 HANDLE Event = NULL; 174 HANDLE SockEvent; 175 PSOCKET_INFORMATION Socket; 176 177 TRACE("Called (%x)\n", Handle); 178 179 /* Get the Socket Structure associate to this Socket*/ 180 Socket = GetSocketStructure(Handle); 181 if (!Socket) 182 { 183 if (lpErrno) 184 *lpErrno = WSAENOTSOCK; 185 return SOCKET_ERROR; 186 } 187 if (!lpNumberOfBytesRead && !lpOverlapped) 188 { 189 if (lpErrno) 190 *lpErrno = WSAEFAULT; 191 return SOCKET_ERROR; 192 } 193 if (Socket->SharedData->OobInline && ReceiveFlags && (*ReceiveFlags & MSG_OOB) != 0) 194 { 195 if (lpErrno) 196 *lpErrno = WSAEINVAL; 197 return SOCKET_ERROR; 198 } 199 200 Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, 201 NULL, SynchronizationEvent, FALSE ); 202 203 if( !NT_SUCCESS(Status) ) 204 return -1; 205 206 /* Set up the Receive Structure */ 207 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers; 208 RecvInfo.BufferCount = dwBufferCount; 209 RecvInfo.TdiFlags = 0; 210 RecvInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; 211 212 /* Set the TDI Flags */ 213 if (*ReceiveFlags == 0) 214 { 215 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL; 216 } 217 else 218 { 219 if (*ReceiveFlags & MSG_OOB) 220 { 221 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED; 222 } 223 224 if (*ReceiveFlags & MSG_PEEK) 225 { 226 RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK; 227 } 228 229 if (*ReceiveFlags & MSG_PARTIAL) 230 { 231 RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL; 232 } 233 } 234 235 /* Verify if we should use APC */ 236 237 if (lpOverlapped == NULL) 238 { 239 /* Not using Overlapped structure, so use normal blocking on event */ 240 APCContext = NULL; 241 APCFunction = NULL; 242 Event = SockEvent; 243 IOSB = &DummyIOSB; 244 } 245 else 246 { 247 /* Overlapped request for non overlapped opened socket */ 248 if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0) 249 { 250 TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n"); 251 return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesRead); 252 } 253 if (lpCompletionRoutine == NULL) 254 { 255 /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ 256 APCContext = lpOverlapped; 257 APCFunction = NULL; 258 Event = lpOverlapped->hEvent; 259 } 260 else 261 { 262 /* Using Overlapped Structure and a Completion Routine, so use an APC */ 263 APCFunction = &AfdAPC; // should be a private io completion function inside us 264 APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); 265 if (!APCContext) 266 { 267 ERR("Not enough memory for APC Context\n"); 268 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesRead); 269 } 270 ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; 271 ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; 272 ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; 273 RecvInfo.AfdFlags |= AFD_SKIP_FIO; 274 } 275 276 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; 277 RecvInfo.AfdFlags |= AFD_OVERLAPPED; 278 } 279 280 IOSB->Status = STATUS_PENDING; 281 282 /* Send IOCTL */ 283 Status = NtDeviceIoControlFile((HANDLE)Handle, 284 Event, 285 APCFunction, 286 APCContext, 287 IOSB, 288 IOCTL_AFD_RECV, 289 &RecvInfo, 290 sizeof(RecvInfo), 291 NULL, 292 0); 293 294 /* Wait for completion of not overlapped */ 295 if (Status == STATUS_PENDING && lpOverlapped == NULL) 296 { 297 /* It's up to the protocol to time out recv. We must wait 298 * until the protocol decides it's had enough. 299 */ 300 WaitForSingleObject(SockEvent, INFINITE); 301 Status = IOSB->Status; 302 } 303 304 NtClose( SockEvent ); 305 306 TRACE("Status %x Information %d\n", Status, IOSB->Information); 307 308 if (Status == STATUS_PENDING) 309 { 310 TRACE("Leaving (Pending)\n"); 311 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead); 312 } 313 314 /* Return the Flags */ 315 *ReceiveFlags = 0; 316 317 switch (Status) 318 { 319 case STATUS_RECEIVE_EXPEDITED: 320 *ReceiveFlags = MSG_OOB; 321 break; 322 case STATUS_RECEIVE_PARTIAL_EXPEDITED: 323 *ReceiveFlags = MSG_PARTIAL | MSG_OOB; 324 break; 325 case STATUS_RECEIVE_PARTIAL: 326 *ReceiveFlags = MSG_PARTIAL; 327 break; 328 } 329 330 /* Re-enable Async Event */ 331 if (*ReceiveFlags & MSG_OOB) 332 { 333 SockReenableAsyncSelectEvent(Socket, FD_OOB); 334 } 335 else 336 { 337 SockReenableAsyncSelectEvent(Socket, FD_READ); 338 } 339 340 if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) 341 { 342 lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags); 343 HeapFree(GlobalHeap, 0, (PVOID)APCContext); 344 } 345 346 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead ); 347 } 348 349 int 350 WSPAPI 351 WSPRecvFrom(SOCKET Handle, 352 LPWSABUF lpBuffers, 353 DWORD dwBufferCount, 354 LPDWORD lpNumberOfBytesRead, 355 LPDWORD ReceiveFlags, 356 struct sockaddr *SocketAddress, 357 int *SocketAddressLength, 358 LPWSAOVERLAPPED lpOverlapped, 359 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, 360 LPWSATHREADID lpThreadId, 361 LPINT lpErrno ) 362 { 363 PIO_STATUS_BLOCK IOSB; 364 IO_STATUS_BLOCK DummyIOSB; 365 AFD_RECV_INFO_UDP RecvInfo; 366 NTSTATUS Status; 367 PVOID APCContext; 368 PVOID APCFunction; 369 HANDLE Event = NULL; 370 HANDLE SockEvent; 371 PSOCKET_INFORMATION Socket; 372 373 /* Get the Socket Structure associate to this Socket*/ 374 Socket = GetSocketStructure(Handle); 375 if (!Socket) 376 { 377 if (lpErrno) 378 *lpErrno = WSAENOTSOCK; 379 return SOCKET_ERROR; 380 } 381 if (!lpNumberOfBytesRead && !lpOverlapped) 382 { 383 if (lpErrno) 384 *lpErrno = WSAEFAULT; 385 return SOCKET_ERROR; 386 } 387 if (Socket->SharedData->OobInline && ReceiveFlags && (*ReceiveFlags & MSG_OOB) != 0) 388 { 389 if (lpErrno) 390 *lpErrno = WSAEINVAL; 391 return SOCKET_ERROR; 392 } 393 394 if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS)) 395 { 396 /* Call WSPRecv for a non-datagram socket */ 397 return WSPRecv(Handle, 398 lpBuffers, 399 dwBufferCount, 400 lpNumberOfBytesRead, 401 ReceiveFlags, 402 lpOverlapped, 403 lpCompletionRoutine, 404 lpThreadId, 405 lpErrno); 406 } 407 408 /* Bind us First */ 409 if (Socket->SharedData->State == SocketOpen) 410 { 411 Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext, 412 SocketAddress, 413 SocketAddressLength); 414 /* Bind it */ 415 if (WSPBind(Handle, SocketAddress, *SocketAddressLength, lpErrno) == SOCKET_ERROR) 416 return SOCKET_ERROR; 417 } 418 419 Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, 420 NULL, SynchronizationEvent, FALSE ); 421 422 if( !NT_SUCCESS(Status) ) 423 return -1; 424 425 /* Set up the Receive Structure */ 426 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers; 427 RecvInfo.BufferCount = dwBufferCount; 428 RecvInfo.TdiFlags = 0; 429 RecvInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; 430 RecvInfo.AddressLength = SocketAddressLength; 431 RecvInfo.Address = SocketAddress; 432 433 /* Set the TDI Flags */ 434 if (*ReceiveFlags == 0) 435 { 436 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL; 437 } 438 else 439 { 440 if (*ReceiveFlags & MSG_OOB) 441 { 442 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED; 443 } 444 445 if (*ReceiveFlags & MSG_PEEK) 446 { 447 RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK; 448 } 449 450 if (*ReceiveFlags & MSG_PARTIAL) 451 { 452 RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL; 453 } 454 } 455 456 /* Verify if we should use APC */ 457 458 if (lpOverlapped == NULL) 459 { 460 /* Not using Overlapped structure, so use normal blocking on event */ 461 APCContext = NULL; 462 APCFunction = NULL; 463 Event = SockEvent; 464 IOSB = &DummyIOSB; 465 } 466 else 467 { 468 /* Overlapped request for non overlapped opened socket */ 469 if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0) 470 { 471 TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n"); 472 return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesRead); 473 } 474 if (lpCompletionRoutine == NULL) 475 { 476 /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ 477 APCContext = lpOverlapped; 478 APCFunction = NULL; 479 Event = lpOverlapped->hEvent; 480 } 481 else 482 { 483 /* Using Overlapped Structure and a Completion Routine, so use an APC */ 484 APCFunction = &AfdAPC; // should be a private io completion function inside us 485 APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); 486 if (!APCContext) 487 { 488 ERR("Not enough memory for APC Context\n"); 489 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesRead); 490 } 491 ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; 492 ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; 493 ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; 494 RecvInfo.AfdFlags |= AFD_SKIP_FIO; 495 } 496 497 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; 498 RecvInfo.AfdFlags |= AFD_OVERLAPPED; 499 } 500 501 IOSB->Status = STATUS_PENDING; 502 503 /* Send IOCTL */ 504 Status = NtDeviceIoControlFile((HANDLE)Handle, 505 Event, 506 APCFunction, 507 APCContext, 508 IOSB, 509 IOCTL_AFD_RECV_DATAGRAM, 510 &RecvInfo, 511 sizeof(RecvInfo), 512 NULL, 513 0); 514 515 /* Wait for completion of not overlapped */ 516 if (Status == STATUS_PENDING && lpOverlapped == NULL) 517 { 518 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infinitely for receive... 519 Status = IOSB->Status; 520 } 521 522 NtClose( SockEvent ); 523 524 if (Status == STATUS_PENDING) 525 { 526 TRACE("Leaving (Pending)\n"); 527 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead); 528 } 529 530 /* Return the Flags */ 531 *ReceiveFlags = 0; 532 533 switch (Status) 534 { 535 case STATUS_RECEIVE_EXPEDITED: 536 *ReceiveFlags = MSG_OOB; 537 break; 538 case STATUS_RECEIVE_PARTIAL_EXPEDITED: 539 *ReceiveFlags = MSG_PARTIAL | MSG_OOB; 540 break; 541 case STATUS_RECEIVE_PARTIAL: 542 *ReceiveFlags = MSG_PARTIAL; 543 break; 544 } 545 546 /* Re-enable Async Event */ 547 if (*ReceiveFlags & MSG_OOB) 548 { 549 SockReenableAsyncSelectEvent(Socket, FD_OOB); 550 } 551 else 552 { 553 SockReenableAsyncSelectEvent(Socket, FD_READ); 554 } 555 556 if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) 557 { 558 lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags); 559 HeapFree(GlobalHeap, 0, (PVOID)APCContext); 560 } 561 562 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead ); 563 } 564 565 566 int 567 WSPAPI 568 WSPSend(SOCKET Handle, 569 LPWSABUF lpBuffers, 570 DWORD dwBufferCount, 571 LPDWORD lpNumberOfBytesSent, 572 DWORD iFlags, 573 LPWSAOVERLAPPED lpOverlapped, 574 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, 575 LPWSATHREADID lpThreadId, 576 LPINT lpErrno) 577 { 578 PIO_STATUS_BLOCK IOSB; 579 IO_STATUS_BLOCK DummyIOSB; 580 AFD_SEND_INFO SendInfo; 581 NTSTATUS Status; 582 PVOID APCContext; 583 PVOID APCFunction; 584 HANDLE Event = NULL; 585 HANDLE SockEvent; 586 PSOCKET_INFORMATION Socket; 587 588 /* Get the Socket Structure associate to this Socket*/ 589 Socket = GetSocketStructure(Handle); 590 if (!Socket) 591 { 592 if (lpErrno) 593 *lpErrno = WSAENOTSOCK; 594 return SOCKET_ERROR; 595 } 596 if (!lpNumberOfBytesSent && !lpOverlapped) 597 { 598 if (lpErrno) 599 *lpErrno = WSAEFAULT; 600 return SOCKET_ERROR; 601 } 602 603 Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, 604 NULL, SynchronizationEvent, FALSE ); 605 606 if( !NT_SUCCESS(Status) ) 607 return -1; 608 609 TRACE("Called\n"); 610 611 /* Set up the Send Structure */ 612 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers; 613 SendInfo.BufferCount = dwBufferCount; 614 SendInfo.TdiFlags = 0; 615 SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; 616 617 /* Set the TDI Flags */ 618 if (iFlags) 619 { 620 if (iFlags & MSG_OOB) 621 { 622 SendInfo.TdiFlags |= TDI_SEND_EXPEDITED; 623 } 624 if (iFlags & MSG_PARTIAL) 625 { 626 SendInfo.TdiFlags |= TDI_SEND_PARTIAL; 627 } 628 } 629 630 /* Verify if we should use APC */ 631 if (lpOverlapped == NULL) 632 { 633 /* Not using Overlapped structure, so use normal blocking on event */ 634 APCContext = NULL; 635 APCFunction = NULL; 636 Event = SockEvent; 637 IOSB = &DummyIOSB; 638 } 639 else 640 { 641 /* Overlapped request for non overlapped opened socket */ 642 if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0) 643 { 644 TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n"); 645 return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent); 646 } 647 if (lpCompletionRoutine == NULL) 648 { 649 /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ 650 APCContext = lpOverlapped; 651 APCFunction = NULL; 652 Event = lpOverlapped->hEvent; 653 } 654 else 655 { 656 /* Using Overlapped Structure and a Completion Routine, so use an APC */ 657 APCFunction = &AfdAPC; // should be a private io completion function inside us 658 APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); 659 if (!APCContext) 660 { 661 ERR("Not enough memory for APC Context\n"); 662 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent); 663 } 664 ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; 665 ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; 666 ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; 667 SendInfo.AfdFlags |= AFD_SKIP_FIO; 668 } 669 670 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; 671 SendInfo.AfdFlags |= AFD_OVERLAPPED; 672 } 673 674 IOSB->Status = STATUS_PENDING; 675 676 /* Send IOCTL */ 677 Status = NtDeviceIoControlFile((HANDLE)Handle, 678 Event, 679 APCFunction, 680 APCContext, 681 IOSB, 682 IOCTL_AFD_SEND, 683 &SendInfo, 684 sizeof(SendInfo), 685 NULL, 686 0); 687 688 /* Wait for completion of not overlapped */ 689 if (Status == STATUS_PENDING && lpOverlapped == NULL) 690 { 691 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infinitely for send... 692 Status = IOSB->Status; 693 } 694 695 NtClose( SockEvent ); 696 697 if (Status == STATUS_PENDING) 698 { 699 TRACE("Leaving (Pending)\n"); 700 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); 701 } 702 703 /* Re-enable Async Event */ 704 SockReenableAsyncSelectEvent(Socket, FD_WRITE); 705 706 TRACE("Leaving (Success, %d)\n", IOSB->Information); 707 708 if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) 709 { 710 lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0); 711 HeapFree(GlobalHeap, 0, (PVOID)APCContext); 712 } 713 714 return MsafdReturnWithErrno( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent ); 715 } 716 717 int 718 WSPAPI 719 WSPSendTo(SOCKET Handle, 720 LPWSABUF lpBuffers, 721 DWORD dwBufferCount, 722 LPDWORD lpNumberOfBytesSent, 723 DWORD iFlags, 724 const struct sockaddr *SocketAddress, 725 int SocketAddressLength, 726 LPWSAOVERLAPPED lpOverlapped, 727 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, 728 LPWSATHREADID lpThreadId, 729 LPINT lpErrno) 730 { 731 PIO_STATUS_BLOCK IOSB; 732 IO_STATUS_BLOCK DummyIOSB; 733 AFD_SEND_INFO_UDP SendInfo; 734 NTSTATUS Status; 735 PVOID APCContext; 736 PVOID APCFunction; 737 HANDLE Event = NULL; 738 PTRANSPORT_ADDRESS RemoteAddress; 739 PSOCKADDR BindAddress = NULL; 740 INT BindAddressLength; 741 HANDLE SockEvent; 742 PSOCKET_INFORMATION Socket; 743 744 /* Get the Socket Structure associate to this Socket */ 745 Socket = GetSocketStructure(Handle); 746 if (!Socket) 747 { 748 if (lpErrno) 749 *lpErrno = WSAENOTSOCK; 750 return SOCKET_ERROR; 751 } 752 if (!lpNumberOfBytesSent && !lpOverlapped) 753 { 754 if (lpErrno) 755 *lpErrno = WSAEFAULT; 756 return SOCKET_ERROR; 757 } 758 759 if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS)) 760 { 761 /* Use WSPSend for connection-oriented sockets */ 762 return WSPSend(Handle, 763 lpBuffers, 764 dwBufferCount, 765 lpNumberOfBytesSent, 766 iFlags, 767 lpOverlapped, 768 lpCompletionRoutine, 769 lpThreadId, 770 lpErrno); 771 } 772 773 /* Bind us First */ 774 if (Socket->SharedData->State == SocketOpen) 775 { 776 /* Get the Wildcard Address */ 777 BindAddressLength = Socket->HelperData->MaxWSAddressLength; 778 BindAddress = HeapAlloc(GlobalHeap, 0, BindAddressLength); 779 if (!BindAddress) 780 { 781 MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL); 782 return INVALID_SOCKET; 783 } 784 785 Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext, 786 BindAddress, 787 &BindAddressLength); 788 /* Bind it */ 789 if (WSPBind(Handle, BindAddress, BindAddressLength, lpErrno) == SOCKET_ERROR) 790 return SOCKET_ERROR; 791 } 792 793 RemoteAddress = HeapAlloc(GlobalHeap, 0, 0x6 + SocketAddressLength); 794 if (!RemoteAddress) 795 { 796 if (BindAddress != NULL) 797 { 798 HeapFree(GlobalHeap, 0, BindAddress); 799 } 800 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL); 801 } 802 803 Status = NtCreateEvent(&SockEvent, 804 EVENT_ALL_ACCESS, 805 NULL, SynchronizationEvent, FALSE); 806 807 if (!NT_SUCCESS(Status)) 808 { 809 HeapFree(GlobalHeap, 0, RemoteAddress); 810 if (BindAddress != NULL) 811 { 812 HeapFree(GlobalHeap, 0, BindAddress); 813 } 814 return SOCKET_ERROR; 815 } 816 817 /* Set up Address in TDI Format */ 818 RemoteAddress->TAAddressCount = 1; 819 RemoteAddress->Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family); 820 RtlCopyMemory(&RemoteAddress->Address[0].AddressType, SocketAddress, SocketAddressLength); 821 822 /* Set up Structure */ 823 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers; 824 SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; 825 SendInfo.BufferCount = dwBufferCount; 826 SendInfo.TdiConnection.RemoteAddress = RemoteAddress; 827 SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength; 828 829 /* Verify if we should use APC */ 830 if (lpOverlapped == NULL) 831 { 832 /* Not using Overlapped structure, so use normal blocking on event */ 833 APCContext = NULL; 834 APCFunction = NULL; 835 Event = SockEvent; 836 IOSB = &DummyIOSB; 837 } 838 else 839 { 840 /* Overlapped request for non overlapped opened socket */ 841 if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0) 842 { 843 TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n"); 844 return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent); 845 } 846 if (lpCompletionRoutine == NULL) 847 { 848 /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ 849 APCContext = lpOverlapped; 850 APCFunction = NULL; 851 Event = lpOverlapped->hEvent; 852 } 853 else 854 { 855 /* Using Overlapped Structure and a Completion Routine, so use an APC */ 856 APCFunction = &AfdAPC; // should be a private io completion function inside us 857 APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); 858 if (!APCContext) 859 { 860 ERR("Not enough memory for APC Context\n"); 861 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent); 862 } 863 ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; 864 ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; 865 ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; 866 SendInfo.AfdFlags |= AFD_SKIP_FIO; 867 } 868 869 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; 870 SendInfo.AfdFlags |= AFD_OVERLAPPED; 871 } 872 873 /* Send IOCTL */ 874 Status = NtDeviceIoControlFile((HANDLE)Handle, 875 Event, 876 APCFunction, 877 APCContext, 878 IOSB, 879 IOCTL_AFD_SEND_DATAGRAM, 880 &SendInfo, 881 sizeof(SendInfo), 882 NULL, 883 0); 884 885 /* Wait for completion of not overlapped */ 886 if (Status == STATUS_PENDING && lpOverlapped == NULL) 887 { 888 /* BUGBUG, shouldn't wait infinitely for send... */ 889 WaitForSingleObject(SockEvent, INFINITE); 890 Status = IOSB->Status; 891 } 892 893 NtClose(SockEvent); 894 HeapFree(GlobalHeap, 0, RemoteAddress); 895 if (BindAddress != NULL) 896 { 897 HeapFree(GlobalHeap, 0, BindAddress); 898 } 899 900 if (Status == STATUS_PENDING) 901 { 902 TRACE("Leaving (Pending)\n"); 903 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); 904 } 905 906 SockReenableAsyncSelectEvent(Socket, FD_WRITE); 907 908 if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) 909 { 910 lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0); 911 HeapFree(GlobalHeap, 0, (PVOID)APCContext); 912 } 913 914 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); 915 } 916 917 INT 918 WSPAPI 919 WSPRecvDisconnect(IN SOCKET s, 920 OUT LPWSABUF lpInboundDisconnectData, 921 OUT LPINT lpErrno) 922 { 923 UNIMPLEMENTED; 924 return 0; 925 } 926 927 928 929 INT 930 WSPAPI 931 WSPSendDisconnect(IN SOCKET s, 932 IN LPWSABUF lpOutboundDisconnectData, 933 OUT LPINT lpErrno) 934 { 935 UNIMPLEMENTED; 936 return 0; 937 } 938 939 /* EOF */ 940