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

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

Add: reimplementation of WSA sockets

File size: 18.2 KB
Line 
1/* $Id: async.cpp,v 1.1 1999-10-20 01:18:28 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#include <os2win.h>
26//#include <wsock32.h>
27#include <misc.h>
28
29
30/*****************************************************************************
31 * Structures *
32 *****************************************************************************/
33
34// request types
35enum tagAsyncRequestType
36{
37 WSAASYNC_TERMINATE, // internal message
38 WSAASYNC_GETHOSTBYADDR,
39 WSAASYNC_GETHOSTBYNAME,
40 WSAASYNC_GETPROTOBYNAME,
41 WSAASYNC_GETPROTOBYNUMBER,
42 WSAASYNC_GETSERVBYNAME,
43 WSAASYNC_GETSERVBYPORT,
44 WSAASYNC_SELECT
45};
46
47
48// request states
49enum tagAsyncRequestStates
50{
51 RS_WAITING, // request is waiting in queue
52 RS_BUSY, // request is currently being serviced
53 RS_CANCELLED, // request has been cancelled
54 RS_DONE
55};
56
57
58typedef struct tagAsyncRequest
59{
60 struct tagAsyncRequest* pPrev; // pointer to previous request
61 struct tagAsyncRequest* pNext; // pointer to next request
62
63 ULONG ulType; // type of request
64 ULONG ulState; // state of request
65
66 HWND hwnd; // window handle to post message to
67 ULONG ulMessage; // message to post
68
69 PVOID pBuffer; // result buffer
70 ULONG ulBufferLength; // length of the return buffer
71
72 ULONG ul1; // multi purpose parameters
73 ULONG ul2;
74 ULONG ul3;
75 ULONG ul4;
76 ULONG ul5;
77
78} ASYNCREQUEST, *PASYNCREQUEST;
79
80
81
82/*****************************************************************************
83 * Implementation *
84 *****************************************************************************/
85
86class WSAAsyncWorker
87{
88 // private members
89 PASYNCREQUEST pRequestHead = NULL; // chain root
90 PASYNCREQUEST pRequestTail = NULL; // chain root
91 TID tidWorker = 0; // worker thread id
92 HEV hevRequest; // fired upon new request
93 HMUTEX hmtxRequestQueue; // request queue protection
94
95 // public members
96 public:
97 WSAAsyncWorker(void); // constructor
98 ~WSAAsyncWorker(); // destructor
99
100 PASYNCREQUEST createRequest (HWND hwnd,
101 ULONG ulMessage,
102 ULONG ul1 = 0,
103 ULONG ul2 = 0,
104 ULONG ul3 = 0,
105 ULONG ul4 = 0,
106 ULONG ul5 = 0);
107 void pushRequest (PASYNCREQUEST pRequest); // put request on queue
108
109
110
111 // protected members
112 protected:
113 BOOL fTerminate = FALSE; // got to die ?
114
115 TID startWorker (void); // start worker thread
116 void processingLoop (void); // "work"
117 int dispatchRequest(PASYNCREQUEST pRequest); // complete request
118 PASYNCREQUEST popRequest (void); // get one request from queue
119 BOOL deleteRequest (PASYNCREQUEST pRequest); // remove particular request
120
121 void lockQueue (void); // enter mutex
122 void unlockQueue (void); // leave mutex
123
124 // the real worker methods
125 void asyncGetHostByAddr (PASYNCREQUEST pRequest);
126 void asyncGetHostByName (PASYNCREQUEST pRequest);
127 void asyncGetProtoByName (PASYNCREQUEST pRequest);
128 void asyncGetProtoByNumber(PASYNCREQUEST pRequest);
129 void asyncGetServByName (PASYNCREQUEST pRequest);
130 void asyncGetServByPort (PASYNCREQUEST pRequest);
131};
132
133
134// constructor
135WSAAsyncWorker::WSAAsyncWorker(void)
136{
137 startWorker();
138}
139
140
141// destructor
142WSAAsyncWorker::~WSAAsyncWorker(void)
143{
144 // remove all requests
145 while (popRequest() != NULL);
146
147 // just in case ... terminate worker thread
148 if (tidWorker != 0)
149 {
150 fTerminate = TRUE;
151 DosPostEventSem(hevRequest);
152 }
153
154 DosCloseEventSem(hevRequest);
155 DosCloseMutexSem(hmtxRequestQueue);
156}
157
158
159
160// start worker thread if necessary
161TID WSAAsyncWorker::startWorker(void)
162{
163 APIRET rc;
164
165 if (tidWorker == 0)
166 {
167 // create semaphores
168 rc = DosCreateEventSem(NULL, // unnamed
169 &hevRequest,
170 0, // unshared
171 FALSE); // reset
172 if (rc != NO_ERROR)
173 {
174 dprintf(("WSOCK32: WSAAsyncWorker::startWorker - DosCreateEventSem = %08xh\n",
175 rc));
176
177 return 0;
178 }
179
180 rc = DosCreateMutexSem(NULL, // unnamed
181 &hmtxRequestQueue,
182 0, // unshared
183 FALSE); // unowned
184 if (rc != NO_ERROR)
185 {
186 dprintf(("WSOCK32: WSAAsyncWorker::startWorker - DosCreateMutexSem = %08xh\n",
187 rc));
188
189 DosCloseEventSem(hevRequest);
190 return 0;
191 }
192
193 // create thread
194 tidWorker = _beginthread(WorkerThreadProc,
195 (PVOID)this,
196 4096);
197 if (tidWorker == -1)
198 {
199 // cancel the whole thing
200 tidWorker = 0;
201 DosCloseEventSem(hevRequest);
202 DosCloseMutexSem(hmtxRequestQueue);
203 }
204 }
205
206 return tidWorker; // thread already running
207}
208
209
210// lock double-linked request chain
211void WSAAsyncWorker::lockQueue(void)
212{
213 DosRequestMutex(hmtxRequestQueue, SEM_INDEFINITE_WAIT);
214}
215
216
217// unlock double-linked request chain
218void WSAAsyncWorker::unlockQueue(void)
219{
220 DosReleaseMutex(hmtxRequestQueue);
221}
222
223
224// get request from queue
225PASYNCREQUEST WSAAsyncWorker::popRequest(void)
226{
227 PASYNCREQUEST pLast;
228
229 lockQueue(); // lock queue
230
231 // alter queue
232 pLast = pRequestTail;
233
234 if (pRequestTail != NULL)
235 if (pRequestTail->pPrev)
236 {
237 pRequestTail->pPrev->pNext = NULL; // cut off element
238 pRequestTail = pRequestTail->pPrev; // unlink previous element
239 }
240
241 unlockQueue(); // unlock queue
242
243 return (pLast); // return element
244}
245
246
247// insert request into queue
248void WSAAsyncWorker::pushRequest(PASYNCREQUEST pNew)
249{
250 lockQueue(); // lock queue
251
252 // alter queue
253 if (pRequestHead == NULL)
254 {
255 // first element in queue
256 pRequestHead = pNew;
257 pRequestTail = pNew;
258 pNew->pPrev = NULL;
259 pNew->pNext = NULL;
260 }
261 else
262 {
263 // chain in request
264 pNew->pPrev = NULL;
265 pNew->pNext = pRequestHead;
266 pRequestHead->pPrev = pNew;
267 pRequestHead = pNew;
268 }
269
270 // trigger thread!
271 DosPostEventSem(hevRequest);
272
273 unlockQueue(); // unlock queue
274}
275
276
277// delete particular request from queue
278BOOL WSAAsyncWorker::deleteRequest(PASYNCREQUEST pDelete)
279{
280 PASYNCREQUEST pRequest; // for verification
281 BOOL bResult = FALSE;
282
283 lockQueue(); // lock queue
284
285 // find request (optional, just for verification)
286 for (pRequest = pRequestHead;
287 pRequest != NULL;
288 pRequest = pRequest->pNext)
289 if (pRequest == pDelete)
290 break;
291
292 if (pRequest == pDelete) // if request has been found
293 {
294 // is request the head of the list ?
295 if (pDelete == pRequestHead)
296 {
297 pRequestHead = pDelete->pNext;
298 if (pRequestHead == NULL) // last element ?
299 pRequestTail = NULL;
300 else
301 pRequestHead->pPrev = NULL;
302 }
303 else
304 // if request the last in the list ?
305 if (pDelete == pRequestTail)
306 {
307 pRequestTail = pDelete->pPrev;
308 if (pRequestTail == NULL) // last element ?
309 pRequestHead = NULL;
310 else
311 pRequestTail->pNext = NULL;
312 }
313 else
314 // request is somewhere in the middle of the list
315 {
316 if (pDelete->pPrev != NULL)
317 pDelete->pPrev->pNext = pDelete->pNext;
318
319 if (pDelete->pNext != NULL)
320 pDelete->pNext->pPrev = pDelete->pPrev;
321 }
322
323 bResult = TRUE; // OK
324 }
325
326 unlockQueue(); // unlock queue
327 return bResult;
328}
329
330
331
332void WSAAsyncWorker::asyncGetHostByAddr (PASYNCREQUEST pRequest)
333{
334 struct hostent* pHostent;
335 USHORT usLength;
336 ULONG wParam;
337 ULONG lParam;
338 USHORT rc;
339
340 // result buffer length
341 usLength = min(pRequest->ulBufferLength, sizeof(struct hostent));
342
343 // call API
344 pHostent = gethostbyaddr((const char*)pRequest->u1,
345 (int) pRequest->u2,
346 (int) pRequest->u3);
347 if (pHostent == NULL) // error ?
348 {
349 rc = sock_errno(); // assuming OS/2 return codes are
350 WSASetLastError(rc); // same as Winsock return codes
351 }
352 else
353 {
354 // build result buffer
355 memcpy (pRequest->pBuffer,
356 pHostent,
357 usLength);
358 rc = 0;
359 }
360
361 // post result
362 PostMessageA(pRequest->hwnd,
363 pRequest->ulMessage,
364 (WPARAM)pRequest,
365 (LPARAM)(rc << 16 | usLength));
366
367 // M$ says, if PostMessageA fails, spin as long as window exists
368}
369
370void WSAAsyncWorker::asyncGetHostByName (PASYNCREQUEST pRequest)
371{
372 struct hostent* pHostent;
373 USHORT usLength;
374 ULONG wParam;
375 ULONG lParam;
376 USHORT rc;
377
378 // result buffer length
379 usLength = min(pRequest->ulBufferLength, sizeof(struct hostent));
380
381 // call API
382 pHostent = gethostbyname((const char*)pRequest->u1);
383 if (pHostent == NULL) // error ?
384 {
385 rc = sock_errno(); // assuming OS/2 return codes are
386 WSASetLastError(rc); // same as Winsock return codes
387 }
388 else
389 {
390 // build result buffer
391 memcpy (pRequest->pBuffer,
392 pHostent,
393 usLength);
394 rc = 0;
395 }
396
397 // post result
398 PostMessageA(pRequest->hwnd,
399 pRequest->ulMessage,
400 (WPARAM)pRequest,
401 (LPARAM)(rc << 16 | usLength));
402
403 // M$ says, if PostMessageA fails, spin as long as window exists
404}
405
406
407void WSAAsyncWorker::asyncGetProtoByName (PASYNCREQUEST pRequest)
408{
409 struct protoent* pProtoent;
410 USHORT usLength;
411 ULONG wParam;
412 ULONG lParam;
413 USHORT rc;
414
415 // result buffer length
416 usLength = min(pRequest->ulBufferLength, sizeof(struct protoent));
417
418 // call API
419 pProtoent = getprotobyname((const char*)pRequest->u1);
420 if (pProtoent == NULL) // error ?
421 {
422 rc = sock_errno(); // assuming OS/2 return codes are
423 WSASetLastError(rc); // same as Winsock return codes
424 }
425 else
426 {
427 // build result buffer
428 memcpy (pRequest->pBuffer,
429 pProtoent,
430 usLength);
431 rc = 0;
432 }
433
434 // post result
435 PostMessageA(pRequest->hwnd,
436 pRequest->ulMessage,
437 (WPARAM)pRequest,
438 (LPARAM)(rc << 16 | usLength));
439
440 // M$ says, if PostMessageA fails, spin as long as window exists
441}
442
443void WSAAsyncWorker::asyncGetProtoByNumber(PASYNCREQUEST pRequest)
444{
445 struct protoent* pProtoent;
446 USHORT usLength;
447 ULONG wParam;
448 ULONG lParam;
449 USHORT rc;
450
451 // result buffer length
452 usLength = min(pRequest->ulBufferLength, sizeof(struct protoent));
453
454 // call API
455 pProtoent = getprotobyname((int)pRequest->u1);
456 if (pProtoent == NULL) // error ?
457 {
458 rc = sock_errno(); // assuming OS/2 return codes are
459 WSASetLastError(rc); // same as Winsock return codes
460 }
461 else
462 {
463 // build result buffer
464 memcpy (pRequest->pBuffer,
465 pProtoent,
466 usLength);
467 rc = 0;
468 }
469
470 // post result
471 PostMessageA(pRequest->hwnd,
472 pRequest->ulMessage,
473 (WPARAM)pRequest,
474 (LPARAM)(rc << 16 | usLength));
475
476 // M$ says, if PostMessageA fails, spin as long as window exists
477}
478
479
480void WSAAsyncWorker::asyncGetServByName(PASYNCREQUEST pRequest)
481{
482 struct servent* pServent;
483 USHORT usLength;
484 ULONG wParam;
485 ULONG lParam;
486 USHORT rc;
487
488 // result buffer length
489 usLength = min(pRequest->ulBufferLength, sizeof(struct servent));
490
491 // call API
492 pServent = getservbyname((const char*)pRequest->u1,
493 (const char*)pRequest->u2);
494 if (pServent == NULL) // error ?
495 {
496 rc = sock_errno(); // assuming OS/2 return codes are
497 WSASetLastError(rc); // same as Winsock return codes
498 }
499 else
500 {
501 // build result buffer
502 memcpy (pRequest->pBuffer,
503 pServent,
504 usLength);
505 rc = 0;
506 }
507
508 // post result
509 PostMessageA(pRequest->hwnd,
510 pRequest->ulMessage,
511 (WPARAM)pRequest,
512 (LPARAM)(rc << 16 | usLength));
513
514 // M$ says, if PostMessageA fails, spin as long as window exists
515}
516
517
518void WSAAsyncWorker::asyncGetServByPort(PASYNCREQUEST pRequest)
519{
520 struct servent* pServent;
521 USHORT usLength;
522 ULONG wParam;
523 ULONG lParam;
524 USHORT rc;
525
526 // result buffer length
527 usLength = min(pRequest->ulBufferLength, sizeof(struct servent));
528
529 // call API
530 pServent = getservbyport((int )pRequest->u1,
531 (const char*)pRequest->u2);
532 if (pServent == NULL) // error ?
533 {
534 rc = sock_errno(); // assuming OS/2 return codes are
535 WSASetLastError(rc); // same as Winsock return codes
536 }
537 else
538 {
539 // build result buffer
540 memcpy (pRequest->pBuffer,
541 pServent,
542 usLength);
543 rc = 0;
544 }
545
546 // post result
547 PostMessageA(pRequest->hwnd,
548 pRequest->ulMessage,
549 (WPARAM)pRequest,
550 (LPARAM)(rc << 16 | usLength));
551
552 // M$ says, if PostMessageA fails, spin as long as window exists
553}
554
555
556// process one request
557int WSAAsyncWorker::dispatchRequest(PASYNCREQUEST pRequest)
558{
559 // check request state first
560 switch(pRequest->ulState)
561 {
562 case RS_WAITING: // OK, proceed
563 break;
564
565 case RS_BUSY: // oops, shouldn't happen
566 dprintf(("WSOCK32: WSAAsyncWorker::dispatchRequest - got already busy request %08xh\n",
567 pRequest));
568 return 1;
569
570 case RS_CANCELLED: // don't service request
571 // request has been removed from queue already
572 return 1;
573 }
574
575 // OK, servicing request
576 pRequest->ulStatus = RS_BUSY;
577
578 switch(pRequest->ulType)
579 {
580 case WSAASYNC_TERMINATE: // internal message
581 fTerminate = TRUE;
582 return 1;
583
584 case WSAASYNC_GETHOSTBYADDR:
585 asyncGetHostByAddr(pRequest->hwnd,
586 pRequest->ulMessage,
587 (char*)pRequest->u1,
588 (int) pRequest->u2,
589 (int) pRequest->u3,
590 (char*)pRequest->u4,
591 (int) pRequest->u5);
592 return 1;
593
594 case WSAASYNC_GETHOSTBYNAME:
595 asyncGetHostByName(pRequest->hwnd,
596 pRequest->ulMessage,
597 (char*)pRequest->u1,
598 (char*)pRequest->u2,
599 (int) pRequest->u3);
600 break;
601
602 case WSAASYNC_GETPROTOBYNAME:
603 asyncGetProtoByName (pRequest->hwnd,
604 pRequest->ulMessage,
605 (char*)pRequest->u1,
606 (char*)pRequest->u2,
607 (int) pRequest->u3);
608 break;
609
610 case WSAASYNC_GETPROTOBYNUMBER:
611 asyncGetProtoByNumber(pRequest->hwnd,
612 pRequest->ulMessage,
613 (int) pRequest->u1,
614 (char*)pRequest->u2,
615 (int) pRequest->u3);
616 break;
617
618 case WSAASYNC_GETSERVBYNAME:
619 asyncGetServByName (pRequest->hwnd,
620 pRequest->ulMessage,
621 (char*)pRequest->u1,
622 (char*)pRequest->u2,
623 (char*)pRequest->u3,
624 (int) pRequest->u4);
625 break;
626
627 case WSAASYNC_GETSERVBYPORT:
628 asyncGetServByPort (pRequest->hwnd,
629 pRequest->ulMessage,
630 (int) pRequest->u1,
631 (char*)pRequest->u2,
632 (char*)pRequest->u3,
633 (int) pRequest->u4);
634 break;
635
636 case WSAASYNC_SELECT:
637 break;
638
639 default:
640 dprintf(("WSOCK32: WSAAsyncWorker::dispatchRequest - invalid request type %d\n",
641 pRequest->ulType));
642 return 1;
643 }
644
645 pRequest->ulStatus = RS_DONE;
646 return 0;
647}
648
649
650// process all requests in queue until termination
651void WSAAsyncWorker::processingLoop(void)
652{
653 PASYNCREQUEST pRequest;
654 APIRET rc;
655 ULONG ulPostCount;
656
657 do
658 {
659 // work as long as there are requests
660 do
661 {
662 pRequest = popRequest(); // get request from queue
663 if (pRequest != NULL)
664 dispatchRequest(pRequest); // process request
665 }
666 while (pRequest != NULL)
667
668 // wait for semaphore
669 rc = DosWaitEventSem(hevRequest, SEM_INDEFINITE_WAIT);
670 rc = DosResetEventSem(hevRequest, &ulPostCount);
671 }
672 while (fTerminate == FALSE);
673
674 tidWorker = 0; // clear worker thread id
675}
676
677
678// thread procedure
679void _System WorkerThreadProc(PVOID pParam)
680{
681 // convert object pointer
682 WSAAsyncWorker* pWSAAsyncWorker = (WSAAsyncWorker*)pParam;
683 pWSAAsyncWorker->processingLoop(); // processing loop
684}
685
686
687// the real function calls
688ODINFUNCTION5(HANDLE, WSAAsyncGetHostByName, HWND, hwnd,
689 unsigned int, wMsg,
690 const char*, name,
691 char*, buf,
692 int, buflen)
693{
694 PASYNCREQUEST pRequest = wsaWorker->createRequest((HWND) hwnd,
695 (PVOID)buf,
696 (ULONG)buflen,
697 (ULONG)wMsg,
698 (ULONG)name);
699 wsaWorker->pushRequest(pRequest);
700 return (HANDLE)pRequest;
701}
702
703
Note: See TracBrowser for help on using the repository browser.