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