4b3cdd4f25737965c74d3ffaf014a1713f99f731
[reactos.git] / reactos / dll / win32 / ws2_32 / src / async.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WinSock 2 API
4 * FILE: dll/win32/ws2_32_new/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
851 /* Initialize the Queue and event */
852 WsAsyncQueue = &Context->AsyncQueue;
853 InitializeListHead(WsAsyncQueue);
854 Context->AsyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
855 WsAsyncEvent = Context->AsyncEvent;
856
857 /* Prevent us from ever being killed while running */
858 WSAStartup(MAKEWORD(2,2), &WsaData);
859
860 /* Create the thread */
861 ThreadHandle = CreateThread(NULL,
862 0,
863 WsAsyncThread,
864 Context,
865 0,
866 &Tid);
867
868 /* Close the handle and set init */
869 CloseHandle(ThreadHandle);
870 WsAsyncThreadInitialized = TRUE;
871 }
872
873 /* Release the lock */
874 WsAsyncUnlock();
875 return WsAsyncThreadInitialized;
876 }
877
878 VOID
879 WSAAPI
880 WsAsyncTerminateThread(VOID)
881 {
882 PWSASYNCBLOCK AsyncBlock;
883
884 /* Make sure we're initialized */
885 if (!WsAsyncThreadInitialized) return;
886
887 /* Allocate a block */
888 AsyncBlock = WsAsyncAllocateBlock(0);
889
890 /* Initialize it for termination */
891 AsyncBlock->Operation = WsAsyncTerminate;
892
893 /* Queue the request and return */
894 WsAsyncQueueRequest(AsyncBlock);
895 WsAsyncThreadInitialized = FALSE;
896 }
897
898 VOID
899 WSAAPI
900 WsAsyncQueueRequest(IN PWSASYNCBLOCK AsyncBlock)
901 {
902 /* Get the lock */
903 WsAsyncLock();
904
905 /* Insert it into the queue */
906 InsertTailList(WsAsyncQueue, &AsyncBlock->AsyncQueue);
907
908 /* Wake up the thread */
909 SetEvent(WsAsyncEvent);
910
911 /* Release lock and return */
912 WsAsyncUnlock();
913 }
914
915 INT
916 WSAAPI
917 WsAsyncCancelRequest(IN HANDLE TaskHandle)
918 {
919 PLIST_ENTRY Entry;
920 PWSASYNCBLOCK AsyncBlock;
921
922 /* Make sure we're initialized */
923 if (!WsAsyncThreadInitialized) return WSAEINVAL;
924
925 /* Acquire the lock */
926 WsAsyncLock();
927
928 /* Check if we're cancelling the current task */
929 if (TaskHandle == WsAsyncCurrentTaskHandle)
930 {
931 /* Mark us as cancelled, the async thread will see this later */
932 WsAsyncCancelledTaskHandle = TaskHandle;
933
934 /* Release lock and return */
935 WsAsyncUnlock();
936 return NO_ERROR;
937 }
938
939 /* Loop the queue */
940 Entry = WsAsyncQueue->Flink;
941 while (Entry != WsAsyncQueue)
942 {
943 /* Get the Async Block */
944 AsyncBlock = CONTAINING_RECORD(Entry, WSASYNCBLOCK, AsyncQueue);
945
946 /* Check if this is the one */
947 if (TaskHandle == AsyncBlock->TaskHandle)
948 {
949 /* It is, remove it */
950 RemoveEntryList(Entry);
951
952 /* Release the lock, free the block, and return */
953 WsAsyncUnlock();
954 WsAsyncFreeBlock(AsyncBlock);
955 return NO_ERROR;
956 }
957
958 /* Move to the next entry */
959 Entry = Entry->Flink;
960 }
961
962 /* Nothing found, fail */
963 WsAsyncUnlock();
964 return WSAEINVAL;
965 }