1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS WinSock 2 API 4 * FILE: dll/win32/ws2_32/src/async.c 5 * PURPOSE: Async Block Object and Async Thread Management 6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ws2_32.h> 12 13 /* DATA **********************************************************************/ 14 15 BOOLEAN WsAsyncThreadInitialized; 16 LONG WsAsyncTaskHandle; 17 PLIST_ENTRY WsAsyncQueue; 18 CRITICAL_SECTION WsAsyncCritSect; 19 HANDLE WsAsyncEvent; 20 HANDLE WsAsyncCurrentTaskHandle; 21 HANDLE WsAsyncCancelledTaskHandle; 22 HINSTANCE WsAsyncDllHandle; 23 24 #define WsAsyncLock() EnterCriticalSection(&WsAsyncCritSect) 25 #define WsAsyncUnlock() LeaveCriticalSection(&WsAsyncCritSect) 26 27 /* FUNCTIONS *****************************************************************/ 28 29 VOID 30 WSAAPI 31 WsAsyncGlobalInitialize(VOID) 32 { 33 /* Initialize the async lock */ 34 InitializeCriticalSection(&WsAsyncCritSect); 35 } 36 37 VOID 38 WSAAPI 39 WsAsyncGlobalTerminate(VOID) 40 { 41 /* Destroy the async lock */ 42 DeleteCriticalSection(&WsAsyncCritSect); 43 } 44 45 46 SIZE_T 47 WSAAPI 48 BytesInHostent(PHOSTENT Hostent) 49 { 50 SIZE_T Bytes; 51 INT i; 52 53 /* Start with the static stuff */ 54 Bytes = sizeof(HOSTENT) + strlen(Hostent->h_name) + sizeof(CHAR); 55 56 /* Add 2 pointers for the list-terminators */ 57 Bytes += 2 * sizeof(ULONG_PTR); 58 59 /* Now loop for the aliases */ 60 for (i = 0; Hostent->h_aliases[i]; i++) 61 { 62 /* Add the alias size, plus the space its pointer takes */ 63 Bytes += strlen(Hostent->h_aliases[i]) + sizeof(CHAR) + sizeof(ULONG_PTR); 64 } 65 66 /* Now loop for the hostnames */ 67 for (i = 0; Hostent->h_addr_list[i]; i++) 68 { 69 /* Add the alias size, plus the space its pointer takes */ 70 Bytes += Hostent->h_length + sizeof(ULONG_PTR); 71 } 72 73 /* Align to 8 bytes */ 74 return (Bytes + 7) & ~7; 75 } 76 77 SIZE_T 78 WSAAPI 79 BytesInServent(PSERVENT Servent) 80 { 81 SIZE_T Bytes; 82 INT i; 83 84 /* Start with the static stuff */ 85 Bytes = sizeof(SERVENT) + 86 strlen(Servent->s_name) + sizeof(CHAR) + 87 strlen(Servent->s_proto) + sizeof(CHAR); 88 89 /* Add 1 pointers for the list terminator */ 90 Bytes += sizeof(ULONG_PTR); 91 92 /* Now loop for the aliases */ 93 for (i = 0; Servent->s_aliases[i]; i++) 94 { 95 /* Add the alias size, plus the space its pointer takes */ 96 Bytes += strlen(Servent->s_aliases[i]) + sizeof(CHAR) + sizeof(ULONG_PTR); 97 } 98 99 /* return */ 100 return Bytes; 101 } 102 103 SIZE_T 104 WSAAPI 105 BytesInProtoent(PPROTOENT Protoent) 106 { 107 SIZE_T Bytes; 108 INT i; 109 110 /* Start with the static stuff */ 111 Bytes = sizeof(SERVENT) + strlen(Protoent->p_name) + sizeof(CHAR); 112 113 /* Add 1 pointers for the list terminator */ 114 Bytes += sizeof(ULONG_PTR); 115 116 /* Now loop for the aliases */ 117 for (i = 0; Protoent->p_aliases[i]; i++) 118 { 119 /* Add the alias size, plus the space its pointer takes */ 120 Bytes += strlen(Protoent->p_aliases[i]) + sizeof(CHAR) + sizeof(ULONG_PTR); 121 } 122 123 /* return */ 124 return Bytes; 125 } 126 127 SIZE_T 128 WSAAPI 129 CopyHostentToBuffer(IN PCHAR Buffer, 130 IN INT BufferLength, 131 IN PHOSTENT Hostent) 132 { 133 SIZE_T BufferSize, CurrentSize, NameSize; 134 PCHAR p = Buffer; 135 DWORD Aliases = 0, Names = 0; 136 DWORD i; 137 PHOSTENT ReturnedHostent = (PHOSTENT)Buffer; 138 139 /* Determine the buffer size required */ 140 BufferSize = BytesInHostent(Hostent); 141 142 /* Check which size to use */ 143 if ((DWORD)BufferLength > BufferSize) 144 { 145 /* Zero the buffer */ 146 RtlZeroMemory(Buffer, BufferSize); 147 } 148 else 149 { 150 /* Zero the buffer */ 151 RtlZeroMemory(Buffer, BufferLength); 152 } 153 154 /* Start with the raw Hostent */ 155 CurrentSize = sizeof(HOSTENT); 156 157 /* Return the size needed now */ 158 if (CurrentSize > (DWORD)BufferLength) return BufferSize; 159 160 /* Copy the Hostent and initialize it */ 161 CopyMemory(p, Hostent, sizeof(HOSTENT)); 162 p = Buffer + CurrentSize; 163 ReturnedHostent->h_name = NULL; 164 ReturnedHostent->h_aliases = NULL; 165 ReturnedHostent->h_addr_list = NULL; 166 167 /* Find out how many aliases there are */ 168 while (Hostent->h_aliases[Aliases]) 169 { 170 /* Increase the alias count */ 171 Aliases++; 172 } 173 174 /* Add the aliases to the size, and validate it */ 175 CurrentSize += (Aliases + 1) * sizeof(ULONG_PTR); 176 if (CurrentSize > (DWORD)BufferLength) 177 { 178 /* Clear the aliases and return */ 179 Hostent->h_aliases = NULL; 180 return BufferSize; 181 } 182 183 /* Write the aliases, update the pointer */ 184 ReturnedHostent->h_aliases = (PCHAR*)p; 185 p = Buffer + CurrentSize; 186 187 /* Find out how many names there are */ 188 while (Hostent->h_addr_list[Names]) 189 { 190 /* Increase the alias count */ 191 Names++; 192 } 193 194 /* Add the names to the size, and validate it */ 195 CurrentSize += (Names + 1) * sizeof(ULONG_PTR); 196 if (CurrentSize > (DWORD)BufferLength) 197 { 198 /* Clear the aliases and return */ 199 Hostent->h_addr_list = NULL; 200 return BufferSize; 201 } 202 203 /* Write the names, update the pointer */ 204 ReturnedHostent->h_addr_list = (PCHAR*)p; 205 p = Buffer + CurrentSize; 206 207 /* Now add the names */ 208 for (i = 0; i < Names; i++) 209 { 210 /* Update size and validate */ 211 CurrentSize += Hostent->h_length; 212 if (CurrentSize > (DWORD)BufferLength) return BufferSize; 213 214 /* Write pointer and copy */ 215 ReturnedHostent->h_addr_list[i] = p; 216 CopyMemory(p, Hostent->h_addr_list[i], Hostent->h_length); 217 218 /* Update pointer */ 219 p = Buffer + CurrentSize; 220 } 221 222 /* Finalize the list */ 223 ReturnedHostent->h_addr_list[i] = NULL; 224 225 /* Add the service name to the size, and validate it */ 226 NameSize = strlen(Hostent->h_name) + sizeof(CHAR); 227 CurrentSize += NameSize; 228 if (CurrentSize > (DWORD)BufferLength) return BufferSize; 229 230 /* Write the service name and update the pointer */ 231 ReturnedHostent->h_name = p; 232 CopyMemory(p, Hostent->h_name, NameSize); 233 p = Buffer + CurrentSize; 234 235 /* Now add the aliases */ 236 for (i = 0; i < Aliases; i++) 237 { 238 /* Update size and validate */ 239 NameSize = strlen(Hostent->h_aliases[i]) + sizeof(CHAR); 240 CurrentSize += NameSize; 241 if (CurrentSize > (DWORD)BufferLength) return BufferSize; 242 243 /* Write pointer and copy */ 244 ReturnedHostent->h_aliases[i] = p; 245 CopyMemory(p, Hostent->h_aliases[i], NameSize); 246 247 /* Update pointer */ 248 p = Buffer + CurrentSize; 249 } 250 251 /* Finalize the list and return */ 252 ReturnedHostent->h_aliases[i] = NULL; 253 return BufferSize; 254 } 255 256 SIZE_T 257 WSAAPI 258 CopyServentToBuffer(IN PCHAR Buffer, 259 IN INT BufferLength, 260 IN PSERVENT Servent) 261 { 262 SIZE_T BufferSize, CurrentSize, NameSize; 263 PCHAR p = Buffer; 264 DWORD Aliases = 0; 265 DWORD i; 266 PSERVENT ReturnedServent = (PSERVENT)Buffer; 267 268 /* Determine the buffer size required */ 269 BufferSize = BytesInServent(Servent); 270 271 /* Check which size to use */ 272 if ((DWORD)BufferLength > BufferSize) 273 { 274 /* Zero the buffer */ 275 ZeroMemory(Buffer, BufferSize); 276 } 277 else 278 { 279 /* Zero the buffer */ 280 ZeroMemory(Buffer, BufferLength); 281 } 282 283 /* Start with the raw servent */ 284 CurrentSize = sizeof(SERVENT); 285 286 /* Return the size needed now */ 287 if (CurrentSize > (DWORD)BufferLength) return BufferSize; 288 289 /* Copy the servent and initialize it */ 290 CopyMemory(p, Servent, sizeof(SERVENT)); 291 p = Buffer + CurrentSize; 292 ReturnedServent->s_name = NULL; 293 ReturnedServent->s_aliases = NULL; 294 ReturnedServent->s_proto = NULL; 295 296 /* Find out how many aliases there are */ 297 while (Servent->s_aliases[Aliases]) 298 { 299 /* Increase the alias count */ 300 Aliases++; 301 } 302 303 /* Add the aliases to the size, and validate it */ 304 CurrentSize += (Aliases + 1) * sizeof(ULONG_PTR); 305 if (CurrentSize > (DWORD)BufferLength) 306 { 307 /* Clear the aliases and return */ 308 Servent->s_aliases = NULL; 309 return BufferSize; 310 } 311 312 /* Write the aliases, update the pointer */ 313 ReturnedServent->s_aliases = (PCHAR*)p; 314 p = Buffer + CurrentSize; 315 316 /* Add the service name to the size, and validate it */ 317 NameSize = strlen(Servent->s_name) + sizeof(CHAR); 318 CurrentSize += NameSize; 319 if (CurrentSize > (DWORD)BufferLength) return BufferSize; 320 321 /* Write the service name and update the pointer */ 322 ReturnedServent->s_name = p; 323 CopyMemory(p, Servent->s_name, NameSize); 324 p = Buffer + CurrentSize; 325 326 /* Now add the aliases */ 327 for (i = 0; i < Aliases; i++) 328 { 329 /* Update size and validate */ 330 NameSize = strlen(Servent->s_aliases[i]) + sizeof(CHAR); 331 CurrentSize += NameSize; 332 if (CurrentSize > (DWORD)BufferLength) return BufferSize; 333 334 /* Write pointer and copy */ 335 ReturnedServent->s_aliases[i] = p; 336 CopyMemory(p, Servent->s_aliases[i], NameSize); 337 338 /* Update pointer */ 339 p = Buffer + CurrentSize; 340 } 341 342 /* Finalize the list and return */ 343 ReturnedServent->s_aliases[i] = NULL; 344 return BufferSize; 345 } 346 347 SIZE_T 348 WSAAPI 349 CopyProtoentToBuffer(IN PCHAR Buffer, 350 IN INT BufferLength, 351 IN PPROTOENT Protoent) 352 { 353 SIZE_T BufferSize, CurrentSize, NameSize; 354 PCHAR p = Buffer; 355 DWORD Aliases = 0; 356 DWORD i; 357 PPROTOENT ReturnedProtoent = (PPROTOENT)Buffer; 358 359 /* Determine the buffer size required */ 360 BufferSize = BytesInProtoent(Protoent); 361 362 /* Check which size to use */ 363 if ((DWORD)BufferLength > BufferSize) 364 { 365 /* Zero the buffer */ 366 ZeroMemory(Buffer, BufferSize); 367 } 368 else 369 { 370 /* Zero the buffer */ 371 ZeroMemory(Buffer, BufferLength); 372 } 373 374 /* Start with the raw servent */ 375 CurrentSize = sizeof(PROTOENT); 376 377 /* Return the size needed now */ 378 if (CurrentSize > (DWORD)BufferLength) return BufferSize; 379 380 /* Copy the servent and initialize it */ 381 CopyMemory(p, Protoent, sizeof(PROTOENT)); 382 p = Buffer + CurrentSize; 383 ReturnedProtoent->p_name = NULL; 384 ReturnedProtoent->p_aliases = NULL; 385 386 /* Find out how many aliases there are */ 387 while (Protoent->p_aliases[Aliases]) 388 { 389 /* Increase the alias count */ 390 Aliases++; 391 } 392 393 /* Add the aliases to the size, and validate it */ 394 CurrentSize += (Aliases + 1) * sizeof(ULONG_PTR); 395 if (CurrentSize > (DWORD)BufferLength) 396 { 397 /* Clear the aliases and return */ 398 Protoent->p_aliases = NULL; 399 return BufferSize; 400 } 401 402 /* Write the aliases, update the pointer */ 403 ReturnedProtoent->p_aliases = (PCHAR*)p; 404 p = Buffer + CurrentSize; 405 406 /* Add the service name to the size, and validate it */ 407 NameSize = strlen(Protoent->p_name) + sizeof(CHAR); 408 CurrentSize += NameSize; 409 if (CurrentSize > (DWORD)BufferLength) return BufferSize; 410 411 /* Write the service name and update the pointer */ 412 ReturnedProtoent->p_name = p; 413 CopyMemory(p, Protoent->p_name, NameSize); 414 p = Buffer + CurrentSize; 415 416 /* Now add the aliases */ 417 for (i = 0; i < Aliases; i++) 418 { 419 /* Update size and validate */ 420 NameSize = strlen(Protoent->p_aliases[i]) + sizeof(CHAR); 421 CurrentSize += NameSize; 422 if (CurrentSize > (DWORD)BufferLength) return BufferSize; 423 424 /* Write pointer and copy */ 425 ReturnedProtoent->p_aliases[i] = p; 426 CopyMemory(p, Protoent->p_aliases[i], NameSize); 427 428 /* Update pointer */ 429 p = Buffer + CurrentSize; 430 } 431 432 /* Finalize the list and return */ 433 ReturnedProtoent->p_aliases[i] = NULL; 434 return BufferSize; 435 } 436 437 PWSASYNCBLOCK 438 WSAAPI 439 WsAsyncAllocateBlock(IN SIZE_T ExtraLength) 440 { 441 PWSASYNCBLOCK AsyncBlock; 442 443 /* Add the size of the block */ 444 ExtraLength += sizeof(WSASYNCBLOCK); 445 446 /* Allocate it */ 447 AsyncBlock = HeapAlloc(WsSockHeap, 0, ExtraLength); 448 449 /* Get a handle to it */ 450 AsyncBlock->TaskHandle = UlongToPtr(InterlockedIncrement(&WsAsyncTaskHandle)); 451 452 /* Return it */ 453 return AsyncBlock; 454 } 455 456 BOOL 457 WINAPI 458 WsAsyncThreadBlockingHook(VOID) 459 { 460 /* Check if this task is being cancelled */ 461 if (WsAsyncCurrentTaskHandle == WsAsyncCancelledTaskHandle) 462 { 463 /* Cancel the blocking call so we can get back */ 464 WSACancelBlockingCall(); 465 } 466 467 /* Return to system */ 468 return FALSE; 469 } 470 471 VOID 472 WSAAPI 473 WsAsyncFreeBlock(IN PWSASYNCBLOCK AsyncBlock) 474 { 475 /* Free it */ 476 HeapFree(WsSockHeap, 0, AsyncBlock); 477 } 478 479 VOID 480 WSAAPI 481 WsAsyncGetServ(IN HANDLE TaskHandle, 482 IN DWORD Operation, 483 IN HWND hWnd, 484 IN UINT wMsg, 485 IN CHAR FAR *ByWhat, 486 IN CHAR FAR *Protocol, 487 IN CHAR FAR *Buffer, 488 IN INT BufferLength) 489 { 490 PSERVENT Servent; 491 SIZE_T BufferSize = 0; 492 LPARAM lParam; 493 INT ErrorCode = 0; 494 495 /* Check the operation */ 496 if (Operation == WsAsyncGetServByName) 497 { 498 /* Call the API */ 499 Servent = getservbyname(ByWhat, Protocol); 500 } 501 else 502 { 503 /* Call the API */ 504 Servent = getservbyport(PtrToUlong(ByWhat), Protocol); 505 } 506 507 /* Make sure we got one */ 508 if (!Servent) ErrorCode = GetLastError(); 509 510 /* Acquire the lock */ 511 WsAsyncLock(); 512 513 /* Check if this task got cancelled */ 514 if (TaskHandle == WsAsyncCancelledTaskHandle) 515 { 516 /* Return */ 517 WsAsyncUnlock(); 518 return; 519 } 520 521 /* If we got a Servent back, copy it */ 522 if (Servent) 523 { 524 /* Copy it into the buffer */ 525 BufferSize = CopyServentToBuffer(Buffer, BufferLength, Servent); 526 527 /* Check if we had enough space */ 528 if (BufferSize > (DWORD)BufferLength) 529 { 530 /* Not enough */ 531 ErrorCode = WSAENOBUFS; 532 } 533 else 534 { 535 /* Perfect */ 536 ErrorCode = NO_ERROR; 537 } 538 } 539 540 /* Not processing anymore */ 541 WsAsyncCurrentTaskHandle = NULL; 542 543 /* Release the lock */ 544 WsAsyncUnlock(); 545 546 /* Make the messed-up lParam reply */ 547 lParam = WSAMAKEASYNCREPLY(BufferSize, ErrorCode); 548 549 /* Sent it through the Upcall API */ 550 WPUPostMessage(hWnd, wMsg, (WPARAM)TaskHandle, lParam); 551 } 552 553 VOID 554 WSAAPI 555 WsAsyncGetProto(IN HANDLE TaskHandle, 556 IN DWORD Operation, 557 IN HWND hWnd, 558 IN UINT wMsg, 559 IN CHAR FAR *ByWhat, 560 IN CHAR FAR *Buffer, 561 IN INT BufferLength) 562 { 563 PPROTOENT Protoent; 564 SIZE_T BufferSize = 0; 565 LPARAM lParam; 566 INT ErrorCode = 0; 567 568 /* Check the operation */ 569 if (Operation == WsAsyncGetProtoByName) 570 { 571 /* Call the API */ 572 Protoent = getprotobyname(ByWhat); 573 } 574 else 575 { 576 /* Call the API */ 577 Protoent = getprotobynumber(PtrToUlong(ByWhat)); 578 } 579 580 /* Make sure we got one */ 581 if (!Protoent) ErrorCode = GetLastError(); 582 583 /* Acquire the lock */ 584 WsAsyncLock(); 585 586 /* Check if this task got cancelled */ 587 if (TaskHandle == WsAsyncCancelledTaskHandle) 588 { 589 /* Return */ 590 WsAsyncUnlock(); 591 return; 592 } 593 594 /* If we got a Servent back, copy it */ 595 if (Protoent) 596 { 597 /* Copy it into the buffer */ 598 BufferSize = CopyProtoentToBuffer(Buffer, BufferLength, Protoent); 599 600 /* Check if we had enough space */ 601 if (BufferSize > (DWORD)BufferLength) 602 { 603 /* Not enough */ 604 ErrorCode = WSAENOBUFS; 605 } 606 else 607 { 608 /* Perfect */ 609 ErrorCode = NO_ERROR; 610 } 611 } 612 613 /* Not processing anymore */ 614 WsAsyncCurrentTaskHandle = NULL; 615 616 /* Release the lock */ 617 WsAsyncUnlock(); 618 619 /* Make the messed-up lParam reply */ 620 lParam = WSAMAKEASYNCREPLY(BufferSize, ErrorCode); 621 622 /* Sent it through the Upcall API */ 623 WPUPostMessage(hWnd, wMsg, (WPARAM)TaskHandle, lParam); 624 } 625 626 VOID 627 WSAAPI 628 WsAsyncGetHost(IN HANDLE TaskHandle, 629 IN DWORD Operation, 630 IN HWND hWnd, 631 IN UINT wMsg, 632 IN CHAR FAR *ByWhat, 633 IN INT Length, 634 IN INT Type, 635 IN CHAR FAR *Buffer, 636 IN INT BufferLength) 637 { 638 PHOSTENT Hostent; 639 SIZE_T BufferSize = 0; 640 LPARAM lParam; 641 INT ErrorCode = 0; 642 643 /* Check the operation */ 644 if (Operation == WsAsyncGetHostByAddr) 645 { 646 /* Call the API */ 647 Hostent = gethostbyaddr(ByWhat, Length, Type); 648 } 649 else 650 { 651 /* Call the API */ 652 Hostent = gethostbyname(ByWhat); 653 } 654 655 /* Make sure we got one */ 656 if (!Hostent) ErrorCode = GetLastError(); 657 658 /* Acquire the lock */ 659 WsAsyncLock(); 660 661 /* Check if this task got cancelled */ 662 if (TaskHandle == WsAsyncCancelledTaskHandle) 663 { 664 /* Return */ 665 WsAsyncUnlock(); 666 return; 667 } 668 669 /* If we got a Servent back, copy it */ 670 if (Hostent) 671 { 672 /* Copy it into the buffer */ 673 BufferSize = CopyHostentToBuffer(Buffer, BufferLength, Hostent); 674 675 /* Check if we had enough space */ 676 if (BufferSize > (DWORD)BufferLength) 677 { 678 /* Not enough */ 679 ErrorCode = WSAENOBUFS; 680 } 681 else 682 { 683 /* Perfect */ 684 ErrorCode = NO_ERROR; 685 } 686 } 687 688 /* Not processing anymore */ 689 WsAsyncCurrentTaskHandle = NULL; 690 691 /* Release the lock */ 692 WsAsyncUnlock(); 693 694 /* Make the messed-up lParam reply */ 695 lParam = WSAMAKEASYNCREPLY(BufferSize, ErrorCode); 696 697 /* Sent it through the Upcall API */ 698 WPUPostMessage(hWnd, wMsg, (WPARAM)TaskHandle, lParam); 699 } 700 701 DWORD 702 WINAPI 703 WsAsyncThread(IN PVOID ThreadContext) 704 { 705 PWSASYNCCONTEXT Context = ThreadContext; 706 PWSASYNCBLOCK AsyncBlock; 707 PLIST_ENTRY Entry; 708 HANDLE AsyncEvent = Context->AsyncEvent; 709 PLIST_ENTRY ListHead = &Context->AsyncQueue; 710 711 /* Set the blocking hook */ 712 WSASetBlockingHook((FARPROC)WsAsyncThreadBlockingHook); 713 714 /* Loop */ 715 while (TRUE) 716 { 717 /* Wait for the event */ 718 WaitForSingleObject(AsyncEvent, INFINITE); 719 720 /* Get the lock */ 721 WsAsyncLock(); 722 723 /* Process the queue */ 724 while (!IsListEmpty(ListHead)) 725 { 726 /* Remove this entry and get the async block */ 727 Entry = RemoveHeadList(ListHead); 728 AsyncBlock = CONTAINING_RECORD(Entry, WSASYNCBLOCK, AsyncQueue); 729 730 /* Save the current task handle */ 731 WsAsyncCurrentTaskHandle = AsyncBlock->TaskHandle; 732 733 /* Release the lock */ 734 WsAsyncUnlock(); 735 736 /* Check which operation to do */ 737 switch (AsyncBlock->Operation) 738 { 739 /* Get Host by Y */ 740 case WsAsyncGetHostByAddr: case WsAsyncGetHostByName: 741 742 /* Call the handler */ 743 WsAsyncGetHost(AsyncBlock->TaskHandle, 744 AsyncBlock->Operation, 745 AsyncBlock->GetHost.hWnd, 746 AsyncBlock->GetHost.wMsg, 747 AsyncBlock->GetHost.ByWhat, 748 AsyncBlock->GetHost.Length, 749 AsyncBlock->GetHost.Type, 750 AsyncBlock->GetHost.Buffer, 751 AsyncBlock->GetHost.BufferLength); 752 break; 753 754 /* Get Proto by Y */ 755 case WsAsyncGetProtoByNumber: case WsAsyncGetProtoByName: 756 757 /* Call the handler */ 758 WsAsyncGetProto(AsyncBlock->TaskHandle, 759 AsyncBlock->Operation, 760 AsyncBlock->GetProto.hWnd, 761 AsyncBlock->GetProto.wMsg, 762 AsyncBlock->GetHost.ByWhat, 763 AsyncBlock->GetProto.Buffer, 764 AsyncBlock->GetProto.BufferLength); 765 break; 766 767 /* Get Serv by Y */ 768 case WsAsyncGetServByPort: case WsAsyncGetServByName: 769 770 /* Call the handler */ 771 WsAsyncGetServ(AsyncBlock->TaskHandle, 772 AsyncBlock->Operation, 773 AsyncBlock->GetServ.hWnd, 774 AsyncBlock->GetServ.wMsg, 775 AsyncBlock->GetServ.ByWhat, 776 AsyncBlock->GetServ.Protocol, 777 AsyncBlock->GetServ.Buffer, 778 AsyncBlock->GetServ.BufferLength); 779 break; 780 781 /* Termination */ 782 case WsAsyncTerminate: 783 784 /* Clean up the extra reference */ 785 WSACleanup(); 786 787 /* Free the context block */ 788 WsAsyncFreeBlock(AsyncBlock); 789 790 /* Acquire the lock */ 791 WsAsyncLock(); 792 793 /* Loop the queue and flush it */ 794 while (!IsListEmpty(ListHead)) 795 { 796 Entry = RemoveHeadList(ListHead); 797 AsyncBlock = CONTAINING_RECORD(Entry, 798 WSASYNCBLOCK, 799 AsyncQueue); 800 WsAsyncFreeBlock(AsyncBlock); 801 } 802 803 /* Release lock */ 804 WsAsyncUnlock(); 805 806 /* Close the event, free the Context */ 807 CloseHandle(AsyncEvent); 808 HeapFree(WsSockHeap, 0, Context); 809 810 /* Remove the extra DLL reference and kill us */ 811 FreeLibraryAndExitThread(WsAsyncDllHandle, 0); 812 813 default: 814 break; 815 } 816 817 /* Done processing */ 818 WsAsyncCurrentTaskHandle = NULL; 819 820 /* Free this block, get lock and reloop */ 821 WsAsyncFreeBlock(AsyncBlock); 822 WsAsyncLock(); 823 } 824 825 /* Release the lock */ 826 WsAsyncUnlock(); 827 } 828 } 829 830 BOOL 831 WSAAPI 832 WsAsyncCheckAndInitThread(VOID) 833 { 834 HANDLE ThreadHandle; 835 DWORD Tid; 836 PWSASYNCCONTEXT Context = NULL; 837 WSADATA WsaData; 838 839 /* Make sure we're not initialized */ 840 if (WsAsyncThreadInitialized) return TRUE; 841 842 /* Acquire the lock */ 843 WsAsyncLock(); 844 845 /* Make sure we're not initialized */ 846 if (!WsAsyncThreadInitialized) 847 { 848 /* Initialize Thread Context */ 849 Context = HeapAlloc(WsSockHeap, 0, sizeof(*Context)); 850 if (!Context) 851 goto Exit; 852 853 /* Initialize the Queue and event */ 854 WsAsyncQueue = &Context->AsyncQueue; 855 InitializeListHead(WsAsyncQueue); 856 Context->AsyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 857 WsAsyncEvent = Context->AsyncEvent; 858 859 /* Prevent us from ever being killed while running */ 860 if (WSAStartup(MAKEWORD(2,2), &WsaData) != ERROR_SUCCESS) 861 goto Fail; 862 863 /* Create the thread */ 864 ThreadHandle = CreateThread(NULL, 865 0, 866 WsAsyncThread, 867 Context, 868 0, 869 &Tid); 870 if (ThreadHandle == NULL) 871 { 872 /* Cleanup and fail */ 873 WSACleanup(); 874 goto Fail; 875 } 876 877 /* Close the handle and set init */ 878 CloseHandle(ThreadHandle); 879 WsAsyncThreadInitialized = TRUE; 880 } 881 882 Exit: 883 /* Release the lock */ 884 WsAsyncUnlock(); 885 return WsAsyncThreadInitialized; 886 887 Fail: 888 /* Close the event, free the Context */ 889 if (Context->AsyncEvent) 890 CloseHandle(Context->AsyncEvent); 891 HeapFree(WsSockHeap, 0, Context); 892 893 /* Bail out */ 894 goto Exit; 895 } 896 897 VOID 898 WSAAPI 899 WsAsyncTerminateThread(VOID) 900 { 901 PWSASYNCBLOCK AsyncBlock; 902 903 /* Make sure we're initialized */ 904 if (!WsAsyncThreadInitialized) return; 905 906 /* Allocate a block */ 907 AsyncBlock = WsAsyncAllocateBlock(0); 908 909 /* Initialize it for termination */ 910 AsyncBlock->Operation = WsAsyncTerminate; 911 912 /* Queue the request and return */ 913 WsAsyncQueueRequest(AsyncBlock); 914 WsAsyncThreadInitialized = FALSE; 915 } 916 917 VOID 918 WSAAPI 919 WsAsyncQueueRequest(IN PWSASYNCBLOCK AsyncBlock) 920 { 921 /* Get the lock */ 922 WsAsyncLock(); 923 924 /* Insert it into the queue */ 925 InsertTailList(WsAsyncQueue, &AsyncBlock->AsyncQueue); 926 927 /* Wake up the thread */ 928 SetEvent(WsAsyncEvent); 929 930 /* Release lock and return */ 931 WsAsyncUnlock(); 932 } 933 934 INT 935 WSAAPI 936 WsAsyncCancelRequest(IN HANDLE TaskHandle) 937 { 938 PLIST_ENTRY Entry; 939 PWSASYNCBLOCK AsyncBlock; 940 941 /* Make sure we're initialized */ 942 if (!WsAsyncThreadInitialized) return WSAEINVAL; 943 944 /* Acquire the lock */ 945 WsAsyncLock(); 946 947 /* Check if we're cancelling the current task */ 948 if (TaskHandle == WsAsyncCurrentTaskHandle) 949 { 950 /* Mark us as cancelled, the async thread will see this later */ 951 WsAsyncCancelledTaskHandle = TaskHandle; 952 953 /* Release lock and return */ 954 WsAsyncUnlock(); 955 return NO_ERROR; 956 } 957 958 /* Loop the queue */ 959 Entry = WsAsyncQueue->Flink; 960 while (Entry != WsAsyncQueue) 961 { 962 /* Get the Async Block */ 963 AsyncBlock = CONTAINING_RECORD(Entry, WSASYNCBLOCK, AsyncQueue); 964 965 /* Check if this is the one */ 966 if (TaskHandle == AsyncBlock->TaskHandle) 967 { 968 /* It is, remove it */ 969 RemoveEntryList(Entry); 970 971 /* Release the lock, free the block, and return */ 972 WsAsyncUnlock(); 973 WsAsyncFreeBlock(AsyncBlock); 974 return NO_ERROR; 975 } 976 977 /* Move to the next entry */ 978 Entry = Entry->Flink; 979 } 980 981 /* Nothing found, fail */ 982 WsAsyncUnlock(); 983 return WSAEINVAL; 984 } 985