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
WsAsyncGlobalInitialize(VOID)31 WsAsyncGlobalInitialize(VOID)
32 {
33 /* Initialize the async lock */
34 InitializeCriticalSection(&WsAsyncCritSect);
35 }
36
37 VOID
38 WSAAPI
WsAsyncGlobalTerminate(VOID)39 WsAsyncGlobalTerminate(VOID)
40 {
41 /* Destroy the async lock */
42 DeleteCriticalSection(&WsAsyncCritSect);
43 }
44
45
46 SIZE_T
47 WSAAPI
BytesInHostent(PHOSTENT Hostent)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
BytesInServent(PSERVENT Servent)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
BytesInProtoent(PPROTOENT Protoent)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
CopyHostentToBuffer(IN PCHAR Buffer,IN INT BufferLength,IN PHOSTENT Hostent)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
CopyServentToBuffer(IN PCHAR Buffer,IN INT BufferLength,IN PSERVENT Servent)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
CopyProtoentToBuffer(IN PCHAR Buffer,IN INT BufferLength,IN PPROTOENT Protoent)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
WsAsyncAllocateBlock(IN SIZE_T ExtraLength)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
WsAsyncThreadBlockingHook(VOID)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
WsAsyncFreeBlock(IN PWSASYNCBLOCK AsyncBlock)473 WsAsyncFreeBlock(IN PWSASYNCBLOCK AsyncBlock)
474 {
475 /* Free it */
476 HeapFree(WsSockHeap, 0, AsyncBlock);
477 }
478
479 VOID
480 WSAAPI
WsAsyncGetServ(IN HANDLE TaskHandle,IN DWORD Operation,IN HWND hWnd,IN UINT wMsg,IN CHAR FAR * ByWhat,IN CHAR FAR * Protocol,IN CHAR FAR * Buffer,IN INT BufferLength)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
WsAsyncGetProto(IN HANDLE TaskHandle,IN DWORD Operation,IN HWND hWnd,IN UINT wMsg,IN CHAR FAR * ByWhat,IN CHAR FAR * Buffer,IN INT BufferLength)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
WsAsyncGetHost(IN HANDLE TaskHandle,IN DWORD Operation,IN HWND hWnd,IN UINT wMsg,IN CHAR FAR * ByWhat,IN INT Length,IN INT Type,IN CHAR FAR * Buffer,IN INT BufferLength)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
WsAsyncThread(IN PVOID ThreadContext)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
WsAsyncCheckAndInitThread(VOID)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
WsAsyncTerminateThread(VOID)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
WsAsyncQueueRequest(IN PWSASYNCBLOCK AsyncBlock)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
WsAsyncCancelRequest(IN HANDLE TaskHandle)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