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
18 #include <sys/ioctl.h>
19 #include <sys/types.h>
25 # include <sys/so_ioctl.h>
27 #ifdef HAVE_SYS_PARAM_H
28 # include <sys/param.h>
30 #ifdef HAVE_SYS_FILIO_H
31 # include <sys/filio.h>
33 #ifdef HAVE_SYS_FILE_H
34 # include <sys/file.h>
46 static void WINSOCK_async_handler(int unixfd,void *private);
48 /* async DNS op control struct */
63 extern HANDLE16 __ws_gethandle( void* ptr );
64 extern void* __ws_memalloc( int size );
65 extern void __ws_memfree( void* ptr );
67 /* NOTE: ws_async_op list is traversed inside the SIGIO handler! */
68 static ws_async_op* __async_op_list = NULL;
70 static void fixup_wshe(struct ws_hostent* p_wshe, void* base);
71 static void fixup_wspe(struct ws_protoent* p_wspe, void* base);
72 static void fixup_wsse(struct ws_servent* p_wsse, void* base);
74 /* ----------------------------------- async/non-blocking I/O */
76 int WINSOCK_unblock_io(int fd, int noblock)
80 fd_flags = fcntl(fd, F_GETFL, 0);
81 if (fcntl(fd, F_SETFL, (noblock)? fd_flags | O_NONBLOCK
82 : fd_flags & ~O_NONBLOCK ) != -1) return 0;
86 int WINSOCK_check_async_op(ws_async_op* p_aop)
88 ws_async_op* p = __async_op_list;
89 while( p ) if( p == p_aop ) return 1;
94 int WINSOCK_cancel_async_op(ws_async_op* p_aop)
98 if( WINSOCK_check_async_op(p_aop) )
100 if( !(p_aop->flags & WSMSG_DEAD_AOP) )
102 kill(p_aop->pid, SIGKILL);
103 waitpid(p_aop->pid, NULL, 0); /* just in case */
106 WINSOCK_unlink_async_op(p_aop);
107 EVENT_DeleteIO( p_aop->fd[0], EVENT_IO_READ );
109 p_aop->hWnd = p_aop->uMsg = 0;
115 void WINSOCK_cancel_task_aops(HTASK16 hTask, void (*__opfree)(void*))
117 /* SIGIO safe, hTask == 0 cancels all outstanding async ops */
119 int num = 0, num_dead = 0;
120 ws_async_op* p, *next;
122 TRACE(winsock," cancelling async DNS requests... \n");
124 SIGNAL_MaskAsyncEvents( TRUE );
125 next = __async_op_list;
128 HTASK16 hWndTask = GetWindowTask16(p->hWnd);
131 if(!hTask || !hWndTask || (hTask == hWndTask))
134 if( p->flags & WSMSG_DEAD_AOP )
137 WINSOCK_cancel_async_op(p);
138 if( __opfree ) __opfree(p);
141 SIGNAL_MaskAsyncEvents( FALSE );
142 TRACE(winsock," -> %i total (%i active)\n", num, num - num_dead );
145 void WINSOCK_link_async_op(ws_async_op* p_aop)
150 SIGNAL_MaskAsyncEvents( TRUE );
151 if( __async_op_list )
153 ws_async_op* p = __async_op_list;
154 __async_op_list->prev = p_aop;
156 /* traverse the list and retire dead ops created
157 * by the signal handler (see below). */
161 if( p->flags & WSMSG_DEAD_AOP )
163 ws_async_op* dead = p;
165 TRACE(winsock,"\treaping dead aop [%08x]\n", (unsigned)p );
168 WINSOCK_unlink_async_op( dead );
169 __ws_memfree( dead );
175 p_aop->next = __async_op_list;
176 __async_op_list = p_aop;
178 SIGNAL_MaskAsyncEvents( FALSE );
180 ASYNC_RegisterFD(p_aop->fd[0],WINSOCK_async_handler,p_aop);
183 void WINSOCK_unlink_async_op(ws_async_op* p_aop)
187 if( p_aop == __async_op_list ) __async_op_list = p_aop->next;
189 p_aop->prev->next = p_aop->next;
190 if( p_aop->next ) p_aop->next->prev = p_aop->prev;
192 ASYNC_UnregisterFD(p_aop->fd[0],WINSOCK_async_handler);
195 /* ----------------------------------- SIGIO handler -
197 * link_async_op/unlink_async_op allow to install generic
198 * async IO handlers (provided that aop_control function is defined).
200 * Note: pipe-based handlers must raise explicit SIGIO with kill(2).
203 static void WINSOCK_async_handler(int unixfd,void *private)
205 ws_async_op* p_aop = (ws_async_op*)private;
207 if( p_aop->aop_control(p_aop, AOP_IO) == AOP_CONTROL_REMOVE )
209 /* NOTE: memory management is signal-unsafe, therefore
210 * we can only set a flag to remove this p_aop later on.
212 p_aop->flags = WSMSG_DEAD_AOP;
216 kill(p_aop->pid, SIGKILL);
217 waitpid(p_aop->pid, NULL, WNOHANG);
223 /* ----------------------------------- getXbyY requests */
225 /* child process control struct */
226 static ws_async_ctl async_ctl;
228 static int aop_control(ws_async_op* p_aop, int flag )
232 /* success: LOWORD(lLength) has the length of the struct
234 * failure: LOWORD(lLength) is zero, HIWORD(lLength) contains
238 read(p_aop->fd[0], &lLength, sizeof(unsigned));
239 if( LOWORD(lLength) )
241 if( (int)LOWORD(lLength) <= p_aop->buflen )
243 char* buffer = (p_aop->flags & WSMSG_WIN32_AOP)
244 ? p_aop->b.lin_base : (char*)PTR_SEG_TO_LIN(p_aop->b.seg_base);
246 read(p_aop->fd[0], buffer, LOWORD(lLength));
247 switch( p_aop->flags & WSMSG_ASYNC_RQMASK )
249 case WSMSG_ASYNC_HOSTBYNAME:
250 case WSMSG_ASYNC_HOSTBYADDR:
251 fixup_wshe((struct ws_hostent*)buffer, p_aop->b.ptr_base); break;
252 case WSMSG_ASYNC_PROTOBYNAME:
253 case WSMSG_ASYNC_PROTOBYNUM:
254 fixup_wspe((struct ws_protoent*)buffer, p_aop->b.ptr_base); break;
255 case WSMSG_ASYNC_SERVBYNAME:
256 case WSMSG_ASYNC_SERVBYPORT:
257 fixup_wsse((struct ws_servent*)buffer, p_aop->b.ptr_base); break;
259 if( p_aop->flags ) WARN(winsock,"Received unknown async request!\n");
260 return AOP_CONTROL_REMOVE;
263 else lLength = ((UINT32)LOWORD(lLength)) | ((unsigned)WSAENOBUFS << 16);
266 /* was a __WS_ASYNC_DEBUG statement */
267 TRACE(winsock, "DNS aop completed: hWnd [%04x], uMsg [%04x], "
268 "aop [%04x], event [%08lx]\n",
269 p_aop->hWnd, p_aop->uMsg, __ws_gethandle(p_aop), (LPARAM)lLength);
271 /* FIXME: update num_async_rq */
272 EVENT_DeleteIO( p_aop->fd[0], EVENT_IO_READ );
273 PostMessage32A( p_aop->hWnd, p_aop->uMsg, __ws_gethandle(p_aop), (LPARAM)lLength );
275 return AOP_CONTROL_REMOVE; /* one-shot request */
279 HANDLE16 __WSAsyncDBQuery(LPWSINFO pwsi, HWND32 hWnd, UINT32 uMsg, INT32 type,
280 LPCSTR init, INT32 len, LPCSTR proto, void* sbuf, INT32 buflen, UINT32 flag)
282 /* queue 'flag' request and fork off its handler */
284 async_ctl.ws_aop = (ws_async_op*)__ws_memalloc(sizeof(ws_async_op));
286 if( async_ctl.ws_aop )
288 HANDLE16 handle = __ws_gethandle(async_ctl.ws_aop);
290 if( pipe(async_ctl.ws_aop->fd) == 0 )
292 async_ctl.rq.init = (char*)init;
293 async_ctl.ilength = len;
294 async_ctl.buffer = (char*)proto;
295 async_ctl.type = type;
297 async_ctl.ws_aop->hWnd = hWnd;
298 async_ctl.ws_aop->uMsg = uMsg;
299 async_ctl.ws_aop->b.ptr_base = sbuf;
300 async_ctl.ws_aop->buflen = buflen;
301 async_ctl.ws_aop->flags = flag;
302 async_ctl.ws_aop->aop_control = &aop_control;
304 WINSOCK_link_async_op( async_ctl.ws_aop );
306 EVENT_AddIO( async_ctl.ws_aop->fd[0], EVENT_IO_READ );
307 pwsi->num_async_rq++;
309 async_ctl.ws_aop->pid = fork();
310 if( async_ctl.ws_aop->pid )
312 TRACE(winsock, "\tasync_op = %04x (child %i)\n",
313 handle, async_ctl.ws_aop->pid);
315 close(async_ctl.ws_aop->fd[1]); /* write endpoint */
316 if( async_ctl.ws_aop->pid > 0 )
317 return __ws_gethandle(async_ctl.ws_aop);
321 pwsi->num_async_rq--;
322 EVENT_DeleteIO( async_ctl.ws_aop->fd[0], EVENT_IO_READ );
323 close(async_ctl.ws_aop->fd[0]);
324 pwsi->err = WSAEWOULDBLOCK;
328 extern BOOL32 THREAD_InitDone;
330 THREAD_InitDone = FALSE;
333 close(async_ctl.ws_aop->fd[0]); /* read endpoint */
334 switch( flag & WSMSG_ASYNC_RQMASK )
336 case WSMSG_ASYNC_HOSTBYADDR:
337 case WSMSG_ASYNC_HOSTBYNAME:
338 WS_do_async_gethost(pwsi, flag);
340 case WSMSG_ASYNC_PROTOBYNUM:
341 case WSMSG_ASYNC_PROTOBYNAME:
342 WS_do_async_getproto(pwsi, flag);
344 case WSMSG_ASYNC_SERVBYPORT:
345 case WSMSG_ASYNC_SERVBYNAME:
346 WS_do_async_getserv(pwsi, flag);
349 _exit(0); /* skip atexit()'ed cleanup */
352 else pwsi->err = wsaErrno(); /* failed to create pipe */
354 __ws_memfree((void*)async_ctl.ws_aop);
355 } else pwsi->err = WSAEWOULDBLOCK;
359 static int _async_notify()
361 /* use half-duplex pipe to send variable length packets
362 * to the parent process */
364 write(async_ctl.ws_aop->fd[1], &async_ctl.ilength, sizeof(unsigned));
365 write(async_ctl.ws_aop->fd[1], async_ctl.buffer, async_ctl.ilength );
368 kill(getppid(), SIGIO); /* simulate async I/O */
371 /* was a __WS_ASYNC_DEBUG statement */
372 TRACE(winsock, "handler - notify aop [%d, buf %d]\n",
373 async_ctl.ilength, async_ctl.ws_aop->buflen);
377 static void _async_fail()
379 /* write a DWORD with error code (low word is zero) */
382 (h_errno < 0) ? (unsigned)WSAMAKEASYNCREPLY( 0, wsaErrno() )
383 : (unsigned)WSAMAKEASYNCREPLY( 0, wsaHerrno() );
384 write(async_ctl.ws_aop->fd[1], &async_ctl.ilength, sizeof(unsigned) );
386 kill(getppid(), SIGIO); /* simulate async I/O */
389 /* was a __WS_ASYNC_DEBUG statement */
390 TRACE(winsock, "handler - failed aop [%d, buf %d]\n",
391 async_ctl.ilength, async_ctl.ws_aop->buflen);
394 void dump_ws_hostent_offset(struct ws_hostent* wshe)
397 char* base = (char*)wshe;
400 DUMP("h_name = %08x\t[%s]\n",
401 (unsigned)wshe->h_name, base + (unsigned)wshe->h_name);
402 DUMP("h_aliases = %08x\t[%08x]\n",
403 (unsigned)wshe->h_aliases, (unsigned)(base+(unsigned)wshe->h_aliases));
404 ptr = (unsigned*)(base + (unsigned)wshe->h_aliases);
405 for(i = 0; ptr[i]; i++ )
407 DUMP("%i - %08x [%s]\n", i + 1, ptr[i], ((char*)base) + ptr[i]);
409 DUMP("h_length = %i\n", wshe->h_length);
412 void WS_do_async_gethost(LPWSINFO pwsi, unsigned flag )
415 struct hostent* p_he;
417 close(async_ctl.ws_aop->fd[0]);
419 p_he = (flag & WSMSG_ASYNC_HOSTBYNAME)
420 ? gethostbyname(async_ctl.rq.name)
421 : gethostbyaddr(async_ctl.rq.name,
422 async_ctl.ilength, async_ctl.type);
424 TRACE(winsock,"DNS: got hostent for [%s]\n", async_ctl.rq.name );
426 if( p_he ) /* convert to the Winsock format with internal pointers as offsets */
427 size = WS_dup_he(pwsi, p_he, WS_DUP_OFFSET |
428 ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
431 async_ctl.buffer = (char*)pwsi->he;
432 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
433 _async_notify( flag );
438 void WS_do_async_getproto(LPWSINFO pwsi, unsigned flag )
441 struct protoent* p_pe;
443 close(async_ctl.ws_aop->fd[0]);
444 p_pe = (flag & WSMSG_ASYNC_PROTOBYNAME)
445 ? getprotobyname(async_ctl.rq.name)
446 : getprotobynumber(async_ctl.type);
448 TRACE(winsock,"DNS: got protoent for [%s]\n", async_ctl.rq.name );
450 if( p_pe ) /* convert to the Winsock format with internal pointers as offsets */
451 size = WS_dup_pe(pwsi, p_pe, WS_DUP_OFFSET |
452 ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
455 async_ctl.buffer = (char*)pwsi->pe;
456 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
457 _async_notify( flag );
462 void WS_do_async_getserv(LPWSINFO pwsi, unsigned flag )
465 struct servent* p_se;
467 close(async_ctl.ws_aop->fd[0]);
468 p_se = (flag & WSMSG_ASYNC_SERVBYNAME)
469 ? getservbyname(async_ctl.rq.name, async_ctl.buffer)
470 : getservbyport(async_ctl.type, async_ctl.buffer);
472 if( p_se ) /* convert to the Winsock format with internal pointers as offsets */
473 size = WS_dup_se(pwsi, p_se, WS_DUP_OFFSET |
474 ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
477 async_ctl.buffer = (char*)pwsi->se;
478 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
479 _async_notify( flag );
484 /* ----------------------------------- helper functions -
486 * Raw results from the pipe contain internal pointers stored as
487 * offsets relative to the beginning of the buffer and we need
488 * to apply a fixup before passing them to applications.
490 * NOTE: It is possible to exploit the fact that fork() doesn't
491 * change the buffer address by storing fixed up pointers right
492 * in the handler. However, this will get in the way if we ever
493 * get around to implementing DNS helper daemon a-la Netscape 4.x.
496 void fixup_wshe(struct ws_hostent* p_wshe, void* 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, void* 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, void* 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;