source: trunk/src/wsock32/new/asyncapi.cpp@ 3210

Last change on this file since 3210 was 3210, checked in by sandervl, 25 years ago

bugfixes

File size: 19.3 KB
Line 
1/* $Id: asyncapi.cpp,v 1.3 2000-03-23 23:07:22 sandervl Exp $ */
2
3/*
4 *
5 * Win32 SOCK32 for OS/2 (Async apis)
6 *
7 * Copyright (C) 2000 Sander van Leeuwen (sandervl@xs4all.nl)
8 *
9 * Parts based on Wine code: (dlls\winsock\async.c)
10 * (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
11 * (C) 1999 Marcus Meissner
12 *
13 * Project Odin Software License can be found in LICENSE.TXT
14 *
15 */
16#define INCL_BASE
17#include <os2wrap.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <odin.h>
22#include <odinwrap.h>
23#include <os2sel.h>
24#include <misc.h>
25#include <win32api.h>
26#include "wsock32.h"
27#include "asyncthread.h"
28#include "wsastruct.h"
29
30#define DBG_LOCALLOG DBG_async
31#include "dbglocal.h"
32
33ODINDEBUGCHANNEL(WSOCK32-ASYNC)
34
35//******************************************************************************
36//******************************************************************************
37void ASYNCCNV WSAsyncThreadProc(void *pparm)
38{
39 PASYNCTHREADPARM pThreadParm = (PASYNCTHREADPARM)pparm;
40 LPARAM lParam;
41 int size = 0;
42 int fail = NO_ERROR;
43
44 if(!pThreadParm->fCancelled)
45 {
46 switch(pThreadParm->request)
47 {
48 case ASYNC_GETHOSTBYNAME:
49 case ASYNC_GETHOSTBYADDR:
50 {
51 struct hostent *ret;
52
53 if(pThreadParm->request == ASYNC_GETHOSTBYNAME) {
54 ret = gethostbyname(pThreadParm->u.gethostbyname.name);
55
56 free(pThreadParm->u.gethostbyname.name);
57 pThreadParm->u.gethostbyname.name = 0;
58 }
59 else {
60 ret = gethostbyaddr(pThreadParm->u.gethostbyaddr.addr,
61 pThreadParm->u.gethostbyaddr.len,
62 pThreadParm->u.gethostbyaddr.type);
63
64 free(pThreadParm->u.gethostbyaddr.addr);
65 pThreadParm->u.gethostbyaddr.addr = 0;
66 }
67 if (ret != NULL) {
68 size = WS_copy_he((struct ws_hostent *)pThreadParm->buf,
69 pThreadParm->buf,
70 pThreadParm->buflen,
71 ret);
72 if(size < 0) {
73 fail = WSAENOBUFS;
74 size = -size;
75 }
76 }
77 else fail = WSANO_DATA;
78 break;
79 }
80
81 case ASYNC_GETPROTOBYNAME:
82 case ASYNC_GETPROTOBYNUMBER:
83 {
84 struct protoent *ret;
85
86 if(pThreadParm->request == ASYNC_GETPROTOBYNAME) {
87 ret = getprotobyname(pThreadParm->u.getprotobyname.name);
88
89 free(pThreadParm->u.getprotobyname.name);
90 pThreadParm->u.getprotobyname.name = 0;
91 }
92 else ret = getprotobynumber(pThreadParm->u.getprotobynumber.number);
93
94 if (ret != NULL) {
95 size = WS_copy_pe((struct ws_protoent *)pThreadParm->buf,
96 pThreadParm->buf,
97 pThreadParm->buflen,
98 ret);
99 if(size < 0) {
100 fail = WSAENOBUFS;
101 size = -size;
102 }
103 }
104 else fail = WSANO_DATA;
105
106 break;
107 }
108
109 case ASYNC_GETSERVBYNAME:
110 case ASYNC_GETSERVBYPORT:
111 {
112 struct servent *ret;
113
114 if(pThreadParm->request == ASYNC_GETSERVBYNAME) {
115 ret = getservbyname(pThreadParm->u.getservbyname.name, pThreadParm->u.getservbyname.proto);
116
117 free(pThreadParm->u.getservbyname.name);
118 pThreadParm->u.getservbyname.name = 0;
119
120 if(pThreadParm->u.getservbyname.proto) {
121 free(pThreadParm->u.getservbyname.proto);
122 pThreadParm->u.getservbyname.proto = 0;
123 }
124
125 }
126 else {
127 ret = getservbyport(pThreadParm->u.getservbyport.port, pThreadParm->u.getservbyport.proto);
128 if(pThreadParm->u.getservbyport.proto) {
129 free(pThreadParm->u.getservbyport.proto);
130 pThreadParm->u.getservbyport.proto = 0;
131 }
132 }
133
134 if (ret != NULL) {
135 size = WS_copy_se((struct ws_servent *)pThreadParm->buf,
136 pThreadParm->buf,
137 pThreadParm->buflen,
138 ret);
139 if(size < 0) {
140 fail = WSAENOBUFS;
141 size = -size;
142 }
143 }
144 else fail = WSANO_DATA;
145 break;
146 }
147 }
148 }
149 lParam = (fail << 16) | size;
150
151 if(!pThreadParm->fCancelled) {
152 dprintf(("WSAsyncThreadProc %x %x %x %x", pThreadParm->hwnd, pThreadParm->msg, pThreadParm->hAsyncTaskHandle, lParam));
153 PostMessageA(pThreadParm->hwnd, pThreadParm->msg,
154 (WPARAM)pThreadParm->hAsyncTaskHandle, lParam);
155 }
156}
157//******************************************************************************
158//******************************************************************************
159LHANDLE WSAAsyncRequest(AsyncRequestType requesttype, HWND hwnd, int msg, char *buf,
160 int buflen, PVOID param1, PVOID param2, PVOID param3,
161 PVOID param4)
162{
163 PASYNCTHREADPARM pThreadParm;
164 LHANDLE hAsyncRequest = 0;
165 LPSTR tempname = 0;
166 LPSTR tempproto = 0;
167 LPSTR tempaddr = 0;
168
169 if(!fWSAInitialized)
170 {
171 WSASetLastError(WSANOTINITIALISED);
172 }
173 else
174 if(WSAIsBlocking())
175 {
176 WSASetLastError(WSAEINPROGRESS); // blocking call in progress
177 }
178 else
179 if(!IsWindow(hwnd))
180 {
181 WSASetLastError(WSAEINVAL); // invalid parameter
182 }
183 else
184 if(buf == NULL || buflen == 0) {
185 WSASetLastError(WSAENOBUFS); // invalid parameter
186 }
187 else
188 {
189 pThreadParm = (PASYNCTHREADPARM)malloc(sizeof(ASYNCTHREADPARM));
190 if(pThreadParm == NULL) {
191 dprintf(("WSAAsyncRequest: malloc failure!"));
192 DebugInt3();
193 WSASetLastError(WSAEFAULT);
194 return 0;
195 }
196 memset(pThreadParm, 0, sizeof(*pThreadParm));
197 pThreadParm->request= requesttype;
198 pThreadParm->hwnd = hwnd;
199 pThreadParm->msg = msg;
200 pThreadParm->buf = buf;
201 pThreadParm->buflen = buflen;
202
203 switch(requesttype) {
204 case ASYNC_GETHOSTBYNAME:
205 tempname = (LPSTR)malloc(strlen((char *)param1)+1);
206 if(tempname == NULL)
207 {
208 dprintf(("WSAAsyncGetHostByName: malloc failure!"));
209 DebugInt3();
210 WSASetLastError(WSAEFAULT);
211 return 0;
212 }
213 pThreadParm->u.gethostbyname.name = tempname;
214 strcpy(pThreadParm->u.gethostbyname.name, (char *)param1);
215 break;
216
217 case ASYNC_GETHOSTBYADDR:
218 tempaddr = (LPSTR)malloc(strlen((char *)param1)+1);
219 if(tempaddr == NULL)
220 {
221 dprintf(("WSAAsyncGetHostByAddr: malloc failure!"));
222 DebugInt3();
223 WSASetLastError(WSAEFAULT);
224 return 0;
225 }
226
227 pThreadParm->u.gethostbyaddr.len = (int)param2;
228 pThreadParm->u.gethostbyaddr.type = (int)param3;
229 pThreadParm->u.gethostbyaddr.addr = tempaddr;
230 strcpy(pThreadParm->u.gethostbyaddr.addr, (char *)param1);
231 break;
232
233 case ASYNC_GETPROTOBYNAME:
234 tempname = (LPSTR)malloc(strlen((char *)param1)+1);
235 if(tempname == NULL)
236 {
237 dprintf(("WSAAsyncGetProtoByName: malloc failure!"));
238 DebugInt3();
239 WSASetLastError(WSAEFAULT);
240 return 0;
241 }
242 pThreadParm->u.getprotobyname.name = tempname;
243 strcpy(pThreadParm->u.getprotobyname.name, (char *)param1);
244 break;
245
246 case ASYNC_GETPROTOBYNUMBER:
247 pThreadParm->u.getprotobynumber.number = (int)param1;
248 break;
249
250 case ASYNC_GETSERVBYNAME:
251 tempname = (LPSTR)malloc(strlen((char *)param1)+1);
252 tempproto = NULL;
253 if(param2) {
254 tempproto = (LPSTR)malloc(strlen((char *)param2)+1);
255 }
256 if(tempname == NULL || (param2 && !tempproto))
257 {
258 dprintf(("WSAAsyncGetServByName: malloc failure!"));
259 DebugInt3();
260 WSASetLastError(WSAEFAULT);
261 return 0;
262 }
263 pThreadParm->u.getservbyname.name = tempname;
264 strcpy(pThreadParm->u.getservbyname.name, (char *)param1);
265 pThreadParm->u.getservbyname.proto = tempproto;
266 if(param2)
267 strcpy(pThreadParm->u.getservbyname.proto, (char *)param2);
268 break;
269
270 case ASYNC_GETSERVBYPORT:
271 if(param2) {
272 tempproto = (LPSTR)malloc(strlen((char *)param2)+1);
273 }
274 if(param2 && !tempproto)
275 {
276 dprintf(("WSAAsyncGetServByPort: malloc failure!"));
277 DebugInt3();
278 WSASetLastError(WSAEFAULT);
279 return 0;
280 }
281 pThreadParm->u.getservbyport.port = (int)param1;
282 pThreadParm->u.getservbyport.proto = tempproto;
283 if(param2)
284 strcpy(pThreadParm->u.getservbyport.proto, (char *)param2);
285 break;
286 }
287 hAsyncRequest = (LHANDLE)QueueAsyncJob(WSAsyncThreadProc, pThreadParm);
288 if(hAsyncRequest == 0) {
289 free(pThreadParm);
290 if(tempname) free(tempname);
291 if(tempaddr) free(tempaddr);
292 if(tempproto) free(tempproto);
293
294 dprintf(("WSAAsyncRequest: QueueAsyncJob failure!"));
295 DebugInt3();
296 WSASetLastError(WSAEFAULT);
297 return 0;
298 }
299 return hAsyncRequest;
300 }
301 return 0;
302}
303//******************************************************************************
304//******************************************************************************
305ODINFUNCTION5(LHANDLE,WSAAsyncGetHostByName,
306 HWND,hWnd,
307 u_int,wMsg,
308 const char *,name,
309 char *,buf,
310 int,buflen)
311{
312 dprintf(("WSAAsyncGetHostByName %s", name));
313
314 return WSAAsyncRequest(ASYNC_GETHOSTBYNAME, hWnd, wMsg, buf, buflen,
315 (PVOID)name, 0, 0, 0);
316}
317//******************************************************************************
318//******************************************************************************
319ODINFUNCTION7(LHANDLE,WSAAsyncGetHostByAddr,
320 HWND,hWnd,
321 u_int,wMsg,
322 const char *,addr,
323 int,len,
324 int,type,
325 char *,buf,
326 int,buflen)
327{
328 dprintf(("WSAAsyncGetHostByAddr %s", addr));
329
330 return WSAAsyncRequest(ASYNC_GETHOSTBYADDR, hWnd, wMsg, buf, buflen,
331 (PVOID)addr, (PVOID)len, (PVOID)type, 0);
332}
333//******************************************************************************
334//******************************************************************************
335ODINFUNCTION5(LHANDLE,WSAAsyncGetProtoByName,
336 HWND,hWnd,
337 u_int,wMsg,
338 const char *,name,
339 char *,buf,
340 int,buflen)
341{
342 dprintf(("WSAAsyncGetProtoByName %s", name));
343
344 return WSAAsyncRequest(ASYNC_GETPROTOBYNAME, hWnd, wMsg, buf, buflen,
345 (PVOID)name, 0, 0, 0);
346}
347//******************************************************************************
348//******************************************************************************
349ODINFUNCTION5(LHANDLE,WSAAsyncGetProtoByNumber,
350 HWND,hWnd,
351 u_int,wMsg,
352 int,number,
353 char *,buf,
354 int,buflen)
355{
356 dprintf(("WSAAsyncGetProtoByNumber %d", number));
357
358 return WSAAsyncRequest(ASYNC_GETPROTOBYNUMBER, hWnd, wMsg, buf, buflen,
359 (PVOID)number, 0, 0, 0);
360}
361//******************************************************************************
362//******************************************************************************
363ODINFUNCTION6(LHANDLE,WSAAsyncGetServByName,
364 HWND,hWnd,
365 u_int,wMsg,
366 const char *,name,
367 const char *,proto,
368 char *,buf,
369 int,buflen)
370{
371 dprintf(("WSAAsyncGetServByName %s", name));
372
373 return WSAAsyncRequest(ASYNC_GETSERVBYNAME, hWnd, wMsg, buf, buflen,
374 (PVOID)name, (PVOID)proto, 0, 0);
375}
376//******************************************************************************
377//******************************************************************************
378ODINFUNCTION6(LHANDLE,WSAAsyncGetServByPort,
379 HWND,hWnd,
380 u_int,wMsg,
381 int,port,
382 const char *,proto,
383 char *,buf,
384 int,buflen)
385{
386 dprintf(("WSAAsyncGetServByPort %d %s", port, proto));
387
388 return WSAAsyncRequest(ASYNC_GETSERVBYPORT, hWnd, wMsg, buf, buflen,
389 (PVOID)port, (PVOID)proto, 0, 0);
390}
391//******************************************************************************
392//******************************************************************************
393void AsyncNotifyEvent(PASYNCTHREADPARM pThreadParm, ULONG event, ULONG socket_error)
394{
395 pThreadParm->u.asyncselect.lEventsPending &= ~event;
396
397 event = WSAMAKESELECTREPLY(event, socket_error);
398
399 dprintf(("AsyncNotifyEvent %x %x %x %x", pThreadParm->u.asyncselect.s, pThreadParm->hwnd, pThreadParm->msg, event));
400 PostMessageA(pThreadParm->hwnd, pThreadParm->msg, (WPARAM)pThreadParm->u.asyncselect.s,
401 (LPARAM)event);
402}
403//******************************************************************************
404#define nr(i) ((i != -1) ? 1 : 0)
405#define ready(i) ((i != -1) && (sockets[i] != -1))
406//******************************************************************************
407void ASYNCCNV WSAsyncSelectThreadProc(void *pparm)
408{
409 PASYNCTHREADPARM pThreadParm = (PASYNCTHREADPARM)pparm;
410 SOCKET sockets[3];
411 SOCKET s = pThreadParm->u.asyncselect.s;
412 int noread, nowrite, noexcept, state, sockoptlen, sockoptval;
413 int tmp, i, lEventsPending, ret, bytesread;
414
415 while(TRUE)
416 {
417asyncloopstart:
418 i = 0;
419 noread = nowrite = noexcept = -1;
420
421 //break if user cancelled request
422 if(pThreadParm->u.asyncselect.lEvents == 0) {
423 break;
424 }
425
426 lEventsPending = pThreadParm->u.asyncselect.lEventsPending;
427 //block if no events are pending
428 if(lEventsPending == 0)
429 {
430 //wait for events to be enabled
431 pThreadParm->u.asyncselect.asyncSem->wait();
432 //reset event semaphore
433 pThreadParm->u.asyncselect.asyncSem->reset();
434 continue;
435 }
436
437 if(lEventsPending & (FD_READ | FD_CLOSE | FD_ACCEPT)) {
438 noread = i++;
439 sockets[noread] = s;
440 }
441 if((lEventsPending & FD_CONNECT) ||
442 ((lEventsPending & FD_WRITE) &&
443 (!(ioctl(s, FIOBSTATUS, (char *)&tmp, sizeof(tmp)) & SS_CANTSENDMORE))))
444 {
445 nowrite = i++;
446 sockets[nowrite] = s;
447 }
448 if(lEventsPending & FD_OOB) {
449 noexcept = i++;
450 sockets[noexcept] = s;
451 }
452
453// dprintf(("WSAsyncSelectThreadProc %x rds=%d, wrs=%d, oos =%d, pending = %x", pThreadParm->u.asyncselect.s, noread, nowrite, noexcept, lEventsPending));
454
455 ret = select((int *)sockets, nr(noread), nr(nowrite), nr(noexcept), -1);
456 if(ret == SOCKET_ERROR) {
457 int selecterr = sock_errno();
458 dprintf(("WSAsyncSelectThreadProc %x rds=%d, wrs=%d, oos =%d, pending = %x select returned %x", pThreadParm->u.asyncselect.s, noread, nowrite, noexcept, lEventsPending, selecterr));
459 switch(selecterr)
460 {
461 case SOCEINTR:
462 goto asyncloopstart; //so_cancel was called
463
464 case SOCECONNRESET:
465 case SOCEPIPE:
466 if(lEventsPending & FD_CLOSE)
467 AsyncNotifyEvent(pThreadParm, FD_CLOSE, WSAECONNRESET);
468
469 //remote connection broken (so can't receive data anymore)
470 //but can still send
471 pThreadParm->u.asyncselect.lEventsPending &= ~(FD_READ | FD_ACCEPT);
472 goto asyncloopstart;
473
474 case SOCEINVAL:
475 if(lEventsPending & FD_CLOSE)
476 AsyncNotifyEvent(pThreadParm, FD_CLOSE, selecterr);
477 break;
478 default:
479 dprintf(("WSAsyncSelectThreadProc: select SOCKET_ERROR %x", selecterr));
480 break; //something bad happened
481 }
482 break;
483 }
484
485 if(ready(nowrite))
486 {
487 state = ioctl(s, FIOBSTATUS, (char *)&tmp, sizeof(tmp));
488
489 if(lEventsPending & FD_CONNECT) {
490 if(state & SS_ISCONNECTED) {
491 AsyncNotifyEvent(pThreadParm, FD_CONNECT, NO_ERROR);
492 }
493 else {
494 sockoptlen = sizeof(int);
495
496 ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
497 (char *) &sockoptval, &sockoptlen);
498 if(sockoptval == WSAECONNREFUSED) {
499 AsyncNotifyEvent(pThreadParm, FD_CONNECT, WSAECONNREFUSED);
500 }
501 }
502 }
503 else
504 if(!(state & SS_CANTSENDMORE) && (lEventsPending & FD_WRITE)) {
505 AsyncNotifyEvent(pThreadParm, FD_WRITE, NO_ERROR);
506 }
507 }
508
509 if(ready(noread))
510 {
511 state = ioctl(s, FIONREAD, (CHAR *) &bytesread, sizeof(bytesread));
512 if(state == SOCKET_ERROR) {
513 if(lEventsPending & FD_CLOSE)
514 {
515 AsyncNotifyEvent(pThreadParm, FD_CLOSE, NO_ERROR);
516 //remote connection broken (so can't receive data anymore)
517 //but can still send
518 pThreadParm->u.asyncselect.lEventsPending &= ~(FD_READ | FD_ACCEPT);
519 continue;
520 }
521 else {
522 dprintf(("WSAsyncSelectThreadProc: ioctl SOCKET_ERROR!"));
523 break; //todo: correct???
524 }
525 }
526 if(lEventsPending & FD_ACCEPT)
527 {
528 sockoptlen = sizeof(sockoptlen);
529
530 ret = getsockopt(s, SOL_SOCKET, SO_OPTIONS,
531 (char *) &sockoptval, &sockoptlen);
532 if(ret == SOCKET_ERROR) {
533 dprintf(("WSAsyncSelectThreadProc: getsockopt SOCKET_ERROR!"));
534 break;
535 }
536 if((sockoptval & SO_ACCEPTCONN) == SO_ACCEPTCONN) {
537 AsyncNotifyEvent(pThreadParm, FD_ACCEPT, NO_ERROR);
538 }
539 }
540 if((lEventsPending & FD_READ) && bytesread > 0) {
541 AsyncNotifyEvent(pThreadParm, FD_READ, NO_ERROR);
542 }
543 }
544 if(ready(noexcept))
545 {
546 if(lEventsPending & FD_OOB) {
547 AsyncNotifyEvent(pThreadParm, FD_OOB, NO_ERROR);
548 }
549 }
550 if((pThreadParm->u.asyncselect.lEventsPending & (FD_ACCEPT|FD_CLOSE|FD_CONNECT)) ==
551 (lEventsPending & (FD_ACCEPT|FD_CLOSE|FD_CONNECT))) {
552 DosSleep(10);
553 }
554 }
555 delete pThreadParm->u.asyncselect.asyncSem;
556}
557//******************************************************************************
558//******************************************************************************
559ODINFUNCTION4(int,WSAAsyncSelect,
560 SOCKET,s,
561 HWND,hWnd,
562 u_int,wMsg,
563 long,lEvent)
564{
565 PASYNCTHREADPARM pThreadParm;
566 int nonblock = 1;
567 int ret;
568
569 if(!fWSAInitialized)
570 {
571 WSASetLastError(WSANOTINITIALISED);
572 return SOCKET_ERROR;
573 }
574 else
575 if(WSAIsBlocking())
576 {
577 WSASetLastError(WSAEINPROGRESS); // blocking call in progress
578 return SOCKET_ERROR;
579 }
580 else
581 if(hWnd && !IsWindow(hWnd))
582 {
583 WSASetLastError(WSAEINVAL); // invalid parameter
584 return SOCKET_ERROR;
585 }
586 //Set socket to non-blocking mode
587 ret = ioctl(s, FIONBIO, (char *) &nonblock, sizeof(nonblock));
588 if(ret == SOCKET_ERROR) {
589 WSASetLastError(wsaErrno());
590 return SOCKET_ERROR;
591 }
592 if(FindAndSetAsyncEvent(s, hWnd, wMsg, lEvent) == TRUE) {
593 //found and changed active async event
594 WSASetLastError(NO_ERROR);
595 return NO_ERROR;
596 }
597 pThreadParm = (PASYNCTHREADPARM)malloc(sizeof(ASYNCTHREADPARM));
598 if(pThreadParm == NULL) {
599 dprintf(("WSAAsyncSelect: malloc failure!"));
600 DebugInt3();
601 WSASetLastError(WSAEFAULT);
602 return SOCKET_ERROR;
603 }
604 memset(pThreadParm, 0, sizeof(*pThreadParm));
605 pThreadParm->request= ASYNC_SELECT;
606 pThreadParm->hwnd = hWnd;
607 pThreadParm->msg = wMsg;
608 pThreadParm->u.asyncselect.lEvents = lEvent;
609 pThreadParm->u.asyncselect.lEventsPending = lEvent;
610 pThreadParm->u.asyncselect.s = s;
611 pThreadParm->u.asyncselect.asyncSem = new VSemaphore;
612 if(pThreadParm->u.asyncselect.asyncSem == NULL) {
613 dprintf(("WSAAsyncSelect: VSemaphore alloc failure!"));
614 DebugInt3();
615 WSASetLastError(WSAEFAULT);
616 return SOCKET_ERROR;
617 }
618 if(QueueAsyncJob(WSAsyncSelectThreadProc, pThreadParm) == 0) {
619 delete pThreadParm->u.asyncselect.asyncSem;
620 free(pThreadParm);
621 dprintf(("WSAAsyncSelect: QueueAsyncJob failure!"));
622 DebugInt3();
623 WSASetLastError(WSAEFAULT);
624 return SOCKET_ERROR;
625 }
626 WSASetLastError(NO_ERROR);
627 return NO_ERROR;
628}
629//******************************************************************************
630//******************************************************************************
Note: See TracBrowser for help on using the repository browser.