[MSAFD] Don't assume SOL_SOCKET is the only socket level. By Peter Hater. CORE-10440...
[reactos.git] / reactos / dll / win32 / ws2_32_new / 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 alises */
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 alises */
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 alises */
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 operaiton */
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 anyomre */
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 operaiton */
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 anyomre */
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 operaiton */
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 anyomre */
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 PWSASYNCCONTEXT Context)
704 {
705 PWSASYNCBLOCK AsyncBlock;
706 PLIST_ENTRY Entry;
707 HANDLE AsyncEvent = Context->AsyncEvent;
708 PLIST_ENTRY ListHead = &Context->AsyncQueue;
709
710 /* Set the blocking hook */
711 WSASetBlockingHook((FARPROC)WsAsyncThreadBlockingHook);
712
713 /* Loop */
714 while (TRUE)
715 {
716 /* Wait for the event */
717 WaitForSingleObject(AsyncEvent, INFINITE);
718
719 /* Get the lock */
720 WsAsyncLock();
721
722 /* Process the queue */
723 while (ListHead->Flink != ListHead)
724 {
725 /* Remove this entry and get the async block */
726 Entry = RemoveHeadList(ListHead);
727 AsyncBlock = CONTAINING_RECORD(Entry, WSASYNCBLOCK, AsyncQueue);
728
729 /* Save the current task handle */
730 WsAsyncCurrentTaskHandle = AsyncBlock->TaskHandle;
731
732 /* Release the lock */
733 WsAsyncUnlock();
734
735 /* Check which operation to do */
736 switch (AsyncBlock->Operation)
737 {
738 /* Get Host by Y */
739 case WsAsyncGetHostByAddr: case WsAsyncGetHostByName:
740
741 /* Call the handler */
742 WsAsyncGetHost(AsyncBlock->TaskHandle,
743 AsyncBlock->Operation,
744 AsyncBlock->GetHost.hWnd,
745 AsyncBlock->GetHost.wMsg,
746 AsyncBlock->GetHost.ByWhat,
747 AsyncBlock->GetHost.Length,
748 AsyncBlock->GetHost.Type,
749 AsyncBlock->GetHost.Buffer,
750 AsyncBlock->GetHost.BufferLength);
751 break;
752
753 /* Get Proto by Y */
754 case WsAsyncGetProtoByNumber: case WsAsyncGetProtoByName:
755
756 /* Call the handler */
757 WsAsyncGetProto(AsyncBlock->TaskHandle,
758 AsyncBlock->Operation,
759 AsyncBlock->GetProto.hWnd,
760 AsyncBlock->GetProto.wMsg,
761 AsyncBlock->GetHost.ByWhat,
762 AsyncBlock->GetProto.Buffer,
763 AsyncBlock->GetProto.BufferLength);
764 break;
765
766 /* Get Serv by Y */
767 case WsAsyncGetServByPort: case WsAsyncGetServByName:
768
769 /* Call the handler */
770 WsAsyncGetServ(AsyncBlock->TaskHandle,
771 AsyncBlock->Operation,
772 AsyncBlock->GetServ.hWnd,
773 AsyncBlock->GetServ.wMsg,
774 AsyncBlock->GetServ.ByWhat,
775 AsyncBlock->GetServ.Protocol,
776 AsyncBlock->GetServ.Buffer,
777 AsyncBlock->GetServ.BufferLength);
778 break;
779
780 /* Termination */
781 case WsAsyncTerminate:
782
783 /* Clean up the extra reference */
784 WSACleanup();
785
786 /* Free the context block */
787 WsAsyncFreeBlock(AsyncBlock);
788
789 /* Acquire the lock */
790 WsAsyncLock();
791
792 /* Loop the queue and flush it */
793 while (!IsListEmpty(ListHead))
794 {
795 Entry = RemoveHeadList(ListHead);
796 AsyncBlock = CONTAINING_RECORD(Entry,
797 WSASYNCBLOCK,
798 AsyncQueue);
799 WsAsyncFreeBlock(AsyncBlock);
800 }
801
802 /* Release lock */
803 WsAsyncUnlock();
804
805 /* Close the event, free the Context */
806 CloseHandle(AsyncEvent);
807 HeapFree(WsSockHeap, 0, Context);
808
809 /* Remove the extra DLL reference and kill us */
810 FreeLibraryAndExitThread(WsAsyncDllHandle, 0);
811
812 default:
813 break;
814 }
815
816 /* Done processing */
817 WsAsyncCurrentTaskHandle = NULL;
818
819 /* Free this block, get lock and reloop */
820 WsAsyncFreeBlock(AsyncBlock);
821 WsAsyncLock();
822 }
823
824 /* Release the lock */
825 WsAsyncUnlock();
826 }
827 }
828
829 BOOL
830 WSAAPI
831 WsAsyncCheckAndInitThread(VOID)
832 {
833 HANDLE ThreadHandle;
834 DWORD Tid;
835 PWSASYNCCONTEXT Context = NULL;
836 WSADATA WsaData;
837
838 /* Make sure we're not initialized */
839 if (WsAsyncThreadInitialized) return TRUE;
840
841 /* Acquire the lock */
842 WsAsyncLock();
843
844 /* Make sure we're not initialized */
845 if (!WsAsyncThreadInitialized)
846 {
847 /* Initialize Thread Context */
848 Context = HeapAlloc(WsSockHeap, 0, sizeof(*Context));
849
850 /* Initialize the Queue and event */
851 WsAsyncQueue = &Context->AsyncQueue;
852 InitializeListHead(WsAsyncQueue);
853 Context->AsyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
854 WsAsyncEvent = Context->AsyncEvent;
855
856 /* Prevent us from ever being killed while running */
857 WSAStartup(MAKEWORD(2,2), &WsaData);
858
859 /* Create the thread */
860 ThreadHandle = CreateThread(NULL,
861 0,
862 (LPTHREAD_START_ROUTINE)WsAsyncThread,
863 Context,
864 0,
865 &Tid);
866
867 /* Close the handle and set init */
868 CloseHandle(ThreadHandle);
869 WsAsyncThreadInitialized = TRUE;
870 }
871
872 /* Release the lock */
873 WsAsyncUnlock();
874 return WsAsyncThreadInitialized;
875 }
876
877 VOID
878 WSAAPI
879 WsAsyncTerminateThread(VOID)
880 {
881 PWSASYNCBLOCK AsyncBlock;
882
883 /* Make sure we're initialized */
884 if (!WsAsyncThreadInitialized) return;
885
886 /* Allocate a block */
887 AsyncBlock = WsAsyncAllocateBlock(0);
888
889 /* Initialize it for termination */
890 AsyncBlock->Operation = WsAsyncTerminate;
891
892 /* Queue the request and return */
893 WsAsyncQueueRequest(AsyncBlock);
894 WsAsyncThreadInitialized = FALSE;
895 }
896
897 VOID
898 WSAAPI
899 WsAsyncQueueRequest(IN PWSASYNCBLOCK AsyncBlock)
900 {
901 /* Get the lock */
902 WsAsyncLock();
903
904 /* Insert it into the queue */
905 InsertTailList(WsAsyncQueue, &AsyncBlock->AsyncQueue);
906
907 /* Wake up the thread */
908 SetEvent(WsAsyncEvent);
909
910 /* Release lock and return */
911 WsAsyncUnlock();
912 }
913
914 INT
915 WSAAPI
916 WsAsyncCancelRequest(IN HANDLE TaskHandle)
917 {
918 PLIST_ENTRY Entry;
919 PWSASYNCBLOCK AsyncBlock;
920
921 /* Make sure we're initialized */
922 if (!WsAsyncThreadInitialized) return WSAEINVAL;
923
924 /* Acquire the lock */
925 WsAsyncLock();
926
927 /* Check if we're cancelling the current task */
928 if (TaskHandle == WsAsyncCurrentTaskHandle)
929 {
930 /* Mark us as cancelled, the async thread will see this later */
931 WsAsyncCancelledTaskHandle = TaskHandle;
932
933 /* Release lock and return */
934 WsAsyncUnlock();
935 return NO_ERROR;
936 }
937
938 /* Loop the queue */
939 Entry = WsAsyncQueue->Flink;
940 while (Entry != WsAsyncQueue)
941 {
942 /* Get the Async Block */
943 AsyncBlock = CONTAINING_RECORD(Entry, WSASYNCBLOCK, AsyncQueue);
944
945 /* Check if this is the one */
946 if (TaskHandle == AsyncBlock->TaskHandle)
947 {
948 /* It is, remove it */
949 RemoveEntryList(Entry);
950
951 /* Release the lock, free the block, and return */
952 WsAsyncUnlock();
953 WsAsyncFreeBlock(AsyncBlock);
954 return NO_ERROR;
955 }
956
957 /* Move to the next entry */
958 Entry = Entry->Flink;
959 }
960
961 /* Nothing found, fail */
962 WsAsyncUnlock();
963 return WSAEINVAL;
964 }