source: trunk/src/wsock32/async.cpp@ 1807

Last change on this file since 1807 was 1807, checked in by phaller, 26 years ago

Fix: socket experiment with PMWSOCK

File size: 45.4 KB
Line 
1/* $Id: async.cpp,v 1.16 1999-11-22 08:18:01 phaller Exp $ */
2
3/*
4 *
5 * Project Odin Software License can be found in LICENSE.TXT
6 *
7 * Asynchronous Winsock code
8 *
9 * Copyright 1999 Patrick Haller
10 *
11 *
12 * Remark:
13 * - do NOT call WSASetLastError in the async worker thread, since there we don't
14 * know anything about the caller thread.
15 *
16 * Idea is to separate requests:
17 * - all database requests and DNS requests are handled by one thread
18 * - asynchronous selects are each handled by its own thread
19 */
20
21
22/*****************************************************************************
23 * Includes *
24 *****************************************************************************/
25
26#include <odin.h>
27#include <odinwrap.h>
28#include <os2sel.h>
29#define INCL_DOSERRORS
30#define INCL_DOSSEMAPHORES
31#include <os2.h>
32
33#include <netdb.h>
34#include <nerrno.h>
35#include <sys/socket.h>
36#include <sys/ioctl.h>
37#include <sys/select.h>
38#include <sys/time.h>
39
40#include <wsock32const.h>
41
42#include <process.h>
43#include <string.h>
44#include <stdlib.h>
45
46#include <misc.h>
47
48
49/*****************************************************************************
50 * Definitions *
51 *****************************************************************************/
52
53ODINDEBUGCHANNEL(WSOCK32-ASYNC)
54
55
56#define ERROR_SUCCESS 0
57
58
59typedef enum tagSocketStatus
60{
61 SOCKSTAT_UNKNOWN = 0, // unknown socket state
62 SOCKSTAT_NORMAL, // normal socket state
63 SOCKSTAT_CONNECT_PENDING // non-blocking connect attempted
64};
65
66typedef struct tagSocketAsync
67{
68 int hSocket; /* operating system socket descriptor */
69 int iStatus;
70
71 int iEventMaskAllowed; // bits of valid socket events are set to 1
72} SOCKETASYNC, *PSOCKETASYNC;
73
74
75// prototype of the OS/2 select!
76int _System os2_select(int* socket,
77 int fd_read,
78 int fd_write,
79 int fd_exception,
80 long timeout);
81
82int _System bsd_select(int,
83 fd_set *,
84 fd_set *,
85 fd_set *,
86 struct timeval*);
87
88// wsock32.cpp: error code translation
89int iTranslateSockErrToWSock(int iError);
90
91
92/*****************************************************************************
93 * Structures *
94 *****************************************************************************/
95
96// request types
97enum tagAsyncRequestType
98{
99 WSAASYNC_TERMINATE, // internal message
100 WSAASYNC_GETHOSTBYADDR,
101 WSAASYNC_GETHOSTBYNAME,
102 WSAASYNC_GETPROTOBYNAME,
103 WSAASYNC_GETPROTOBYNUMBER,
104 WSAASYNC_GETSERVBYNAME,
105 WSAASYNC_GETSERVBYPORT,
106 WSAASYNC_SELECT
107};
108
109
110// request states
111enum tagAsyncRequestStates
112{
113 RS_WAITING, // request is waiting in queue
114 RS_BUSY, // request is currently being serviced
115 RS_CANCELLED, // request has been cancelled
116 RS_DONE
117};
118
119
120typedef struct tagAsyncRequest
121{
122 struct tagAsyncRequest* pPrev; // pointer to previous request
123 struct tagAsyncRequest* pNext; // pointer to next request
124
125 ULONG ulType; // type of request
126 ULONG ulState; // state of request
127 PWSOCKTHREADDATA pwstd; // save pointer of caller thread's wsock data
128
129 HWND hwnd; // window handle to post message to
130 ULONG ulMessage; // message to post
131
132 PVOID pBuffer; // result buffer
133 ULONG ulBufferLength; // length of the return buffer
134
135 ULONG ul1; // multi purpose parameters
136 ULONG ul2;
137 ULONG ul3;
138
139} ASYNCREQUEST, *PASYNCREQUEST;
140
141
142/*****************************************************************************
143 * Prototypes *
144 *****************************************************************************/
145
146void _Optlink WorkerThreadProc(void* pParam);
147BOOL _System PostMessageA(HWND hwnd, UINT ulMessage, WPARAM wParam, LPARAM lParam);
148
149
150/*****************************************************************************
151 * Implementation *
152 *****************************************************************************/
153
154class WSAAsyncWorker
155{
156 // protected members
157 protected:
158 PASYNCREQUEST pRequestHead; // chain root
159 PASYNCREQUEST pRequestTail; // chain root
160 TID tidWorker; // worker thread id
161 HEV hevRequest; // fired upon new request
162 HMTX hmtxRequestQueue; // request queue protection
163 BOOL fTerminate; // got to die ?
164 BOOL fBlocking; // currently busy ?
165
166 TID startWorker (void); // start worker thread
167 void processingLoop (void); // "work"
168 int dispatchRequest(PASYNCREQUEST pRequest); // complete request
169 PASYNCREQUEST popRequest (void); // get one request from queue
170 BOOL deleteRequest (PASYNCREQUEST pRequest); // remove particular request
171
172 void lockQueue (void); // enter mutex
173 void unlockQueue (void); // leave mutex
174
175 // the real worker methods
176 void asyncGetHostByAddr (PASYNCREQUEST pRequest);
177 void asyncGetHostByName (PASYNCREQUEST pRequest);
178 void asyncGetProtoByName (PASYNCREQUEST pRequest);
179 void asyncGetProtoByNumber(PASYNCREQUEST pRequest);
180 void asyncGetServByName (PASYNCREQUEST pRequest);
181 void asyncGetServByPort (PASYNCREQUEST pRequest);
182 void asyncSelect (PASYNCREQUEST pRequest);
183
184 // public members
185 public:
186 WSAAsyncWorker(void); // constructor
187 ~WSAAsyncWorker(); // destructor
188
189 PASYNCREQUEST createRequest (ULONG ulType,
190 HWND hwnd,
191 ULONG ulMessage,
192 PVOID pBuffer,
193 ULONG ulBufferLength,
194 ULONG ul1 = 0,
195 ULONG ul2 = 0,
196 ULONG ul3 = 0);
197
198 void pushRequest (PASYNCREQUEST pRequest); // put request on queue
199 BOOL cancelAsyncRequest (PASYNCREQUEST pRequest);
200 BOOL isBlocking (void) {return fBlocking;}
201
202 // the thread procedure
203 friend void _Optlink WorkerThreadProc(void* pParam);
204};
205
206
207/*****************************************************************************
208 * Local variables *
209 *****************************************************************************/
210
211//static WSAAsyncWorker* wsaWorker = NULL;
212static WSAAsyncWorker* wsaWorker = new WSAAsyncWorker();
213
214
215/*****************************************************************************
216 * Name :
217 * Purpose :
218 * Parameters:
219 * Variables :
220 * Result :
221 * Remark :
222 * Status : UNTESTED STUB
223 *
224 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
225 *****************************************************************************/
226// constructor
227WSAAsyncWorker::WSAAsyncWorker(void)
228{
229 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::WSAAsyncWorker\n"));
230
231 pRequestHead = NULL; // chain root
232 pRequestTail = NULL; // chain root
233 tidWorker = 0; // worker thread id
234 fTerminate = FALSE; // got to die ?
235
236 startWorker();
237}
238
239
240/*****************************************************************************
241 * Name :
242 * Purpose :
243 * Parameters:
244 * Variables :
245 * Result :
246 * Remark :
247 * Status : UNTESTED STUB
248 *
249 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
250 *****************************************************************************/
251// destructor
252WSAAsyncWorker::~WSAAsyncWorker(void)
253{
254 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::~WSAAsyncWorker (%08xh)\n",
255 this));
256
257 // remove all requests
258 while (popRequest() != NULL);
259
260 // just in case ... terminate worker thread
261 if (tidWorker != 0)
262 {
263 fTerminate = TRUE;
264 DosPostEventSem(hevRequest);
265 }
266
267 DosCloseEventSem(hevRequest);
268 DosCloseMutexSem(hmtxRequestQueue);
269}
270
271
272
273/*****************************************************************************
274 * Name :
275 * Purpose :
276 * Parameters:
277 * Variables :
278 * Result :
279 * Remark :
280 * Status : UNTESTED STUB
281 *
282 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
283 *****************************************************************************/
284// start worker thread if necessary
285TID WSAAsyncWorker::startWorker(void)
286{
287 APIRET rc;
288
289 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::startWorker (%08xh)\n",
290 this));
291
292 if (tidWorker == 0)
293 {
294 // create semaphores
295 rc = DosCreateEventSem(NULL, // unnamed
296 &hevRequest,
297 0, // unshared
298 FALSE); // reset
299 if (rc != NO_ERROR)
300 {
301 dprintf(("WSOCK32: WSAAsyncWorker::startWorker - DosCreateEventSem = %08xh\n",
302 rc));
303
304 return 0;
305 }
306
307 rc = DosCreateMutexSem(NULL, // unnamed
308 &hmtxRequestQueue,
309 0, // unshared
310 FALSE); // unowned
311 if (rc != NO_ERROR)
312 {
313 dprintf(("WSOCK32: WSAAsyncWorker::startWorker - DosCreateMutexSem = %08xh\n",
314 rc));
315
316 DosCloseEventSem(hevRequest);
317 return 0;
318 }
319
320 // create thread
321#if defined(__IBMCPP__)
322 tidWorker = _beginthread(WorkerThreadProc,
323 NULL,
324 16384,
325 (PVOID)this);
326#else
327 tidWorker = _beginthread(WorkerThreadProc,
328 16384,
329 (PVOID)this);
330#endif
331 if (tidWorker == -1)
332 {
333 // cancel the whole thing
334 tidWorker = 0;
335 DosCloseEventSem(hevRequest);
336 DosCloseMutexSem(hmtxRequestQueue);
337 }
338 }
339
340 return tidWorker; // thread already running
341}
342
343
344/*****************************************************************************
345 * Name :
346 * Purpose :
347 * Parameters:
348 * Variables :
349 * Result :
350 * Remark :
351 * Status : UNTESTED STUB
352 *
353 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
354 *****************************************************************************/
355// lock double-linked request chain
356void WSAAsyncWorker::lockQueue(void)
357{
358 DosRequestMutexSem(hmtxRequestQueue, SEM_INDEFINITE_WAIT);
359}
360
361
362/*****************************************************************************
363 * Name :
364 * Purpose :
365 * Parameters:
366 * Variables :
367 * Result :
368 * Remark :
369 * Status : UNTESTED STUB
370 *
371 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
372 *****************************************************************************/
373// unlock double-linked request chain
374void WSAAsyncWorker::unlockQueue(void)
375{
376 DosReleaseMutexSem(hmtxRequestQueue);
377}
378
379
380/*****************************************************************************
381 * Name :
382 * Purpose :
383 * Parameters:
384 * Variables :
385 * Result :
386 * Remark :
387 * Status : UNTESTED STUB
388 *
389 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
390 *****************************************************************************/
391// get request from queue
392PASYNCREQUEST WSAAsyncWorker::popRequest(void)
393{
394 PASYNCREQUEST pLast;
395
396 lockQueue(); // lock queue
397
398 // alter queue
399 pLast = pRequestTail;
400
401 if (pRequestTail != NULL)
402 {
403 if (pRequestTail->pPrev)
404 {
405 pRequestTail->pPrev->pNext = NULL; // cut off element
406 pRequestTail = pRequestTail->pPrev; // unlink previous element
407 }
408 else
409 {
410 // this is the last request on the queue
411 pRequestTail = NULL;
412 pRequestHead = NULL;
413 }
414 }
415
416 unlockQueue(); // unlock queue
417
418 return (pLast); // return element
419}
420
421
422/*****************************************************************************
423 * Name :
424 * Purpose :
425 * Parameters:
426 * Variables :
427 * Result :
428 * Remark :
429 * Status : UNTESTED STUB
430 *
431 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
432 *****************************************************************************/
433// insert request into queue
434void WSAAsyncWorker::pushRequest(PASYNCREQUEST pNew)
435{
436 if (pNew == NULL) // ensure proper parameters
437 return;
438
439 lockQueue(); // lock queue
440
441 // alter queue
442 if (pRequestHead == NULL)
443 {
444 // first element in queue
445 pRequestHead = pNew;
446 pRequestTail = pNew;
447 pNew->pPrev = NULL;
448 pNew->pNext = NULL;
449 }
450 else
451 {
452 // chain in request
453 pNew->pPrev = NULL;
454 pNew->pNext = pRequestHead;
455 pRequestHead->pPrev = pNew;
456 pRequestHead = pNew;
457 }
458
459 // queue debug
460 {
461 PASYNCREQUEST pTemp;
462
463 dprintf(("WSOCK32: WSAAsyncWorker pRequest type state hwnd message\n"));
464 for (pTemp = pRequestHead;
465 pTemp;
466 pTemp = pTemp->pNext)
467 dprintf(("WSOCK32: WSAAsyncWorker %08xh %08xh %08xh %08xh %08xh",
468 pTemp,
469 pTemp->ulType,
470 pTemp->ulState,
471 pTemp->hwnd,
472 pTemp->ulMessage));
473 }
474
475 // trigger thread!
476 DosPostEventSem(hevRequest);
477
478 unlockQueue(); // unlock queue
479}
480
481
482/*****************************************************************************
483 * Name :
484 * Purpose :
485 * Parameters:
486 * Variables :
487 * Result :
488 * Remark :
489 * Status : UNTESTED STUB
490 *
491 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
492 *****************************************************************************/
493// delete particular request from queue
494BOOL WSAAsyncWorker::deleteRequest(PASYNCREQUEST pDelete)
495{
496 PASYNCREQUEST pRequest; // for verification
497 BOOL bResult = FALSE;
498
499 lockQueue(); // lock queue
500
501 // find request (optional, just for verification)
502 for (pRequest = pRequestHead;
503 pRequest != NULL;
504 pRequest = pRequest->pNext)
505 if (pRequest == pDelete)
506 break;
507
508 if (pRequest == pDelete) // if request has been found
509 {
510 // is request the head of the list ?
511 if (pDelete == pRequestHead)
512 {
513 pRequestHead = pDelete->pNext;
514 if (pRequestHead == NULL) // last element ?
515 pRequestTail = NULL;
516 else
517 pRequestHead->pPrev = NULL;
518 }
519 else
520 // if request the last in the list ?
521 if (pDelete == pRequestTail)
522 {
523 pRequestTail = pDelete->pPrev;
524 if (pRequestTail == NULL) // last element ?
525 pRequestHead = NULL;
526 else
527 pRequestTail->pNext = NULL;
528 }
529 else
530 // request is somewhere in the middle of the list
531 {
532 if (pDelete->pPrev != NULL)
533 pDelete->pPrev->pNext = pDelete->pNext;
534
535 if (pDelete->pNext != NULL)
536 pDelete->pNext->pPrev = pDelete->pPrev;
537 }
538
539 delete pDelete; // free the memory
540 bResult = TRUE; // OK
541 }
542
543 unlockQueue(); // unlock queue
544 return bResult;
545}
546
547
548/*****************************************************************************
549 * Name :
550 * Purpose :
551 * Parameters:
552 * Variables :
553 * Result :
554 * Remark :
555 * Status : UNTESTED STUB
556 *
557 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
558 *****************************************************************************/
559
560BOOL WSAAsyncWorker::cancelAsyncRequest(PASYNCREQUEST pRequest)
561{
562 PASYNCREQUEST pRequestTemp;
563 BOOL rc = TRUE;
564
565 lockQueue();
566
567 // verify pRequest
568 // find request (optional, just for verification)
569 for (pRequestTemp = pRequestHead;
570 pRequestTemp != NULL;
571 pRequestTemp = pRequestTemp->pNext)
572 if (pRequestTemp == pRequest)
573 break;
574
575 // is request in queue ?
576 if (pRequestTemp == pRequest)
577 {
578 // is it busy?
579 if (pRequest->ulState != RS_BUSY)
580 {
581 // if not: set RS_CANCELLED
582 pRequest->ulState = RS_CANCELLED;
583 }
584 else
585 {
586 // if busy: ???
587 dprintf(("WSOCK32:Async: WSAAsyncWorker::cancelAsyncRequest(%08xh, %08xh) how to cancel?\n",
588 this,
589 pRequest));
590 rc = FALSE;
591 }
592 }
593 else
594 rc = FALSE;
595
596 unlockQueue();
597 return rc;
598}
599
600
601/*****************************************************************************
602 * Name :
603 * Purpose :
604 * Parameters:
605 * Variables :
606 * Result :
607 * Remark :
608 * Status : UNTESTED STUB
609 *
610 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
611 *****************************************************************************/
612
613PASYNCREQUEST WSAAsyncWorker::createRequest (ULONG ulType,
614 HWND hwnd,
615 ULONG ulMessage,
616 PVOID pBuffer,
617 ULONG ulBufferLength,
618 ULONG ul1,
619 ULONG ul2,
620 ULONG ul3)
621{
622 PASYNCREQUEST pNew = new ASYNCREQUEST();
623
624 if (pNew != NULL) // check for proper allocation
625 {
626 // fill the structure
627 pNew->pPrev = NULL;
628 pNew->pNext = NULL;
629 pNew->ulType = ulType;
630 pNew->ulState = RS_WAITING;
631 pNew->hwnd = hwnd;
632 pNew->ulMessage = ulMessage;
633 pNew->pBuffer = pBuffer;
634 pNew->ulBufferLength = ulBufferLength;
635 pNew->ul1 = ul1;
636 pNew->ul2 = ul2;
637 pNew->ul3 = ul3;
638
639 // save caller thread's wsock data
640 pNew->pwstd = iQueryWsockThreadData();
641 }
642
643 dprintf(("WSOCK32: WSAAsyncWorker:createRequest = %08xh\n",
644 pNew));
645
646 return pNew;
647}
648
649
650/*****************************************************************************
651 * Name :
652 * Purpose :
653 * Parameters:
654 * Variables :
655 * Result :
656 * Remark :
657 * Status : UNTESTED STUB
658 *
659 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
660 *****************************************************************************/
661
662void WSAAsyncWorker::asyncGetHostByAddr (PASYNCREQUEST pRequest)
663{
664 struct hostent* pHostent;
665 USHORT usLength = sizeof(struct Whostent);
666 USHORT rc;
667 struct Whostent* pwhostent = (struct Whostent*)pRequest->pBuffer;
668
669 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::asyncGetHostByAddr (%08xh, %08xh)\n",
670 this,
671 pRequest));
672
673 // result buffer length
674 if (pRequest->ulBufferLength < sizeof(struct Whostent))
675 {
676 rc = WSAEINVAL;
677 //WSASetLastError(rc); // same as Winsock return codes
678 }
679 else
680 {
681 // call API
682 pHostent = gethostbyaddr((char*)pRequest->ul1,
683 (int) pRequest->ul2,
684 (int) pRequest->ul3);
685 if (pHostent == NULL) // error ?
686 {
687 // build error return code
688 rc = iTranslateSockErrToWSock(sock_errno());
689 //WSASetLastError(rc);
690 }
691 else
692 {
693 // translate result to Wsock32-style structure
694 pwhostent->h_name = pHostent->h_name;
695 pwhostent->h_aliases = pHostent->h_aliases;
696 pwhostent->h_addrtype = pHostent->h_addrtype;
697 pwhostent->h_length = pHostent->h_length;
698 pwhostent->h_addr_list = pHostent->h_addr_list;
699 rc = 0;
700 }
701 }
702
703 // post result
704 PostMessageA(pRequest->hwnd,
705 pRequest->ulMessage,
706 (WPARAM)pRequest,
707 (LPARAM)(rc << 16 | usLength));
708
709 // M$ says, if PostMessageA fails, spin as long as window exists
710}
711
712
713/*****************************************************************************
714 * Name :
715 * Purpose :
716 * Parameters:
717 * Variables :
718 * Result :
719 * Remark :
720 * Status : UNTESTED STUB
721 *
722 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
723 *****************************************************************************/
724
725void WSAAsyncWorker::asyncGetHostByName (PASYNCREQUEST pRequest)
726{
727 struct hostent* pHostent;
728 USHORT usLength = sizeof(struct Whostent);
729 USHORT rc;
730 struct Whostent* pwhostent = (struct Whostent*)pRequest->pBuffer;
731
732 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::asyncGetHostByName (%08xh, %08xh)\n",
733 this,
734 pRequest));
735
736 // result buffer length
737 if (pRequest->ulBufferLength < sizeof(struct Whostent))
738 {
739 rc = WSAEINVAL;
740 //WSASetLastError(rc); // same as Winsock return codes
741 }
742 else
743 {
744 // call API
745 pHostent = gethostbyname((char*)pRequest->ul1);
746 if (pHostent == NULL) // error ?
747 {
748 // build error return code
749 rc = iTranslateSockErrToWSock(sock_errno());
750 //WSASetLastError(rc);
751 }
752 else
753 {
754 // translate result to Wsock32-style structure
755 pwhostent->h_name = pHostent->h_name;
756 pwhostent->h_aliases = pHostent->h_aliases;
757 pwhostent->h_addrtype = pHostent->h_addrtype;
758 pwhostent->h_length = pHostent->h_length;
759 pwhostent->h_addr_list = pHostent->h_addr_list;
760 rc = 0;
761 }
762 }
763
764 // post result
765 PostMessageA(pRequest->hwnd,
766 pRequest->ulMessage,
767 (WPARAM)pRequest,
768 (LPARAM)(rc << 16 | usLength));
769
770 // M$ says, if PostMessageA fails, spin as long as window exists
771}
772
773
774/*****************************************************************************
775 * Name :
776 * Purpose :
777 * Parameters:
778 * Variables :
779 * Result :
780 * Remark :
781 * Status : UNTESTED STUB
782 *
783 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
784 *****************************************************************************/
785
786void WSAAsyncWorker::asyncGetProtoByName (PASYNCREQUEST pRequest)
787{
788 struct protoent* pProtoent;
789 USHORT usLength = sizeof(struct Wprotoent);
790 USHORT rc;
791 struct Wprotoent* pwprotoent= (struct Wprotoent*)pRequest->pBuffer;
792
793 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::asyncGetProtoByName (%08xh, %08xh)\n",
794 this,
795 pRequest));
796
797 // result buffer length
798 if (pRequest->ulBufferLength < sizeof(struct Wprotoent))
799 {
800 rc = WSAEINVAL;
801 //WSASetLastError(rc); // same as Winsock return codes
802 }
803 else
804 {
805 // call API
806 pProtoent = getprotobyname((char*)pRequest->ul1);
807 if (pProtoent == NULL) // error ?
808 {
809 // build error return code
810 rc = iTranslateSockErrToWSock(sock_errno());
811 //WSASetLastError(rc);
812 }
813 else
814 {
815 // build result buffer
816 pwprotoent->p_name = pProtoent->p_name;
817 pwprotoent->p_aliases = pProtoent->p_aliases;
818 pwprotoent->p_proto = pProtoent->p_proto;
819 rc = 0;
820 }
821 }
822
823 // post result
824 PostMessageA(pRequest->hwnd,
825 pRequest->ulMessage,
826 (WPARAM)pRequest,
827 (LPARAM)(rc << 16 | usLength));
828
829 // M$ says, if PostMessageA fails, spin as long as window exists
830}
831
832
833/*****************************************************************************
834 * Name :
835 * Purpose :
836 * Parameters:
837 * Variables :
838 * Result :
839 * Remark :
840 * Status : UNTESTED STUB
841 *
842 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
843 *****************************************************************************/
844
845void WSAAsyncWorker::asyncGetProtoByNumber(PASYNCREQUEST pRequest)
846{
847 struct protoent* pProtoent;
848 USHORT usLength = sizeof(struct Wprotoent);
849 USHORT rc;
850 struct Wprotoent* pwprotoent= (struct Wprotoent*)pRequest->pBuffer;
851
852 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::asyncGetProtoByNumber (%08xh, %08xh)\n",
853 this,
854 pRequest));
855
856 // result buffer length
857 if (pRequest->ulBufferLength < sizeof(struct Wprotoent))
858 {
859 rc = WSAEINVAL;
860 //WSASetLastError(rc); // same as Winsock return codes
861 }
862 else
863 {
864 // call API
865 pProtoent = getprotobyname(( char*)pRequest->ul1);
866 if (pProtoent == NULL) // error ?
867 {
868 // build error return code
869 rc = iTranslateSockErrToWSock(sock_errno());
870 //WSASetLastError(rc);
871 }
872 else
873 {
874 // build result buffer
875 pwprotoent->p_name = pProtoent->p_name;
876 pwprotoent->p_aliases = pProtoent->p_aliases;
877 pwprotoent->p_proto = pProtoent->p_proto;
878 rc = 0;
879 }
880 }
881
882 // post result
883 PostMessageA(pRequest->hwnd,
884 pRequest->ulMessage,
885 (WPARAM)pRequest,
886 (LPARAM)(rc << 16 | usLength));
887
888 // M$ says, if PostMessageA fails, spin as long as window exists
889}
890
891
892/*****************************************************************************
893 * Name :
894 * Purpose :
895 * Parameters:
896 * Variables :
897 * Result :
898 * Remark :
899 * Status : UNTESTED STUB
900 *
901 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
902 *****************************************************************************/
903
904void WSAAsyncWorker::asyncGetServByName(PASYNCREQUEST pRequest)
905{
906 struct servent* pServent;
907 USHORT usLength = sizeof(struct Wservent);
908 USHORT rc;
909 struct Wservent* pwservent= (struct Wservent*)pRequest->pBuffer;
910
911 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::asyncGetServByName (%08xh, %08xh)\n",
912 this,
913 pRequest));
914
915 // result buffer length
916 if (pRequest->ulBufferLength < sizeof(struct Wservent))
917 {
918 rc = WSAEINVAL;
919 //WSASetLastError(rc); // same as Winsock return codes
920 }
921 else
922 {
923 // call API
924 pServent = getservbyname((char*)pRequest->ul1,
925 (char*)pRequest->ul2);
926 if (pServent == NULL) // error ?
927 {
928 // build error return code
929 rc = iTranslateSockErrToWSock(sock_errno());
930 //WSASetLastError(rc);
931 }
932 else
933 {
934 // build result buffer
935 pwservent->s_name = pServent->s_name;
936 pwservent->s_aliases = pServent->s_aliases;
937 pwservent->s_port = pServent->s_port;
938 pwservent->s_proto = pServent->s_proto;
939 rc = 0;
940 }
941 }
942
943 // post result
944 PostMessageA(pRequest->hwnd,
945 pRequest->ulMessage,
946 (WPARAM)pRequest,
947 (LPARAM)(rc << 16 | usLength));
948
949 // M$ says, if PostMessageA fails, spin as long as window exists
950}
951
952
953/*****************************************************************************
954 * Name :
955 * Purpose :
956 * Parameters:
957 * Variables :
958 * Result :
959 * Remark :
960 * Status : UNTESTED STUB
961 *
962 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
963 *****************************************************************************/
964
965void WSAAsyncWorker::asyncGetServByPort(PASYNCREQUEST pRequest)
966{
967 struct servent* pServent;
968 USHORT usLength = sizeof(struct Wservent);
969 USHORT rc;
970 struct Wservent* pwservent= (struct Wservent*)pRequest->pBuffer;
971
972 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::asyncGetServByPort (%08xh, %08xh)\n",
973 this,
974 pRequest));
975
976 // result buffer length
977 if (pRequest->ulBufferLength < sizeof(struct Whostent))
978 {
979 rc = WSAEINVAL;
980 //WSASetLastError(rc); // same as Winsock return codes
981 }
982 else
983 {
984 // call API
985 pServent = getservbyport((int )pRequest->ul1,
986 (char*)pRequest->ul2);
987 if (pServent == NULL) // error ?
988 {
989 // build error return code
990 rc = iTranslateSockErrToWSock(sock_errno());
991 //WSASetLastError(rc);
992 }
993 else
994 {
995 // build result buffer
996 pwservent->s_name = pServent->s_name;
997 pwservent->s_aliases = pServent->s_aliases;
998 pwservent->s_port = pServent->s_port;
999 pwservent->s_proto = pServent->s_proto;
1000
1001 rc = 0;
1002 }
1003 }
1004
1005 // post result
1006 PostMessageA(pRequest->hwnd,
1007 pRequest->ulMessage,
1008 (WPARAM)pRequest,
1009 (LPARAM)(rc << 16 | usLength));
1010
1011 // M$ says, if PostMessageA fails, spin as long as window exists
1012}
1013
1014
1015
1016/*****************************************************************************
1017 * Name : WSAAsyncWorker::asyncSelect
1018 * Purpose :
1019 * Parameters:
1020 * Variables :
1021 * Result :
1022 * Remark :
1023 * Status : UNTESTED
1024 *
1025 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1026 *****************************************************************************/
1027
1028typedef int SOCKET;
1029
1030void WSAAsyncWorker::asyncSelect(PASYNCREQUEST pRequest)
1031{
1032 ULONG wParam;
1033 ULONG lParam;
1034 int irc;
1035 int iUnknown;
1036
1037 SOCKET sockWin;
1038 ULONG ulEvent;
1039 USHORT usResult = 0;
1040
1041 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::asyncSelect (%08xh, %08xh) not correctly implemented\n",
1042 this,
1043 pRequest));
1044
1045
1046 // setup variables
1047 sockWin = (SOCKET)pRequest->ul1;
1048 ulEvent = (ULONG) pRequest->ul2;
1049
1050 //@@@PH to do
1051 // 1. automatically set socket to non-blocking mode
1052 // 2. loop until WSAAsyncSelect(s,hwnd,0,0) ?
1053
1054
1055 //@@@PH how to implement other events?
1056
1057
1058 // finally do the select!
1059#ifdef BSDSELECT
1060 irc = os2_select(&sockWin,
1061 (ulEvent & FD_READ) ? 1 : 0,
1062 (ulEvent & FD_WRITE) ? 1 : 0,
1063 (ulEvent & FD_OOB) ? 1 : 0,
1064 10000); // @@@PH timeout
1065#else
1066
1067 // BSD implementation
1068 fd_set fds_read, *pfds_read = &fds_read;
1069 fd_set fds_write, *pfds_write = &fds_write;
1070 fd_set fds_exception,*pfds_exception = &fds_exception;
1071 struct timeval tv;
1072
1073 FD_ZERO(&fds_read); FD_SET(sockWin,&fds_read);
1074 FD_ZERO(&fds_write); FD_SET(sockWin,&fds_write);
1075 FD_ZERO(&fds_exception); FD_SET(sockWin,&fds_exception);
1076
1077 tv.tv_sec = 10;
1078 tv.tv_usec = 0;
1079
1080 if (!(ulEvent & FD_READ)) pfds_read = NULL;
1081 if (!(ulEvent & FD_WRITE)) pfds_write = NULL;
1082 if (!(ulEvent & FD_OOB)) pfds_exception = NULL;
1083
1084 irc = bsd_select(sockWin+1,
1085 pfds_read,
1086 pfds_write,
1087 pfds_exception,
1088 &tv);
1089#endif
1090
1091 if (irc < 0) /* an error occurred */
1092 {
1093 lParam = sock_errno(); /* raise error condition */
1094 if (lParam == SOCENOTSOCK)
1095 {
1096 usResult = FD_CLOSE;
1097 lParam = 0;
1098 }
1099 }
1100 else
1101 if (irc == 0) /* this means timeout */
1102 {
1103 lParam = iTranslateSockErrToWSock(WSAETIMEDOUT);/* raise error condition */
1104 }
1105 else
1106 {
1107 //@@@PH check the socket for any event and report!
1108 usResult = 0;
1109
1110 // readiness for reading bytes ?
1111/*
1112 if (FD_ISSET(sockWin, pfds_read)) usResult |= FD_READ;
1113 if (FD_ISSET(sockWin, pfds_write)) usResult |= FD_WRITE;
1114 if (FD_ISSET(sockWin, pfds_exception)) usResult |= FD_OOB;
1115*/
1116
1117/*
1118#define FD_READ 0x01
1119#define FD_WRITE 0x02
1120#define FD_OOB 0x04
1121#define FD_ACCEPT 0x08
1122#define FD_CONNECT 0x10
1123#define FD_CLOSE 0x20
1124*/
1125
1126 irc = ioctl(sockWin, FIONREAD, (char *)&iUnknown, sizeof(iUnknown));
1127 if ( (irc == 0) && (iUnknown > 0))
1128 usResult |= FD_READ | FD_CONNECT;
1129 }
1130
1131 // post result
1132 irc = (LPARAM)((lParam << 16) | usResult);
1133 dprintf(("WSOCK32:asyncSelect() posting %08xh hwnd%08xh, msg=%08xh, wparam=%08xh, lparam=%08xh\n",
1134 pRequest,
1135 pRequest->hwnd,
1136 pRequest->ulMessage,
1137 sockWin,
1138 irc));
1139
1140 PostMessageA(pRequest->hwnd,
1141 pRequest->ulMessage,
1142 (WPARAM)sockWin,
1143 (LPARAM)irc);
1144
1145 // M$ says, if PostMessageA fails, spin as long as window exists
1146}
1147
1148
1149
1150/*****************************************************************************
1151 * Name :
1152 * Purpose :
1153 * Parameters:
1154 * Variables :
1155 * Result :
1156 * Remark :
1157 * Status : UNTESTED STUB
1158 *
1159 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1160 *****************************************************************************/
1161// process one request
1162int WSAAsyncWorker::dispatchRequest(PASYNCREQUEST pRequest)
1163{
1164 int rc;
1165
1166 dprintf(("WSOCK32-ASYNC: WSAAsyncWorker::dispatchRequest (%08xh, %08xh)\n",
1167 this,
1168 pRequest));
1169
1170 // check request state first
1171 switch(pRequest->ulState)
1172 {
1173 case RS_WAITING: // OK, proceed
1174 break;
1175
1176 case RS_BUSY: // oops, shouldn't happen
1177 dprintf(("WSOCK32: WSAAsyncWorker::dispatchRequest - got already busy request %08xh\n",
1178 pRequest));
1179 return 1;
1180
1181 case RS_CANCELLED: // don't service request
1182 // request has been removed from queue already
1183 return 1;
1184 }
1185
1186 // OK, servicing request
1187 pRequest->ulState = RS_BUSY;
1188
1189 switch(pRequest->ulType)
1190 {
1191 case WSAASYNC_TERMINATE: // internal message
1192 fTerminate = TRUE;
1193 return 1;
1194
1195 case WSAASYNC_GETHOSTBYADDR: asyncGetHostByAddr (pRequest); rc = 1; break;
1196 case WSAASYNC_GETHOSTBYNAME: asyncGetHostByName (pRequest); rc = 1; break;
1197 case WSAASYNC_GETPROTOBYNAME: asyncGetProtoByName (pRequest); rc = 1; break;
1198 case WSAASYNC_GETPROTOBYNUMBER: asyncGetProtoByNumber(pRequest); rc = 1; break;
1199 case WSAASYNC_GETSERVBYNAME: asyncGetServByName (pRequest); rc = 1; break;
1200 case WSAASYNC_GETSERVBYPORT: asyncGetServByPort (pRequest); rc = 1; break;
1201 case WSAASYNC_SELECT: asyncSelect (pRequest); rc = 1; break;
1202
1203 default:
1204 dprintf(("WSOCK32: WSAAsyncWorker::dispatchRequest - invalid request type %d\n",
1205 pRequest->ulType));
1206 rc = 1; break;
1207 }
1208
1209 pRequest->ulState = RS_DONE;
1210 return rc;
1211}
1212
1213
1214/*****************************************************************************
1215 * Name :
1216 * Purpose :
1217 * Parameters:
1218 * Variables :
1219 * Result :
1220 * Remark :
1221 * Status : UNTESTED STUB
1222 *
1223 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1224 *****************************************************************************/
1225// process all requests in queue until termination
1226void WSAAsyncWorker::processingLoop(void)
1227{
1228 PASYNCREQUEST pRequest;
1229 APIRET rc;
1230 ULONG ulPostCount;
1231
1232 do
1233 {
1234 // work as long as there are requests
1235 do
1236 {
1237 pRequest = popRequest(); // get request from queue
1238 if (pRequest != NULL)
1239 {
1240 dispatchRequest(pRequest); // process request
1241 delete pRequest; // free the memory
1242 }
1243 }
1244 while (pRequest != NULL);
1245
1246 // wait for semaphore
1247 fBlocking = FALSE;
1248 rc = DosWaitEventSem(hevRequest, SEM_INDEFINITE_WAIT);
1249 fBlocking = TRUE;
1250 rc = DosResetEventSem(hevRequest, &ulPostCount);
1251 }
1252 while (fTerminate == FALSE);
1253
1254 tidWorker = 0; // clear worker thread id
1255}
1256
1257
1258/*****************************************************************************
1259 * Name :
1260 * Purpose :
1261 * Parameters:
1262 * Variables :
1263 * Result :
1264 * Remark :
1265 * Status : UNTESTED STUB
1266 *
1267 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1268 *****************************************************************************/
1269// thread procedure
1270void _Optlink WorkerThreadProc(void* pParam)
1271{
1272 // convert object pointer
1273 WSAAsyncWorker* pWSAAsyncWorker = (WSAAsyncWorker*)pParam;
1274 pWSAAsyncWorker->processingLoop(); // processing loop
1275}
1276
1277
1278/*****************************************************************************
1279 * Name :
1280 * Purpose :
1281 * Parameters:
1282 * Variables :
1283 * Result :
1284 * Remark :
1285 * Status : UNTESTED STUB
1286 *
1287 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1288 *****************************************************************************/
1289// the real function calls
1290ODINFUNCTION5(HANDLE, WSAAsyncGetHostByName, HWND, hwnd,
1291 unsigned int, wMsg,
1292 const char*, name,
1293 char*, buf,
1294 int, buflen)
1295{
1296 dprintf(("name = %s\n", name));
1297 PASYNCREQUEST pRequest = wsaWorker->createRequest(WSAASYNC_GETHOSTBYNAME,
1298 (HWND) hwnd,
1299 (ULONG)wMsg,
1300 (PVOID)buf,
1301 (ULONG)buflen,
1302 (ULONG)name);
1303 if (pRequest != NULL)
1304 {
1305 // success
1306 wsaWorker->pushRequest(pRequest);
1307 WSASetLastError(ERROR_SUCCESS);
1308 return (HANDLE)pRequest;
1309 }
1310 else
1311 {
1312 // error
1313 WSASetLastError(WSAENOBUFS);
1314 return 0;
1315 }
1316}
1317
1318
1319/*****************************************************************************
1320 * Name :
1321 * Purpose :
1322 * Parameters:
1323 * Variables :
1324 * Result :
1325 * Remark :
1326 * Status : UNTESTED STUB
1327 *
1328 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1329 *****************************************************************************/
1330// the real function calls
1331ODINFUNCTION7(HANDLE, WSAAsyncGetHostByAddr, HWND, hwnd,
1332 unsigned int, wMsg,
1333 const char*, addr,
1334 int, len,
1335 int, type,
1336 char*, buf,
1337 int, buflen)
1338{
1339 PASYNCREQUEST pRequest = wsaWorker->createRequest(WSAASYNC_GETHOSTBYADDR,
1340 (HWND) hwnd,
1341 (ULONG)wMsg,
1342 (PVOID)buf,
1343 (ULONG)buflen,
1344 (ULONG)addr,
1345 (ULONG)len,
1346 (ULONG)type);
1347 if (pRequest != NULL)
1348 {
1349 // success
1350 wsaWorker->pushRequest(pRequest);
1351 WSASetLastError(ERROR_SUCCESS);
1352 return (HANDLE)pRequest;
1353 }
1354 else
1355 {
1356 // error
1357 WSASetLastError(WSAENOBUFS);
1358 return 0;
1359 }
1360}
1361
1362
1363/*****************************************************************************
1364 * Name :
1365 * Purpose :
1366 * Parameters:
1367 * Variables :
1368 * Result :
1369 * Remark :
1370 * Status : UNTESTED STUB
1371 *
1372 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1373 *****************************************************************************/
1374// the real function calls
1375ODINFUNCTION6(HANDLE, WSAAsyncGetServByName, HWND, hwnd,
1376 unsigned int, wMsg,
1377 const char*, name,
1378 const char*, proto,
1379 char*, buf,
1380 int, buflen)
1381{
1382 dprintf(("name = %s, proto = %s\n", name, proto));
1383 PASYNCREQUEST pRequest = wsaWorker->createRequest(WSAASYNC_GETSERVBYNAME,
1384 (HWND) hwnd,
1385 (ULONG)wMsg,
1386 (PVOID)buf,
1387 (ULONG)buflen,
1388 (ULONG)name,
1389 (ULONG)proto);
1390 if (pRequest != NULL)
1391 {
1392 // success
1393 wsaWorker->pushRequest(pRequest);
1394 WSASetLastError(ERROR_SUCCESS);
1395 return (HANDLE)pRequest;
1396 }
1397 else
1398 {
1399 // error
1400 WSASetLastError(WSAENOBUFS);
1401 return 0;
1402 }
1403}
1404
1405
1406/*****************************************************************************
1407 * Name :
1408 * Purpose :
1409 * Parameters:
1410 * Variables :
1411 * Result :
1412 * Remark :
1413 * Status : UNTESTED STUB
1414 *
1415 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1416 *****************************************************************************/
1417// the real function calls
1418ODINFUNCTION6(HANDLE, WSAAsyncGetServByPort, HWND, hwnd,
1419 unsigned int, wMsg,
1420 int, port,
1421 const char*, proto,
1422 char*, buf,
1423 int, buflen)
1424{
1425 dprintf(("proto = %s\n", proto));
1426 PASYNCREQUEST pRequest = wsaWorker->createRequest(WSAASYNC_GETSERVBYPORT,
1427 (HWND) hwnd,
1428 (ULONG)wMsg,
1429 (PVOID)buf,
1430 (ULONG)buflen,
1431 (ULONG)port,
1432 (ULONG)proto);
1433 if (pRequest != NULL)
1434 {
1435 // success
1436 wsaWorker->pushRequest(pRequest);
1437 WSASetLastError(ERROR_SUCCESS);
1438 return (HANDLE)pRequest;
1439 }
1440 else
1441 {
1442 // error
1443 WSASetLastError(WSAENOBUFS);
1444 return 0;
1445 }
1446}
1447
1448
1449/*****************************************************************************
1450 * Name :
1451 * Purpose :
1452 * Parameters:
1453 * Variables :
1454 * Result :
1455 * Remark :
1456 * Status : UNTESTED STUB
1457 *
1458 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1459 *****************************************************************************/
1460// the real function calls
1461ODINFUNCTION5(HANDLE, WSAAsyncGetProtoByName, HWND, hwnd,
1462 unsigned int, wMsg,
1463 const char*, name,
1464 char*, buf,
1465 int, buflen)
1466{
1467 dprintf(("name = %s\n", name));
1468 PASYNCREQUEST pRequest = wsaWorker->createRequest(WSAASYNC_GETPROTOBYNAME,
1469 (HWND) hwnd,
1470 (ULONG)wMsg,
1471 (PVOID)buf,
1472 (ULONG)buflen,
1473 (ULONG)name);
1474 if (pRequest != NULL)
1475 {
1476 // success
1477 wsaWorker->pushRequest(pRequest);
1478 WSASetLastError(ERROR_SUCCESS);
1479 return (HANDLE)pRequest;
1480 }
1481 else
1482 {
1483 // error
1484 WSASetLastError(WSAENOBUFS);
1485 return 0;
1486 }
1487}
1488
1489
1490/*****************************************************************************
1491 * Name :
1492 * Purpose :
1493 * Parameters:
1494 * Variables :
1495 * Result :
1496 * Remark :
1497 * Status : UNTESTED STUB
1498 *
1499 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1500 *****************************************************************************/
1501// the real function calls
1502ODINFUNCTION5(HANDLE, WSAAsyncGetProtoByNumber, HWND, hwnd,
1503 unsigned int, wMsg,
1504 int, number,
1505 char*, buf,
1506 int, buflen)
1507{
1508 PASYNCREQUEST pRequest = wsaWorker->createRequest(WSAASYNC_GETPROTOBYNUMBER,
1509 (HWND) hwnd,
1510 (ULONG)wMsg,
1511 (PVOID)buf,
1512 (ULONG)buflen,
1513 (ULONG)number);
1514 if (pRequest != NULL)
1515 {
1516 // success
1517 wsaWorker->pushRequest(pRequest);
1518 WSASetLastError(ERROR_SUCCESS);
1519 return (HANDLE)pRequest;
1520 }
1521 else
1522 {
1523 // error
1524 WSASetLastError(WSAENOBUFS);
1525 return 0;
1526 }
1527}
1528
1529
1530/*****************************************************************************
1531 * Name :
1532 * Purpose : cancel a queued or busy request
1533 * Parameters:
1534 * Variables :
1535 * Result :
1536 * Remark :
1537 * Status : UNTESTED STUB
1538 *
1539 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1540 *****************************************************************************/
1541
1542ODINFUNCTION1(int, WSACancelAsyncRequest, HANDLE, hAsyncTaskHandle)
1543{
1544 PASYNCREQUEST pRequest = (PASYNCREQUEST)hAsyncTaskHandle;
1545 BOOL rc;
1546
1547 // remove request from queue
1548 rc = wsaWorker->cancelAsyncRequest(pRequest);
1549 if (rc == TRUE)
1550 {
1551 WSASetLastError(ERROR_SUCCESS);
1552 return ERROR_SUCCESS; // success
1553 }
1554 else
1555 {
1556 // error
1557 WSASetLastError(WSAEINVAL);
1558 return (SOCKET_ERROR);
1559 }
1560}
1561
1562
1563/*****************************************************************************
1564 * Name : WSAIsBlocking
1565 * Purpose :
1566 * Parameters:
1567 * Variables :
1568 * Result :
1569 * Remark :
1570 * Status : UNTESTED STUB
1571 *
1572 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1573 *****************************************************************************/
1574
1575ODINFUNCTION0(BOOL, WSAIsBlocking)
1576{
1577 return(wsaWorker->isBlocking());
1578}
1579
1580
1581/*****************************************************************************
1582 * Name :
1583 * Purpose :
1584 * Parameters:
1585 * Variables :
1586 * Result :
1587 * Remark :
1588 * Status : UNTESTED STUB
1589 *
1590 * Author : Patrick Haller [Tue, 1998/06/16 23:00]
1591 *****************************************************************************/
1592// the real function calls
1593
1594ODINFUNCTION4(int, WSAAsyncSelect,SOCKET, s,
1595 HWND, hwnd,
1596 unsigned int, wMsg,
1597 long, lEvent)
1598{
1599 // @@@PH 1999/11/21 implementation is completely wrong!
1600 // handle async select in a completely different way:
1601 // one thread per socket!
1602 PASYNCREQUEST pRequest = wsaWorker->createRequest(WSAASYNC_SELECT,
1603 (HWND) hwnd,
1604 (ULONG)wMsg,
1605 (PVOID)NULL,
1606 (ULONG)0,
1607 (ULONG)s,
1608 (ULONG)lEvent);
1609 if (pRequest != NULL) // request is OK ?
1610 {
1611 wsaWorker->pushRequest(pRequest);
1612
1613 // WSAAsyncSelect() can only fail if the flags specified don't match
1614 WSASetLastError(ERROR_SUCCESS);
1615 return ERROR_SUCCESS;
1616 }
1617 else
1618 {
1619 // error !
1620 WSASetLastError(WSAEINVAL);
1621 return SOCKET_ERROR;
1622 }
1623}
1624
Note: See TracBrowser for help on using the repository browser.