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 /* Non-blocking sockets must wait until data is available */ 295 if (Status == STATUS_PENDING && Socket->SharedData->NonBlocking) 296 { 297 if (lpErrno) *lpErrno = WSAEWOULDBLOCK; 298 return SOCKET_ERROR; 299 } 300 301 /* Wait for completion of not overlapped */ 302 if (Status == STATUS_PENDING && lpOverlapped == NULL) 303 { 304 /* It's up to the protocol to time out recv. We must wait 305 * until the protocol decides it's had enough. 306 */ 307 WaitForSingleObject(SockEvent, INFINITE); 308 Status = IOSB->Status; 309 } 310 311 NtClose( SockEvent ); 312 313 TRACE("Status %x Information %d\n", Status, IOSB->Information); 314 315 if (Status == STATUS_PENDING) 316 { 317 TRACE("Leaving (Pending)\n"); 318 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead); 319 } 320 321 /* Return the Flags */ 322 *ReceiveFlags = 0; 323 324 switch (Status) 325 { 326 case STATUS_RECEIVE_EXPEDITED: 327 *ReceiveFlags = MSG_OOB; 328 break; 329 case STATUS_RECEIVE_PARTIAL_EXPEDITED: 330 *ReceiveFlags = MSG_PARTIAL | MSG_OOB; 331 break; 332 case STATUS_RECEIVE_PARTIAL: 333 *ReceiveFlags = MSG_PARTIAL; 334 break; 335 } 336 337 /* Re-enable Async Event */ 338 if (*ReceiveFlags & MSG_OOB) 339 { 340 SockReenableAsyncSelectEvent(Socket, FD_OOB); 341 } 342 else 343 { 344 SockReenableAsyncSelectEvent(Socket, FD_READ); 345 } 346 347 if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) 348 { 349 lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags); 350 HeapFree(GlobalHeap, 0, (PVOID)APCContext); 351 } 352 353 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead ); 354 } 355 356 int 357 WSPAPI 358 WSPRecvFrom(SOCKET Handle, 359 LPWSABUF lpBuffers, 360 DWORD dwBufferCount, 361 LPDWORD lpNumberOfBytesRead, 362 LPDWORD ReceiveFlags, 363 struct sockaddr *SocketAddress, 364 int *SocketAddressLength, 365 LPWSAOVERLAPPED lpOverlapped, 366 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, 367 LPWSATHREADID lpThreadId, 368 LPINT lpErrno ) 369 { 370 PIO_STATUS_BLOCK IOSB; 371 IO_STATUS_BLOCK DummyIOSB; 372 AFD_RECV_INFO_UDP RecvInfo; 373 NTSTATUS Status; 374 PVOID APCContext; 375 PVOID APCFunction; 376 HANDLE Event = NULL; 377 HANDLE SockEvent; 378 PSOCKET_INFORMATION Socket; 379 380 /* Get the Socket Structure associate to this Socket*/ 381 Socket = GetSocketStructure(Handle); 382 if (!Socket) 383 { 384 if (lpErrno) 385 *lpErrno = WSAENOTSOCK; 386 return SOCKET_ERROR; 387 } 388 if (!lpNumberOfBytesRead && !lpOverlapped) 389 { 390 if (lpErrno) 391 *lpErrno = WSAEFAULT; 392 return SOCKET_ERROR; 393 } 394 if (Socket->SharedData->OobInline && ReceiveFlags && (*ReceiveFlags & MSG_OOB) != 0) 395 { 396 if (lpErrno) 397 *lpErrno = WSAEINVAL; 398 return SOCKET_ERROR; 399 } 400 401 if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS)) 402 { 403 /* Call WSPRecv for a non-datagram socket */ 404 return WSPRecv(Handle, 405 lpBuffers, 406 dwBufferCount, 407 lpNumberOfBytesRead, 408 ReceiveFlags, 409 lpOverlapped, 410 lpCompletionRoutine, 411 lpThreadId, 412 lpErrno); 413 } 414 415 /* Bind us First */ 416 if (Socket->SharedData->State == SocketOpen) 417 { 418 Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext, 419 SocketAddress, 420 SocketAddressLength); 421 /* Bind it */ 422 if (WSPBind(Handle, SocketAddress, *SocketAddressLength, lpErrno) == SOCKET_ERROR) 423 return SOCKET_ERROR; 424 } 425 426 Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, 427 NULL, SynchronizationEvent, FALSE ); 428 429 if( !NT_SUCCESS(Status) ) 430 return -1; 431 432 /* Set up the Receive Structure */ 433 RecvInfo.BufferArray = (PAFD_WSABUF)lpBuffers; 434 RecvInfo.BufferCount = dwBufferCount; 435 RecvInfo.TdiFlags = 0; 436 RecvInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; 437 RecvInfo.AddressLength = SocketAddressLength; 438 RecvInfo.Address = SocketAddress; 439 440 /* Set the TDI Flags */ 441 if (*ReceiveFlags == 0) 442 { 443 RecvInfo.TdiFlags |= TDI_RECEIVE_NORMAL; 444 } 445 else 446 { 447 if (*ReceiveFlags & MSG_OOB) 448 { 449 RecvInfo.TdiFlags |= TDI_RECEIVE_EXPEDITED; 450 } 451 452 if (*ReceiveFlags & MSG_PEEK) 453 { 454 RecvInfo.TdiFlags |= TDI_RECEIVE_PEEK; 455 } 456 457 if (*ReceiveFlags & MSG_PARTIAL) 458 { 459 RecvInfo.TdiFlags |= TDI_RECEIVE_PARTIAL; 460 } 461 } 462 463 /* Verify if we should use APC */ 464 465 if (lpOverlapped == NULL) 466 { 467 /* Not using Overlapped structure, so use normal blocking on event */ 468 APCContext = NULL; 469 APCFunction = NULL; 470 Event = SockEvent; 471 IOSB = &DummyIOSB; 472 } 473 else 474 { 475 /* Overlapped request for non overlapped opened socket */ 476 if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0) 477 { 478 TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n"); 479 return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesRead); 480 } 481 if (lpCompletionRoutine == NULL) 482 { 483 /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ 484 APCContext = lpOverlapped; 485 APCFunction = NULL; 486 Event = lpOverlapped->hEvent; 487 } 488 else 489 { 490 /* Using Overlapped Structure and a Completion Routine, so use an APC */ 491 APCFunction = &AfdAPC; // should be a private io completion function inside us 492 APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); 493 if (!APCContext) 494 { 495 ERR("Not enough memory for APC Context\n"); 496 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesRead); 497 } 498 ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; 499 ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; 500 ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; 501 RecvInfo.AfdFlags |= AFD_SKIP_FIO; 502 } 503 504 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; 505 RecvInfo.AfdFlags |= AFD_OVERLAPPED; 506 } 507 508 IOSB->Status = STATUS_PENDING; 509 510 /* Send IOCTL */ 511 Status = NtDeviceIoControlFile((HANDLE)Handle, 512 Event, 513 APCFunction, 514 APCContext, 515 IOSB, 516 IOCTL_AFD_RECV_DATAGRAM, 517 &RecvInfo, 518 sizeof(RecvInfo), 519 NULL, 520 0); 521 522 /* Wait for completion of not overlapped */ 523 if (Status == STATUS_PENDING && lpOverlapped == NULL) 524 { 525 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infinitely for receive... 526 Status = IOSB->Status; 527 } 528 529 NtClose( SockEvent ); 530 531 if (Status == STATUS_PENDING) 532 { 533 TRACE("Leaving (Pending)\n"); 534 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesRead); 535 } 536 537 /* Return the Flags */ 538 *ReceiveFlags = 0; 539 540 switch (Status) 541 { 542 case STATUS_RECEIVE_EXPEDITED: 543 *ReceiveFlags = MSG_OOB; 544 break; 545 case STATUS_RECEIVE_PARTIAL_EXPEDITED: 546 *ReceiveFlags = MSG_PARTIAL | MSG_OOB; 547 break; 548 case STATUS_RECEIVE_PARTIAL: 549 *ReceiveFlags = MSG_PARTIAL; 550 break; 551 } 552 553 /* Re-enable Async Event */ 554 if (*ReceiveFlags & MSG_OOB) 555 { 556 SockReenableAsyncSelectEvent(Socket, FD_OOB); 557 } 558 else 559 { 560 SockReenableAsyncSelectEvent(Socket, FD_READ); 561 } 562 563 if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) 564 { 565 lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, *ReceiveFlags); 566 HeapFree(GlobalHeap, 0, (PVOID)APCContext); 567 } 568 569 return MsafdReturnWithErrno ( Status, lpErrno, IOSB->Information, lpNumberOfBytesRead ); 570 } 571 572 573 int 574 WSPAPI 575 WSPSend(SOCKET Handle, 576 LPWSABUF lpBuffers, 577 DWORD dwBufferCount, 578 LPDWORD lpNumberOfBytesSent, 579 DWORD iFlags, 580 LPWSAOVERLAPPED lpOverlapped, 581 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, 582 LPWSATHREADID lpThreadId, 583 LPINT lpErrno) 584 { 585 PIO_STATUS_BLOCK IOSB; 586 IO_STATUS_BLOCK DummyIOSB; 587 AFD_SEND_INFO SendInfo; 588 NTSTATUS Status; 589 PVOID APCContext; 590 PVOID APCFunction; 591 HANDLE Event = NULL; 592 HANDLE SockEvent; 593 PSOCKET_INFORMATION Socket; 594 595 /* Get the Socket Structure associate to this Socket*/ 596 Socket = GetSocketStructure(Handle); 597 if (!Socket) 598 { 599 if (lpErrno) 600 *lpErrno = WSAENOTSOCK; 601 return SOCKET_ERROR; 602 } 603 if (!lpNumberOfBytesSent && !lpOverlapped) 604 { 605 if (lpErrno) 606 *lpErrno = WSAEFAULT; 607 return SOCKET_ERROR; 608 } 609 610 Status = NtCreateEvent( &SockEvent, EVENT_ALL_ACCESS, 611 NULL, SynchronizationEvent, FALSE ); 612 613 if( !NT_SUCCESS(Status) ) 614 return -1; 615 616 TRACE("Called\n"); 617 618 /* Set up the Send Structure */ 619 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers; 620 SendInfo.BufferCount = dwBufferCount; 621 SendInfo.TdiFlags = 0; 622 SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; 623 624 /* Set the TDI Flags */ 625 if (iFlags) 626 { 627 if (iFlags & MSG_OOB) 628 { 629 SendInfo.TdiFlags |= TDI_SEND_EXPEDITED; 630 } 631 if (iFlags & MSG_PARTIAL) 632 { 633 SendInfo.TdiFlags |= TDI_SEND_PARTIAL; 634 } 635 } 636 637 /* Verify if we should use APC */ 638 if (lpOverlapped == NULL) 639 { 640 /* Not using Overlapped structure, so use normal blocking on event */ 641 APCContext = NULL; 642 APCFunction = NULL; 643 Event = SockEvent; 644 IOSB = &DummyIOSB; 645 } 646 else 647 { 648 /* Overlapped request for non overlapped opened socket */ 649 if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0) 650 { 651 TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n"); 652 return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent); 653 } 654 if (lpCompletionRoutine == NULL) 655 { 656 /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ 657 APCContext = lpOverlapped; 658 APCFunction = NULL; 659 Event = lpOverlapped->hEvent; 660 } 661 else 662 { 663 /* Using Overlapped Structure and a Completion Routine, so use an APC */ 664 APCFunction = &AfdAPC; // should be a private io completion function inside us 665 APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); 666 if (!APCContext) 667 { 668 ERR("Not enough memory for APC Context\n"); 669 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent); 670 } 671 ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; 672 ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; 673 ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; 674 SendInfo.AfdFlags |= AFD_SKIP_FIO; 675 } 676 677 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; 678 SendInfo.AfdFlags |= AFD_OVERLAPPED; 679 } 680 681 IOSB->Status = STATUS_PENDING; 682 683 /* Send IOCTL */ 684 Status = NtDeviceIoControlFile((HANDLE)Handle, 685 Event, 686 APCFunction, 687 APCContext, 688 IOSB, 689 IOCTL_AFD_SEND, 690 &SendInfo, 691 sizeof(SendInfo), 692 NULL, 693 0); 694 695 /* Wait for completion of not overlapped */ 696 if (Status == STATUS_PENDING && lpOverlapped == NULL) 697 { 698 WaitForSingleObject(SockEvent, INFINITE); // BUGBUG, shouldn wait infinitely for send... 699 Status = IOSB->Status; 700 } 701 702 NtClose( SockEvent ); 703 704 if (Status == STATUS_PENDING) 705 { 706 TRACE("Leaving (Pending)\n"); 707 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); 708 } 709 710 /* Re-enable Async Event */ 711 SockReenableAsyncSelectEvent(Socket, FD_WRITE); 712 713 TRACE("Leaving (Success, %d)\n", IOSB->Information); 714 715 if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) 716 { 717 lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0); 718 HeapFree(GlobalHeap, 0, (PVOID)APCContext); 719 } 720 721 return MsafdReturnWithErrno( Status, lpErrno, IOSB->Information, lpNumberOfBytesSent ); 722 } 723 724 int 725 WSPAPI 726 WSPSendTo(SOCKET Handle, 727 LPWSABUF lpBuffers, 728 DWORD dwBufferCount, 729 LPDWORD lpNumberOfBytesSent, 730 DWORD iFlags, 731 const struct sockaddr *SocketAddress, 732 int SocketAddressLength, 733 LPWSAOVERLAPPED lpOverlapped, 734 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, 735 LPWSATHREADID lpThreadId, 736 LPINT lpErrno) 737 { 738 PIO_STATUS_BLOCK IOSB; 739 IO_STATUS_BLOCK DummyIOSB; 740 AFD_SEND_INFO_UDP SendInfo; 741 NTSTATUS Status; 742 PVOID APCContext; 743 PVOID APCFunction; 744 HANDLE Event = NULL; 745 PTRANSPORT_ADDRESS RemoteAddress; 746 PSOCKADDR BindAddress = NULL; 747 INT BindAddressLength; 748 HANDLE SockEvent; 749 PSOCKET_INFORMATION Socket; 750 751 /* Get the Socket Structure associate to this Socket */ 752 Socket = GetSocketStructure(Handle); 753 if (!Socket) 754 { 755 if (lpErrno) 756 *lpErrno = WSAENOTSOCK; 757 return SOCKET_ERROR; 758 } 759 if (!lpNumberOfBytesSent && !lpOverlapped) 760 { 761 if (lpErrno) 762 *lpErrno = WSAEFAULT; 763 return SOCKET_ERROR; 764 } 765 766 if (!(Socket->SharedData->ServiceFlags1 & XP1_CONNECTIONLESS)) 767 { 768 /* Use WSPSend for connection-oriented sockets */ 769 return WSPSend(Handle, 770 lpBuffers, 771 dwBufferCount, 772 lpNumberOfBytesSent, 773 iFlags, 774 lpOverlapped, 775 lpCompletionRoutine, 776 lpThreadId, 777 lpErrno); 778 } 779 780 /* Bind us First */ 781 if (Socket->SharedData->State == SocketOpen) 782 { 783 /* Get the Wildcard Address */ 784 BindAddressLength = Socket->HelperData->MaxWSAddressLength; 785 BindAddress = HeapAlloc(GlobalHeap, 0, BindAddressLength); 786 if (!BindAddress) 787 { 788 MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL); 789 return INVALID_SOCKET; 790 } 791 792 Socket->HelperData->WSHGetWildcardSockaddr(Socket->HelperContext, 793 BindAddress, 794 &BindAddressLength); 795 /* Bind it */ 796 if (WSPBind(Handle, BindAddress, BindAddressLength, lpErrno) == SOCKET_ERROR) 797 return SOCKET_ERROR; 798 } 799 800 RemoteAddress = HeapAlloc(GlobalHeap, 0, 0x6 + SocketAddressLength); 801 if (!RemoteAddress) 802 { 803 if (BindAddress != NULL) 804 { 805 HeapFree(GlobalHeap, 0, BindAddress); 806 } 807 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, NULL); 808 } 809 810 Status = NtCreateEvent(&SockEvent, 811 EVENT_ALL_ACCESS, 812 NULL, SynchronizationEvent, FALSE); 813 814 if (!NT_SUCCESS(Status)) 815 { 816 HeapFree(GlobalHeap, 0, RemoteAddress); 817 if (BindAddress != NULL) 818 { 819 HeapFree(GlobalHeap, 0, BindAddress); 820 } 821 return SOCKET_ERROR; 822 } 823 824 /* Set up Address in TDI Format */ 825 RemoteAddress->TAAddressCount = 1; 826 RemoteAddress->Address[0].AddressLength = SocketAddressLength - sizeof(SocketAddress->sa_family); 827 RtlCopyMemory(&RemoteAddress->Address[0].AddressType, SocketAddress, SocketAddressLength); 828 829 /* Set up Structure */ 830 SendInfo.BufferArray = (PAFD_WSABUF)lpBuffers; 831 SendInfo.AfdFlags = Socket->SharedData->NonBlocking ? AFD_IMMEDIATE : 0; 832 SendInfo.BufferCount = dwBufferCount; 833 SendInfo.TdiConnection.RemoteAddress = RemoteAddress; 834 SendInfo.TdiConnection.RemoteAddressLength = Socket->HelperData->MaxTDIAddressLength; 835 836 /* Verify if we should use APC */ 837 if (lpOverlapped == NULL) 838 { 839 /* Not using Overlapped structure, so use normal blocking on event */ 840 APCContext = NULL; 841 APCFunction = NULL; 842 Event = SockEvent; 843 IOSB = &DummyIOSB; 844 } 845 else 846 { 847 /* Overlapped request for non overlapped opened socket */ 848 if ((Socket->SharedData->CreateFlags & SO_SYNCHRONOUS_NONALERT) != 0) 849 { 850 TRACE("Opened without flag WSA_FLAG_OVERLAPPED. Do nothing.\n"); 851 return MsafdReturnWithErrno(0, lpErrno, 0, lpNumberOfBytesSent); 852 } 853 if (lpCompletionRoutine == NULL) 854 { 855 /* Using Overlapped Structure, but no Completion Routine, so no need for APC */ 856 APCContext = lpOverlapped; 857 APCFunction = NULL; 858 Event = lpOverlapped->hEvent; 859 } 860 else 861 { 862 /* Using Overlapped Structure and a Completion Routine, so use an APC */ 863 APCFunction = &AfdAPC; // should be a private io completion function inside us 864 APCContext = HeapAlloc(GlobalHeap, 0, sizeof(AFDAPCCONTEXT)); 865 if (!APCContext) 866 { 867 ERR("Not enough memory for APC Context\n"); 868 return MsafdReturnWithErrno(STATUS_INSUFFICIENT_RESOURCES, lpErrno, 0, lpNumberOfBytesSent); 869 } 870 ((PAFDAPCCONTEXT)APCContext)->lpCompletionRoutine = lpCompletionRoutine; 871 ((PAFDAPCCONTEXT)APCContext)->lpOverlapped = lpOverlapped; 872 ((PAFDAPCCONTEXT)APCContext)->lpSocket = Socket; 873 SendInfo.AfdFlags |= AFD_SKIP_FIO; 874 } 875 876 IOSB = (PIO_STATUS_BLOCK)&lpOverlapped->Internal; 877 SendInfo.AfdFlags |= AFD_OVERLAPPED; 878 } 879 880 /* Send IOCTL */ 881 Status = NtDeviceIoControlFile((HANDLE)Handle, 882 Event, 883 APCFunction, 884 APCContext, 885 IOSB, 886 IOCTL_AFD_SEND_DATAGRAM, 887 &SendInfo, 888 sizeof(SendInfo), 889 NULL, 890 0); 891 892 /* Wait for completion of not overlapped */ 893 if (Status == STATUS_PENDING && lpOverlapped == NULL) 894 { 895 /* BUGBUG, shouldn't wait infinitely for send... */ 896 WaitForSingleObject(SockEvent, INFINITE); 897 Status = IOSB->Status; 898 } 899 900 NtClose(SockEvent); 901 HeapFree(GlobalHeap, 0, RemoteAddress); 902 if (BindAddress != NULL) 903 { 904 HeapFree(GlobalHeap, 0, BindAddress); 905 } 906 907 if (Status == STATUS_PENDING) 908 { 909 TRACE("Leaving (Pending)\n"); 910 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); 911 } 912 913 SockReenableAsyncSelectEvent(Socket, FD_WRITE); 914 915 if (Status == STATUS_SUCCESS && lpOverlapped && lpCompletionRoutine) 916 { 917 lpCompletionRoutine(Status, IOSB->Information, lpOverlapped, 0); 918 HeapFree(GlobalHeap, 0, (PVOID)APCContext); 919 } 920 921 return MsafdReturnWithErrno(Status, lpErrno, IOSB->Information, lpNumberOfBytesSent); 922 } 923 924 INT 925 WSPAPI 926 WSPRecvDisconnect(IN SOCKET s, 927 OUT LPWSABUF lpInboundDisconnectData, 928 OUT LPINT lpErrno) 929 { 930 UNIMPLEMENTED; 931 return 0; 932 } 933 934 935 936 INT 937 WSPAPI 938 WSPSendDisconnect(IN SOCKET s, 939 IN LPWSABUF lpOutboundDisconnectData, 940 OUT LPINT lpErrno) 941 { 942 UNIMPLEMENTED; 943 return 0; 944 } 945 946 /* EOF */ 947