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

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

Fix: error checking for request queue

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