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
17 #include <sys/ioctl.h>
18 #include <sys/types.h>
24 # include <sys/so_ioctl.h>
26 #ifdef HAVE_SYS_PARAM_H
27 # include <sys/param.h>
29 #ifdef HAVE_SYS_FILIO_H
30 # include <sys/filio.h>
33 # include <sys/file.h>
43 #include "selectors.h"
45 #include "sig_context.h"
49 #define FASYNC FIOASYNC
52 typedef struct /* async DNS op control struct */
66 extern HANDLE16
__ws_gethandle( void* ptr
);
67 extern void* __ws_memalloc( int size
);
68 extern void __ws_memfree( void* ptr
);
70 /* NOTE: ws_async_op list is traversed inside the SIGIO handler! */
72 static int __async_io_max_fd
= 0;
73 static fd_set __async_io_fdset
;
74 static ws_async_op
* __async_op_list
= NULL
;
76 static void fixup_wshe(struct ws_hostent
* p_wshe
, void* base
);
77 static void fixup_wspe(struct ws_protoent
* p_wspe
, void* base
);
78 static void fixup_wsse(struct ws_servent
* p_wsse
, void* base
);
80 extern void EVENT_AddIO( int fd
, unsigned flag
);
81 extern void EVENT_DeleteIO( int fd
, unsigned flag
);
83 /* ----------------------------------- async/non-blocking I/O */
85 int WINSOCK_async_io(int fd
, int async
)
90 fcntl(fd
, F_SETOWN
, getpid());
93 fd_flags
= fcntl(fd
, F_GETFL
, 0);
94 if (fcntl(fd
, F_SETFL
, (async
)? fd_flags
| FASYNC
95 : fd_flags
& ~FASYNC
) != -1) return 0;
99 int WINSOCK_unblock_io(int fd
, int noblock
)
103 fd_flags
= fcntl(fd
, F_GETFL
, 0);
104 if (fcntl(fd
, F_SETFL
, (noblock
)? fd_flags
| O_NONBLOCK
105 : fd_flags
& ~O_NONBLOCK
) != -1) return 0;
109 int WINSOCK_check_async_op(ws_async_op
* p_aop
)
111 ws_async_op
* p
= __async_op_list
;
112 while( p
) if( p
== p_aop
) return 1;
117 int WINSOCK_cancel_async_op(ws_async_op
* p_aop
)
121 if( WINSOCK_check_async_op(p_aop
) )
123 if( !(p_aop
->flags
& WSMSG_DEAD_AOP
) )
125 kill(p_aop
->pid
, SIGKILL
);
126 waitpid(p_aop
->pid
, NULL
, 0); /* just in case */
129 WINSOCK_unlink_async_op(p_aop
);
130 EVENT_DeleteIO( p_aop
->fd
[0], EVENT_IO_READ
);
132 p_aop
->hWnd
= p_aop
->uMsg
= 0;
138 void WINSOCK_cancel_task_aops(HTASK16 hTask
, void (*__opfree
)(void*))
140 /* SIGIO safe, hTask == 0 cancels all outstanding async ops */
142 int num
= 0, num_dead
= 0;
143 ws_async_op
* p
, *next
;
145 TRACE(winsock
," cancelling async DNS requests... \n");
147 SIGNAL_MaskAsyncEvents( TRUE
);
148 next
= __async_op_list
;
151 HTASK16 hWndTask
= GetWindowTask16(p
->hWnd
);
154 if(!hTask
|| !hWndTask
|| (hTask
== hWndTask
))
157 if( p
->flags
& WSMSG_DEAD_AOP
)
160 WINSOCK_cancel_async_op(p
);
161 if( __opfree
) __opfree(p
);
164 SIGNAL_MaskAsyncEvents( FALSE
);
165 TRACE(winsock
," -> %i total (%i active)\n", num
, num
- num_dead
);
168 void WINSOCK_link_async_op(ws_async_op
* p_aop
)
173 SIGNAL_MaskAsyncEvents( TRUE
);
174 if( __async_op_list
)
176 ws_async_op
* p
= __async_op_list
;
177 __async_op_list
->prev
= p_aop
;
179 /* traverse the list and retire dead ops created
180 * by the signal handler (see below). */
184 if( p
->flags
& WSMSG_DEAD_AOP
)
186 ws_async_op
* dead
= p
;
188 TRACE(winsock
,"\treaping dead aop [%08x]\n", (unsigned)p
);
191 WINSOCK_unlink_async_op( dead
);
192 __ws_memfree( dead
);
198 else FD_ZERO(&__async_io_fdset
);
199 p_aop
->next
= __async_op_list
;
200 __async_op_list
= p_aop
;
201 SIGNAL_MaskAsyncEvents( FALSE
);
203 FD_SET(p_aop
->fd
[0], &__async_io_fdset
);
204 if( p_aop
->fd
[0] > __async_io_max_fd
)
205 __async_io_max_fd
= p_aop
->fd
[0];
208 void WINSOCK_unlink_async_op(ws_async_op
* p_aop
)
212 if( p_aop
== __async_op_list
) __async_op_list
= p_aop
->next
;
214 p_aop
->prev
->next
= p_aop
->next
;
215 if( p_aop
->next
) p_aop
->next
->prev
= p_aop
->prev
;
217 FD_CLR(p_aop
->fd
[0], &__async_io_fdset
);
218 if( p_aop
->fd
[0] == __async_io_max_fd
)
222 /* ----------------------------------- SIGIO handler -
224 * link_async_op/unlink_async_op allow to install generic
225 * async IO handlers (provided that aop_control function is defined).
227 * Note: pipe-based handlers must raise explicit SIGIO with kill(2).
230 HANDLER_DEF(WINSOCK_sigio
)
232 struct timeval timeout
;
238 check_set
= __async_io_fdset
;
239 memset(&timeout
, 0, sizeof(timeout
));
241 while( select(__async_io_max_fd
+ 1,
242 &check_set
, NULL
, NULL
, &timeout
) > 0)
244 for( p_aop
= __async_op_list
;
245 p_aop
; p_aop
= p_aop
->next
)
246 if( FD_ISSET(p_aop
->fd
[0], &check_set
) )
247 if( p_aop
->aop_control(p_aop
, AOP_IO
) == AOP_CONTROL_REMOVE
)
249 /* NOTE: memory management is signal-unsafe, therefore
250 * we can only set a flag to remove this p_aop later on.
253 p_aop
->flags
= WSMSG_DEAD_AOP
;
255 FD_CLR(p_aop
->fd
[0],&__async_io_fdset
);
256 if( p_aop
->fd
[0] == __async_io_max_fd
)
257 __async_io_max_fd
= p_aop
->fd
[0];
260 kill(p_aop
->pid
, SIGKILL
);
261 waitpid(p_aop
->pid
, NULL
, WNOHANG
);
265 check_set
= __async_io_fdset
;
269 /* ----------------------------------- getXbyY requests */
271 static ws_async_ctl async_ctl
; /* child process control struct */
273 static int aop_control(ws_async_op
* p_aop
, int flag
)
277 /* success: LOWORD(lLength) has the length of the struct
279 * failure: LOWORD(lLength) is zero, HIWORD(lLength) contains
283 read(p_aop
->fd
[0], &lLength
, sizeof(unsigned));
284 if( LOWORD(lLength
) )
286 if( (int)LOWORD(lLength
) <= p_aop
->buflen
)
288 char* buffer
= (p_aop
->flags
& WSMSG_WIN32_AOP
)
289 ? p_aop
->b
.lin_base
: (char*)PTR_SEG_TO_LIN(p_aop
->b
.seg_base
);
291 read(p_aop
->fd
[0], buffer
, LOWORD(lLength
));
292 switch( p_aop
->flags
& WSMSG_ASYNC_RQMASK
)
294 case WSMSG_ASYNC_HOSTBYNAME
:
295 case WSMSG_ASYNC_HOSTBYADDR
:
296 fixup_wshe((struct ws_hostent
*)buffer
, p_aop
->b
.ptr_base
); break;
297 case WSMSG_ASYNC_PROTOBYNAME
:
298 case WSMSG_ASYNC_PROTOBYNUM
:
299 fixup_wspe((struct ws_protoent
*)buffer
, p_aop
->b
.ptr_base
); break;
300 case WSMSG_ASYNC_SERVBYNAME
:
301 case WSMSG_ASYNC_SERVBYPORT
:
302 fixup_wsse((struct ws_servent
*)buffer
, p_aop
->b
.ptr_base
); break;
304 if( p_aop
->flags
) WARN(winsock
,"Received unknown async request!\n");
305 return AOP_CONTROL_REMOVE
;
308 else lLength
= ((UINT32
)LOWORD(lLength
)) | ((unsigned)WSAENOBUFS
<< 16);
311 /* was a __WS_ASYNC_DEBUG statement */
312 TRACE(winsock
, "DNS aop completed: hWnd [%04x], uMsg [%04x], "
313 "aop [%04x], event [%08lx]\n",
314 p_aop
->hWnd
, p_aop
->uMsg
, __ws_gethandle(p_aop
), (LPARAM
)lLength
);
316 /* FIXME: update num_async_rq */
317 EVENT_DeleteIO( p_aop
->fd
[0], EVENT_IO_READ
);
318 PostMessage32A( p_aop
->hWnd
, p_aop
->uMsg
, __ws_gethandle(p_aop
), (LPARAM
)lLength
);
320 return AOP_CONTROL_REMOVE
; /* one-shot request */
324 HANDLE16
__WSAsyncDBQuery(LPWSINFO pwsi
, HWND32 hWnd
, UINT32 uMsg
, INT32 type
, LPSTR init
,
325 INT32 len
, LPSTR proto
, void* sbuf
, INT32 buflen
, UINT32 flag
)
327 /* queue 'flag' request and fork off its handler */
329 async_ctl
.ws_aop
= (ws_async_op
*)__ws_memalloc(sizeof(ws_async_op
));
331 if( async_ctl
.ws_aop
)
333 HANDLE16 handle
= __ws_gethandle(async_ctl
.ws_aop
);
335 if( pipe(async_ctl
.ws_aop
->fd
) == 0 )
337 async_ctl
.rq
.init
= (char*)init
;
338 async_ctl
.ilength
= len
;
339 async_ctl
.buffer
= proto
;
340 async_ctl
.type
= type
;
342 async_ctl
.ws_aop
->hWnd
= hWnd
;
343 async_ctl
.ws_aop
->uMsg
= uMsg
;
344 async_ctl
.ws_aop
->b
.ptr_base
= sbuf
;
345 async_ctl
.ws_aop
->buflen
= buflen
;
346 async_ctl
.ws_aop
->flags
= flag
;
347 async_ctl
.ws_aop
->aop_control
= &aop_control
;
349 WINSOCK_link_async_op( async_ctl
.ws_aop
);
351 EVENT_AddIO( async_ctl
.ws_aop
->fd
[0], EVENT_IO_READ
);
352 pwsi
->num_async_rq
++;
354 async_ctl
.ws_aop
->pid
= fork();
355 if( async_ctl
.ws_aop
->pid
)
357 TRACE(winsock
, "\tasync_op = %04x (child %i)\n",
358 handle
, async_ctl
.ws_aop
->pid
);
360 close(async_ctl
.ws_aop
->fd
[1]); /* write endpoint */
361 if( async_ctl
.ws_aop
->pid
> 0 )
362 return __ws_gethandle(async_ctl
.ws_aop
);
366 pwsi
->num_async_rq
--;
367 EVENT_DeleteIO( async_ctl
.ws_aop
->fd
[0], EVENT_IO_READ
);
368 close(async_ctl
.ws_aop
->fd
[0]);
369 pwsi
->err
= WSAEWOULDBLOCK
;
373 extern BOOL32 THREAD_InitDone
;
375 THREAD_InitDone
= FALSE
;
378 close(async_ctl
.ws_aop
->fd
[0]); /* read endpoint */
379 switch( flag
& WSMSG_ASYNC_RQMASK
)
381 case WSMSG_ASYNC_HOSTBYADDR
:
382 case WSMSG_ASYNC_HOSTBYNAME
:
383 WS_do_async_gethost(pwsi
, flag
);
385 case WSMSG_ASYNC_PROTOBYNUM
:
386 case WSMSG_ASYNC_PROTOBYNAME
:
387 WS_do_async_getproto(pwsi
, flag
);
389 case WSMSG_ASYNC_SERVBYPORT
:
390 case WSMSG_ASYNC_SERVBYNAME
:
391 WS_do_async_getserv(pwsi
, flag
);
394 _exit(0); /* skip atexit()'ed cleanup */
397 else pwsi
->err
= wsaErrno(); /* failed to create pipe */
399 __ws_memfree((void*)async_ctl
.ws_aop
);
400 } else pwsi
->err
= WSAEWOULDBLOCK
;
404 static int _async_notify()
406 /* use half-duplex pipe to send variable length packets
407 * to the parent process */
409 write(async_ctl
.ws_aop
->fd
[1], &async_ctl
.ilength
, sizeof(unsigned));
410 write(async_ctl
.ws_aop
->fd
[1], async_ctl
.buffer
, async_ctl
.ilength
);
413 kill(getppid(), SIGIO
); /* simulate async I/O */
416 /* was a __WS_ASYNC_DEBUG statement */
417 TRACE(winsock
, "handler - notify aop [%d, buf %d]\n",
418 async_ctl
.ilength
, async_ctl
.ws_aop
->buflen
);
422 static void _async_fail()
424 /* write a DWORD with error code (low word is zero) */
427 (h_errno
< 0) ? (unsigned)WSAMAKEASYNCREPLY( 0, wsaErrno() )
428 : (unsigned)WSAMAKEASYNCREPLY( 0, wsaHerrno() );
429 write(async_ctl
.ws_aop
->fd
[1], &async_ctl
.ilength
, sizeof(unsigned) );
431 kill(getppid(), SIGIO
); /* simulate async I/O */
434 /* was a __WS_ASYNC_DEBUG statement */
435 TRACE(winsock
, "handler - failed aop [%d, buf %d]\n",
436 async_ctl
.ilength
, async_ctl
.ws_aop
->buflen
);
439 void dump_ws_hostent_offset(struct ws_hostent
* wshe
)
442 char* base
= (char*)wshe
;
445 DUMP("h_name = %08x\t[%s]\n",
446 (unsigned)wshe
->h_name
, base
+ (unsigned)wshe
->h_name
);
447 DUMP("h_aliases = %08x\t[%08x]\n",
448 (unsigned)wshe
->h_aliases
, (unsigned)(base
+(unsigned)wshe
->h_aliases
));
449 ptr
= (unsigned*)(base
+ (unsigned)wshe
->h_aliases
);
450 for(i
= 0; ptr
[i
]; i
++ )
452 DUMP("%i - %08x [%s]\n", i
+ 1, ptr
[i
], ((char*)base
) + ptr
[i
]);
454 DUMP("h_length = %i\n", wshe
->h_length
);
457 void WS_do_async_gethost(LPWSINFO pwsi
, unsigned flag
)
460 struct hostent
* p_he
;
462 close(async_ctl
.ws_aop
->fd
[0]);
464 p_he
= (flag
& WSMSG_ASYNC_HOSTBYNAME
)
465 ? gethostbyname(async_ctl
.rq
.name
)
466 : gethostbyaddr(async_ctl
.rq
.name
,
467 async_ctl
.ilength
, async_ctl
.type
);
469 TRACE(winsock
,"DNS: got hostent for [%s]\n", async_ctl
.rq
.name
);
471 if( p_he
) /* convert to the Winsock format with internal pointers as offsets */
472 size
= WS_dup_he(pwsi
, p_he
, WS_DUP_OFFSET
|
473 ((flag
& WSMSG_WIN32_AOP
) ? WS_DUP_LINEAR
: WS_DUP_SEGPTR
) );
476 async_ctl
.buffer
= pwsi
->buffer
;
477 async_ctl
.ilength
= (unsigned)WSAMAKEASYNCREPLY( (UINT16
)size
, 0 );
478 _async_notify( flag
);
483 void WS_do_async_getproto(LPWSINFO pwsi
, unsigned flag
)
486 struct protoent
* p_pe
;
488 close(async_ctl
.ws_aop
->fd
[0]);
489 p_pe
= (flag
& WSMSG_ASYNC_PROTOBYNAME
)
490 ? getprotobyname(async_ctl
.rq
.name
)
491 : getprotobynumber(async_ctl
.type
);
493 TRACE(winsock
,"DNS: got protoent for [%s]\n", async_ctl
.rq
.name
);
495 if( p_pe
) /* convert to the Winsock format with internal pointers as offsets */
496 size
= WS_dup_pe(pwsi
, p_pe
, WS_DUP_OFFSET
|
497 ((flag
& WSMSG_WIN32_AOP
) ? WS_DUP_LINEAR
: WS_DUP_SEGPTR
) );
500 async_ctl
.buffer
= pwsi
->buffer
;
501 async_ctl
.ilength
= (unsigned)WSAMAKEASYNCREPLY( (UINT16
)size
, 0 );
502 _async_notify( flag
);
507 void WS_do_async_getserv(LPWSINFO pwsi
, unsigned flag
)
510 struct servent
* p_se
;
512 close(async_ctl
.ws_aop
->fd
[0]);
513 p_se
= (flag
& WSMSG_ASYNC_SERVBYNAME
)
514 ? getservbyname(async_ctl
.rq
.name
, async_ctl
.buffer
)
515 : getservbyport(async_ctl
.type
, async_ctl
.buffer
);
517 if( p_se
) /* convert to the Winsock format with internal pointers as offsets */
518 size
= WS_dup_se(pwsi
, p_se
, WS_DUP_OFFSET
|
519 ((flag
& WSMSG_WIN32_AOP
) ? WS_DUP_LINEAR
: WS_DUP_SEGPTR
) );
522 async_ctl
.buffer
= pwsi
->buffer
;
523 async_ctl
.ilength
= (unsigned)WSAMAKEASYNCREPLY( (UINT16
)size
, 0 );
524 _async_notify( flag
);
529 /* ----------------------------------- helper functions -
531 * Raw results from the pipe contain internal pointers stored as
532 * offsets relative to the beginning of the buffer and we need
533 * to apply a fixup before passing them to applications.
535 * NOTE: It is possible to exploit the fact that fork() doesn't
536 * change the buffer address by storing fixed up pointers right
537 * in the handler. However, this will get in the way if we ever
538 * get around to implementing DNS helper daemon a-la Netscape 4.x.
541 void fixup_wshe(struct ws_hostent
* p_wshe
, void* base
)
543 /* add 'base' to ws_hostent pointers to convert them from offsets */
546 unsigned* p_aliases
,*p_addr
;
548 p_aliases
= (unsigned*)((char*)p_wshe
+ (unsigned)p_wshe
->h_aliases
);
549 p_addr
= (unsigned*)((char*)p_wshe
+ (unsigned)p_wshe
->h_addr_list
);
550 ((unsigned)(p_wshe
->h_name
)) += (unsigned)base
;
551 ((unsigned)(p_wshe
->h_aliases
)) += (unsigned)base
;
552 ((unsigned)(p_wshe
->h_addr_list
)) += (unsigned)base
;
553 for(i
=0;p_aliases
[i
];i
++) p_aliases
[i
] += (unsigned)base
;
554 for(i
=0;p_addr
[i
];i
++) p_addr
[i
] += (unsigned)base
;
557 void fixup_wspe(struct ws_protoent
* p_wspe
, void* base
)
560 unsigned* p_aliases
= (unsigned*)((char*)p_wspe
+ (unsigned)p_wspe
->p_aliases
);
561 ((unsigned)(p_wspe
->p_name
)) += (unsigned)base
;
562 ((unsigned)(p_wspe
->p_aliases
)) += (unsigned)base
;
563 for(i
=0;p_aliases
[i
];i
++) p_aliases
[i
] += (unsigned)base
;
566 void fixup_wsse(struct ws_servent
* p_wsse
, void* base
)
569 unsigned* p_aliases
= (unsigned*)((char*)p_wsse
+ (unsigned)p_wsse
->s_aliases
);
570 ((unsigned)(p_wsse
->s_name
)) += (unsigned)base
;
571 ((p_wsse
->s_proto
)) += (unsigned)base
;
572 ((p_wsse
->s_aliases
)) += (unsigned)base
;
573 for(i
=0;p_aliases
[i
];i
++) p_aliases
[i
] += (unsigned)base
;