2 * asynchronous DNS services
4 * (C) 1996,1997 Alex Korobka.
6 * TODO: Fork dns lookup helper during the startup (with a pipe
7 * for communication) and make it fork for a database request
8 * instead of forking the main process (i.e. something like
15 #include <sys/ioctl.h>
16 #include <sys/types.h>
22 #include <sys/so_ioctl.h>
23 #include <sys/param.h>
27 #include <sys/filio.h>
41 #define FASYNC FIOASYNC
44 #define __WS_ASYNC_DEBUG 0
46 typedef struct /* async DNS op control struct */
60 extern HANDLE16
__ws_gethandle( void* ptr
);
61 extern void* __ws_memalloc( int size
);
62 extern void __ws_memfree( void* ptr
);
64 /* NOTE: ws_async_op list is traversed inside the SIGIO handler! */
66 static int __async_io_max_fd
= 0;
67 static fd_set __async_io_fdset
;
68 static ws_async_op
* __async_op_list
= NULL
;
70 static void fixup_wshe(struct ws_hostent
* p_wshe
, SEGPTR base
);
71 static void fixup_wspe(struct ws_protoent
* p_wspe
, SEGPTR base
);
72 static void fixup_wsse(struct ws_servent
* p_wsse
, SEGPTR base
);
74 extern void EVENT_AddIO( int fd
, unsigned flag
);
75 extern void EVENT_DeleteIO( int fd
, unsigned flag
);
77 /* ----------------------------------- async/non-blocking I/O */
79 int WINSOCK_async_io(int fd
, int async
)
84 fcntl(fd
, F_SETOWN
, getpid());
87 fd_flags
= fcntl(fd
, F_GETFL
, 0);
88 if (fcntl(fd
, F_SETFL
, (async
)? fd_flags
| FASYNC
89 : fd_flags
& ~FASYNC
) != -1) return 0;
93 int WINSOCK_unblock_io(int fd
, int noblock
)
97 fd_flags
= fcntl(fd
, F_GETFL
, 0);
98 if (fcntl(fd
, F_SETFL
, (noblock
)? fd_flags
| O_NONBLOCK
99 : fd_flags
& ~O_NONBLOCK
) != -1) return 0;
103 int WINSOCK_check_async_op(ws_async_op
* p_aop
)
105 ws_async_op
* p
= __async_op_list
;
106 while( p
) if( p
== p_aop
) return 1;
111 int WINSOCK_cancel_async_op(ws_async_op
* p_aop
)
115 if( WINSOCK_check_async_op(p_aop
) )
117 if( !(p_aop
->flags
& WSMSG_DEAD_AOP
) )
119 kill(p_aop
->pid
, SIGKILL
);
120 waitpid(p_aop
->pid
, NULL
, 0); /* just in case */
123 WINSOCK_unlink_async_op(p_aop
);
124 EVENT_DeleteIO( p_aop
->fd
[0], EVENT_IO_READ
);
126 p_aop
->hWnd
= p_aop
->uMsg
= 0;
132 void WINSOCK_cancel_task_aops(HTASK16 hTask
, void (*__opfree
)(void*))
134 /* SIGIO safe, hTask == 0 cancels all outstanding async ops */
137 ws_async_op
* p
, *next
;
139 dprintf_winsock(stddeb
,"\tcancelling async DNS requests... ");
141 SIGNAL_MaskAsyncEvents( TRUE
);
142 next
= __async_op_list
;
145 HTASK16 hWndTask
= GetWindowTask16(p
->hWnd
);
148 if(!hTask
|| !hWndTask
|| (hTask
== hWndTask
))
150 WINSOCK_cancel_async_op(p
);
151 if( __opfree
) __opfree(p
);
155 SIGNAL_MaskAsyncEvents( FALSE
);
156 dprintf_winsock(stddeb
,"%i total\n", num
);
159 void WINSOCK_link_async_op(ws_async_op
* p_aop
)
164 SIGNAL_MaskAsyncEvents( TRUE
);
165 if( __async_op_list
)
167 ws_async_op
* p
= __async_op_list
;
168 __async_op_list
->prev
= p_aop
;
170 /* traverse the list and reap dead ops */
173 if( p
->flags
& WSMSG_DEAD_AOP
)
175 ws_async_op
* dead
= p
;
177 dprintf_winsock(stddeb
,"\treaping dead aop [%08x]\n", (unsigned)p
);
180 WINSOCK_unlink_async_op( dead
);
181 __ws_memfree( dead
);
187 else FD_ZERO(&__async_io_fdset
);
188 p_aop
->next
= __async_op_list
;
189 __async_op_list
= p_aop
;
190 SIGNAL_MaskAsyncEvents( FALSE
);
192 FD_SET(p_aop
->fd
[0], &__async_io_fdset
);
193 if( p_aop
->fd
[0] > __async_io_max_fd
)
194 __async_io_max_fd
= p_aop
->fd
[0];
197 void WINSOCK_unlink_async_op(ws_async_op
* p_aop
)
201 if( p_aop
== __async_op_list
) __async_op_list
= p_aop
->next
;
203 p_aop
->prev
->next
= p_aop
->next
;
204 if( p_aop
->next
) p_aop
->next
->prev
= p_aop
->prev
;
206 FD_CLR(p_aop
->fd
[0], &__async_io_fdset
);
207 if( p_aop
->fd
[0] == __async_io_max_fd
)
211 /* ----------------------------------- SIGIO handler -
213 * link_async_op/unlink_async_op allow to install generic
214 * async IO handlers (provided that aop_control function is defined).
216 * Note: AsyncGetXbyY expilicitly raise it.
219 void WINSOCK_sigio(int signal
)
221 struct timeval timeout
;
225 check_set
= __async_io_fdset
;
226 memset(&timeout
, 0, sizeof(timeout
));
228 while( select(__async_io_max_fd
+ 1,
229 &check_set
, NULL
, NULL
, &timeout
) > 0)
231 for( p_aop
= __async_op_list
;
232 p_aop
; p_aop
= p_aop
->next
)
233 if( FD_ISSET(p_aop
->fd
[0], &check_set
) )
234 if( p_aop
->aop_control(p_aop
, AOP_IO
) == AOP_CONTROL_REMOVE
)
236 p_aop
->flags
= WSMSG_DEAD_AOP
; /* can't free inside the signal */
238 FD_CLR(p_aop
->fd
[0],&__async_io_fdset
);
239 if( p_aop
->fd
[0] == __async_io_max_fd
)
240 __async_io_max_fd
= p_aop
->fd
[0];
243 kill(p_aop
->pid
, SIGKILL
);
244 waitpid(p_aop
->pid
, NULL
, WNOHANG
);
248 check_set
= __async_io_fdset
;
252 /* ----------------------------------- getXbyY requests */
254 static ws_async_ctl async_ctl
; /* child process control struct */
256 static int aop_control(ws_async_op
* p_aop
, int flag
)
260 /* success: LOWORD(lLength) has the length of the struct
262 * failure: LOWORD(lLength) is zero, HIWORD(lLength) contains
266 read(p_aop
->fd
[0], &lLength
, sizeof(unsigned));
267 if( LOWORD(lLength
) )
269 if( (int)LOWORD(lLength
) <= p_aop
->buflen
)
271 char* buffer
= (char*)PTR_SEG_TO_LIN(p_aop
->buffer_base
);
272 read(p_aop
->fd
[0], buffer
, LOWORD(lLength
));
273 switch( p_aop
->flags
)
275 case WSMSG_ASYNC_HOSTBYNAME
:
276 case WSMSG_ASYNC_HOSTBYADDR
:
277 fixup_wshe((struct ws_hostent
*)buffer
, p_aop
->buffer_base
); break;
278 case WSMSG_ASYNC_PROTOBYNAME
:
279 case WSMSG_ASYNC_PROTOBYNUM
:
280 fixup_wspe((struct ws_protoent
*)buffer
, p_aop
->buffer_base
); break;
281 case WSMSG_ASYNC_SERVBYNAME
:
282 case WSMSG_ASYNC_SERVBYPORT
:
283 fixup_wsse((struct ws_servent
*)buffer
, p_aop
->buffer_base
); break;
285 if( p_aop
->flags
) fprintf(stderr
,"Received unknown async request!\n");
286 return AOP_CONTROL_REMOVE
;
289 else lLength
= ((UINT32
)LOWORD(lLength
)) | ((unsigned)WSAENOBUFS
<< 16);
293 printf("DNS aop completed: hWnd [%04x], uMsg [%04x], aop [%04x], event [%08x]\n",
294 p_aop
->hWnd
, p_aop
->uMsg
, __ws_gethandle(p_aop
), (LPARAM
)lLength
);
297 /* FIXME: update num_async_rq */
298 EVENT_DeleteIO( p_aop
->fd
[0], EVENT_IO_READ
);
299 PostMessage16( p_aop
->hWnd
, p_aop
->uMsg
, __ws_gethandle(p_aop
), (LPARAM
)lLength
);
301 return AOP_CONTROL_REMOVE
; /* one-shot request */
305 HANDLE16
__WSAsyncDBQuery(LPWSINFO pwsi
, HWND16 hWnd
, UINT16 uMsg
, INT16 type
, LPSTR init
,
306 INT16 len
, LPSTR proto
, SEGPTR sbuf
, INT16 buflen
, UINT32 flag
)
308 /* queue 'flag' request and fork off its handler */
310 async_ctl
.ws_aop
= (ws_async_op
*)__ws_memalloc(sizeof(ws_async_op
));
312 if( async_ctl
.ws_aop
)
314 HANDLE16 handle
= __ws_gethandle(async_ctl
.ws_aop
);
316 if( pipe(async_ctl
.ws_aop
->fd
) == 0 )
318 async_ctl
.rq
.init
= (char*)init
;
319 async_ctl
.ilength
= len
;
320 async_ctl
.buffer
= proto
;
321 async_ctl
.type
= type
;
323 async_ctl
.ws_aop
->hWnd
= hWnd
;
324 async_ctl
.ws_aop
->uMsg
= uMsg
;
325 async_ctl
.ws_aop
->buffer_base
= sbuf
; async_ctl
.ws_aop
->buflen
= buflen
;
326 async_ctl
.ws_aop
->flags
= flag
;
327 async_ctl
.ws_aop
->aop_control
= &aop_control
;
329 WINSOCK_link_async_op( async_ctl
.ws_aop
);
331 async_ctl
.ws_aop
->pid
= fork();
332 if( async_ctl
.ws_aop
->pid
)
334 close(async_ctl
.ws_aop
->fd
[1]); /* write endpoint */
335 dprintf_winsock(stddeb
, "\tasync_op = %04x (child %i)\n",
336 handle
, async_ctl
.ws_aop
->pid
);
337 if( async_ctl
.ws_aop
->pid
> 0 )
339 EVENT_AddIO( async_ctl
.ws_aop
->fd
[0], EVENT_IO_READ
);
340 pwsi
->num_async_rq
++;
341 return __ws_gethandle(async_ctl
.ws_aop
);
345 close(async_ctl
.ws_aop
->fd
[0]);
346 pwsi
->err
= WSAEWOULDBLOCK
;
352 close(async_ctl
.ws_aop
->fd
[0]); /* read endpoint */
355 case WSMSG_ASYNC_HOSTBYADDR
:
356 case WSMSG_ASYNC_HOSTBYNAME
:
357 WS_do_async_gethost(pwsi
, flag
);
359 case WSMSG_ASYNC_PROTOBYNUM
:
360 case WSMSG_ASYNC_PROTOBYNAME
:
361 WS_do_async_getproto(pwsi
, flag
);
363 case WSMSG_ASYNC_SERVBYPORT
:
364 case WSMSG_ASYNC_SERVBYNAME
:
365 WS_do_async_getserv(pwsi
, flag
);
368 _exit(0); /* skip atexit()'ed cleanup */
371 else pwsi
->err
= wsaErrno(); /* failed to create pipe */
373 __ws_memfree((void*)async_ctl
.ws_aop
);
374 } else pwsi
->err
= WSAEWOULDBLOCK
;
378 static int _async_notify()
380 /* use half-duplex pipe to send variable length packets
381 * to the parent process */
383 write(async_ctl
.ws_aop
->fd
[1], &async_ctl
.ilength
, sizeof(unsigned));
384 write(async_ctl
.ws_aop
->fd
[1], async_ctl
.buffer
, async_ctl
.ilength
);
387 kill(getppid(), SIGIO
); /* simulate async I/O */
391 printf("handler - notify aop [%d, buf %d]\n", async_ctl
.ilength
, async_ctl
.ws_aop
->buflen
);
396 static void _async_fail()
398 /* write a DWORD with error code (low word is zero) */
401 (h_errno
< 0) ? (unsigned)WSAMAKEASYNCREPLY( 0, wsaErrno() )
402 : (unsigned)WSAMAKEASYNCREPLY( 0, wsaHerrno() );
403 write(async_ctl
.ws_aop
->fd
[1], &async_ctl
.ilength
, sizeof(unsigned) );
405 kill(getppid(), SIGIO
); /* simulate async I/O */
409 printf("handler - failed aop [%d, buf %d]\n", async_ctl
.ilength
, async_ctl
.ws_aop
->buflen
);
413 void dump_ws_hostent_offset(struct ws_hostent
* wshe
)
416 char* base
= (char*)wshe
;
419 printf("h_name = %08x\t[%s]\n", (unsigned)wshe
->h_name
, base
+ (unsigned)wshe
->h_name
);
420 printf("h_aliases = %08x\t[%08x]\n", (unsigned)wshe
->h_aliases
,
421 (unsigned)(base
+ (unsigned)wshe
->h_aliases
));
422 ptr
= (unsigned*)(base
+ (unsigned)wshe
->h_aliases
);
423 for(i
= 0; ptr
[i
]; i
++ )
425 printf("%i - %08x ", i
+ 1, ptr
[i
]);
426 printf(" [%s]\n", ((char*)base
) + ptr
[i
]);
428 printf("h_length = %i\n", wshe
->h_length
);
431 void WS_do_async_gethost(LPWSINFO pwsi
, unsigned flag
)
434 struct hostent
* p_he
;
436 close(async_ctl
.ws_aop
->fd
[0]);
438 dprintf_winsock(stddeb
,"DNS: getting hostent for [%s]\n", async_ctl
.rq
.name
);
440 p_he
= (flag
& WSMSG_ASYNC_HOSTBYNAME
)
441 ? gethostbyname(async_ctl
.rq
.name
)
442 : gethostbyaddr(async_ctl
.rq
.name
,
443 async_ctl
.ilength
, async_ctl
.type
);
444 dprintf_winsock(stddeb
,"DNS: done!\n");
446 if( p_he
) size
= WS_dup_he(pwsi
, p_he
, WS_DUP_SEGPTR
| WS_DUP_OFFSET
);
449 async_ctl
.buffer
= pwsi
->buffer
;
450 async_ctl
.ilength
= (unsigned)WSAMAKEASYNCREPLY( (UINT16
)size
, 0 );
451 _async_notify( flag
);
456 void WS_do_async_getproto(LPWSINFO pwsi
, unsigned flag
)
459 struct protoent
* p_pe
;
461 close(async_ctl
.ws_aop
->fd
[0]);
462 p_pe
= (flag
& WSMSG_ASYNC_PROTOBYNAME
)
463 ? getprotobyname(async_ctl
.rq
.name
)
464 : getprotobynumber(async_ctl
.type
);
465 if( p_pe
) size
= WS_dup_pe(pwsi
, p_pe
, WS_DUP_SEGPTR
| WS_DUP_OFFSET
);
468 async_ctl
.buffer
= pwsi
->buffer
;
469 async_ctl
.ilength
= (unsigned)WSAMAKEASYNCREPLY( (UINT16
)size
, 0 );
470 _async_notify( flag
);
475 void WS_do_async_getserv(LPWSINFO pwsi
, unsigned flag
)
478 struct servent
* p_se
;
480 close(async_ctl
.ws_aop
->fd
[0]);
481 p_se
= (flag
& WSMSG_ASYNC_SERVBYNAME
)
482 ? getservbyname(async_ctl
.rq
.name
, async_ctl
.buffer
)
483 : getservbyport(async_ctl
.type
, async_ctl
.buffer
);
484 if( p_se
) size
= WS_dup_se(pwsi
, p_se
, WS_DUP_SEGPTR
| WS_DUP_OFFSET
);
487 async_ctl
.buffer
= pwsi
->buffer
;
488 async_ctl
.ilength
= (unsigned)WSAMAKEASYNCREPLY( (UINT16
)size
, 0 );
489 _async_notify( flag
);
494 /* ----------------------------------- helper functions */
496 void fixup_wshe(struct ws_hostent
* p_wshe
, SEGPTR base
)
498 /* add 'base' to ws_hostent pointers to convert them from offsets */
501 unsigned* p_aliases
,*p_addr
;
503 p_aliases
= (unsigned*)((char*)p_wshe
+ (unsigned)p_wshe
->h_aliases
);
504 p_addr
= (unsigned*)((char*)p_wshe
+ (unsigned)p_wshe
->h_addr_list
);
505 ((unsigned)(p_wshe
->h_name
)) += (unsigned)base
;
506 ((unsigned)(p_wshe
->h_aliases
)) += (unsigned)base
;
507 ((unsigned)(p_wshe
->h_addr_list
)) += (unsigned)base
;
508 for(i
=0;p_aliases
[i
];i
++) p_aliases
[i
] += (unsigned)base
;
509 for(i
=0;p_addr
[i
];i
++) p_addr
[i
] += (unsigned)base
;
512 void fixup_wspe(struct ws_protoent
* p_wspe
, SEGPTR base
)
515 unsigned* p_aliases
= (unsigned*)((char*)p_wspe
+ (unsigned)p_wspe
->p_aliases
);
516 ((unsigned)(p_wspe
->p_name
)) += (unsigned)base
;
517 ((unsigned)(p_wspe
->p_aliases
)) += (unsigned)base
;
518 for(i
=0;p_aliases
[i
];i
++) p_aliases
[i
] += (unsigned)base
;
521 void fixup_wsse(struct ws_servent
* p_wsse
, SEGPTR base
)
524 unsigned* p_aliases
= (unsigned*)((char*)p_wsse
+ (unsigned)p_wsse
->s_aliases
);
525 ((unsigned)(p_wsse
->s_name
)) += (unsigned)base
;
526 ((p_wsse
->s_proto
)) += (unsigned)base
;
527 ((p_wsse
->s_aliases
)) += (unsigned)base
;
528 for(i
=0;p_aliases
[i
];i
++) p_aliases
[i
] += (unsigned)base
;