Release 980927
[wine] / misc / winsock_dns.c
1 /*
2  * asynchronous DNS services
3  * 
4  * (C) 1996,1997 Alex Korobka.
5  *
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
9  *       Netscape 4.0).
10  */
11
12 #include "config.h"
13
14 #include <unistd.h>
15 #include <string.h>
16 #include <signal.h>
17 #include <sys/ioctl.h>
18 #include <sys/types.h>
19 #include <sys/ipc.h>
20 #include <sys/msg.h>
21 #include <sys/wait.h>
22 #include <errno.h>
23 #ifdef __EMX__
24 # include <sys/so_ioctl.h>
25 #endif
26 #ifdef HAVE_SYS_PARAM_H
27 # include <sys/param.h>
28 #endif
29 #ifdef HAVE_SYS_FILIO_H
30 # include <sys/filio.h>
31 #endif
32 #ifdef __svr4__
33 # include <sys/file.h>
34 #endif
35
36 #include "winsock.h"
37 #include "windows.h"
38 #include "heap.h"
39 #include "ldt.h"
40 #include "message.h"
41 #include "selectors.h"
42 #include "miscemu.h"
43 #include "sig_context.h"
44 #include "debug.h"
45
46 #ifndef FASYNC
47 #define FASYNC FIOASYNC
48 #endif
49
50 /* async DNS op control struct */
51 typedef struct          
52 {
53   ws_async_op*  ws_aop;
54   char*         buffer;
55   int           type;
56   union
57   {
58     char*       init;
59     char*       name;
60     char*       addr;
61   } rq;
62   unsigned      ilength;
63 } ws_async_ctl;
64
65 extern HANDLE16 __ws_gethandle( void* ptr );
66 extern void*    __ws_memalloc( int size );
67 extern void     __ws_memfree( void* ptr );
68
69 /* NOTE: ws_async_op list is traversed inside the SIGIO handler! */
70
71 static int              __async_io_max_fd = 0;
72 static fd_set           __async_io_fdset;
73 static ws_async_op*     __async_op_list = NULL;
74
75 static void fixup_wshe(struct ws_hostent* p_wshe, void* base);
76 static void fixup_wspe(struct ws_protoent* p_wspe, void* base);
77 static void fixup_wsse(struct ws_servent* p_wsse, void* base);
78
79 /* ----------------------------------- async/non-blocking I/O */
80
81 int WINSOCK_async_io(int fd, int async)
82 {
83     int fd_flags;
84
85 #ifndef __EMX__
86     fcntl(fd, F_SETOWN, getpid());
87 #endif
88
89     fd_flags = fcntl(fd, F_GETFL, 0);
90     if (fcntl(fd, F_SETFL, (async)? fd_flags | FASYNC
91                                   : fd_flags & ~FASYNC ) != -1) return 0;
92     return -1;
93 }
94
95 int WINSOCK_unblock_io(int fd, int noblock)
96 {
97     int fd_flags;
98
99     fd_flags = fcntl(fd, F_GETFL, 0);
100     if (fcntl(fd, F_SETFL, (noblock)? fd_flags |  O_NONBLOCK
101                                     : fd_flags & ~O_NONBLOCK ) != -1) return 0;
102     return -1;
103 }
104
105 int WINSOCK_check_async_op(ws_async_op* p_aop)
106 {
107   ws_async_op*   p = __async_op_list;
108   while( p ) if( p == p_aop ) return 1;
109              else p = p->next;
110   return 0;
111 }
112
113 int WINSOCK_cancel_async_op(ws_async_op* p_aop)
114 {
115     /* SIGIO unsafe! */
116
117     if( WINSOCK_check_async_op(p_aop) )
118     {
119         if( !(p_aop->flags & WSMSG_DEAD_AOP) )
120         {
121             kill(p_aop->pid, SIGKILL);
122             waitpid(p_aop->pid, NULL, 0); /* just in case */
123             close(p_aop->fd[0]);
124         }
125         WINSOCK_unlink_async_op(p_aop);
126         EVENT_DeleteIO( p_aop->fd[0], EVENT_IO_READ );
127         p_aop->flags = 0;
128         p_aop->hWnd = p_aop->uMsg = 0;
129         return 1;
130     }
131     return 0;
132 }
133
134 void WINSOCK_cancel_task_aops(HTASK16 hTask, void (*__opfree)(void*))
135 {
136     /* SIGIO safe, hTask == 0 cancels all outstanding async ops */
137
138     int num = 0, num_dead = 0;
139     ws_async_op*   p, *next;
140
141     TRACE(winsock," cancelling async DNS requests... \n");
142
143     SIGNAL_MaskAsyncEvents( TRUE );
144     next = __async_op_list;
145     while( (p = next) ) 
146     {
147         HTASK16 hWndTask = GetWindowTask16(p->hWnd);
148
149         next = p->next;
150         if(!hTask || !hWndTask || (hTask == hWndTask))
151         {
152             num++;
153             if( p->flags & WSMSG_DEAD_AOP )
154                 num_dead++;
155
156             WINSOCK_cancel_async_op(p);
157             if( __opfree ) __opfree(p);
158         }
159     }
160     SIGNAL_MaskAsyncEvents( FALSE );
161     TRACE(winsock," -> %i total (%i active)\n", num, num - num_dead );
162 }
163
164 void WINSOCK_link_async_op(ws_async_op* p_aop)
165 {
166   /* SIGIO safe */
167
168   p_aop->prev = NULL;
169   SIGNAL_MaskAsyncEvents( TRUE );
170   if( __async_op_list )
171   {
172       ws_async_op*      p = __async_op_list;
173       __async_op_list->prev = p_aop;
174
175       /* traverse the list and retire dead ops created
176        * by the signal handler (see below). */
177
178       while( p )
179       {
180           if( p->flags & WSMSG_DEAD_AOP )
181           {
182               ws_async_op* dead = p;
183
184               TRACE(winsock,"\treaping dead aop [%08x]\n", (unsigned)p );
185
186               p = p->next;
187               WINSOCK_unlink_async_op( dead );
188               __ws_memfree( dead );
189               continue;
190           }
191           p = p->next;
192       }
193   }
194   else FD_ZERO(&__async_io_fdset);
195   p_aop->next = __async_op_list;
196   __async_op_list = p_aop;
197   SIGNAL_MaskAsyncEvents( FALSE );
198
199   FD_SET(p_aop->fd[0], &__async_io_fdset);
200   if( p_aop->fd[0] > __async_io_max_fd ) 
201                      __async_io_max_fd = p_aop->fd[0];
202 }
203
204 void WINSOCK_unlink_async_op(ws_async_op* p_aop)
205 {
206   /* SIGIO unsafe! */
207
208   if( p_aop == __async_op_list ) __async_op_list = p_aop->next;
209   else
210       p_aop->prev->next = p_aop->next;
211   if( p_aop->next ) p_aop->next->prev = p_aop->prev;
212
213   FD_CLR(p_aop->fd[0], &__async_io_fdset); 
214   if( p_aop->fd[0] == __async_io_max_fd )
215                       __async_io_max_fd--;
216 }
217
218 /* ----------------------------------- SIGIO handler -
219  *
220  * link_async_op/unlink_async_op allow to install generic
221  * async IO handlers (provided that aop_control function is defined).
222  *
223  * Note: pipe-based handlers must raise explicit SIGIO with kill(2).
224  */
225
226 HANDLER_DEF(WINSOCK_sigio)
227 {
228  struct timeval         timeout;
229  fd_set                 check_set;
230  ws_async_op*           p_aop;
231
232  HANDLER_INIT();
233
234  check_set = __async_io_fdset;
235  memset(&timeout, 0, sizeof(timeout));
236
237  while( select(__async_io_max_fd + 1,
238               &check_set, NULL, NULL, &timeout) > 0)
239  {
240    for( p_aop = __async_op_list;
241         p_aop ; p_aop = p_aop->next )
242       if( FD_ISSET(p_aop->fd[0], &check_set) )
243           if( p_aop->aop_control(p_aop, AOP_IO) == AOP_CONTROL_REMOVE )
244           {
245              /* NOTE: memory management is signal-unsafe, therefore
246               * we can only set a flag to remove this p_aop later on.
247               */
248
249               p_aop->flags = WSMSG_DEAD_AOP;
250               close(p_aop->fd[0]);
251               FD_CLR(p_aop->fd[0],&__async_io_fdset);
252               if( p_aop->fd[0] == __async_io_max_fd )
253                                  __async_io_max_fd = p_aop->fd[0];
254               if( p_aop->pid ) 
255               { 
256                   kill(p_aop->pid, SIGKILL); 
257                   waitpid(p_aop->pid, NULL, WNOHANG);
258                   p_aop->pid = 0;
259               }
260           }
261    check_set = __async_io_fdset;
262   }
263 }
264
265 /* ----------------------------------- getXbyY requests */
266
267 /* child process control struct */
268 static   ws_async_ctl   async_ctl; 
269
270 static int aop_control(ws_async_op* p_aop, int flag )
271 {
272     unsigned    lLength;
273
274   /* success:   LOWORD(lLength) has the length of the struct
275    *            to read.
276    * failure:   LOWORD(lLength) is zero, HIWORD(lLength) contains
277    *            the error code.
278    */
279
280     read(p_aop->fd[0], &lLength, sizeof(unsigned));
281     if( LOWORD(lLength) )
282     {
283         if( (int)LOWORD(lLength) <= p_aop->buflen )
284         {
285             char* buffer = (p_aop->flags & WSMSG_WIN32_AOP)
286                   ? p_aop->b.lin_base : (char*)PTR_SEG_TO_LIN(p_aop->b.seg_base);
287
288             read(p_aop->fd[0], buffer, LOWORD(lLength));
289             switch( p_aop->flags & WSMSG_ASYNC_RQMASK )
290             {
291                 case WSMSG_ASYNC_HOSTBYNAME:
292                 case WSMSG_ASYNC_HOSTBYADDR:
293                      fixup_wshe((struct ws_hostent*)buffer, p_aop->b.ptr_base); break;
294                 case WSMSG_ASYNC_PROTOBYNAME:
295                 case WSMSG_ASYNC_PROTOBYNUM:
296                      fixup_wspe((struct ws_protoent*)buffer, p_aop->b.ptr_base); break;
297                 case WSMSG_ASYNC_SERVBYNAME:
298                 case WSMSG_ASYNC_SERVBYPORT:
299                      fixup_wsse((struct ws_servent*)buffer, p_aop->b.ptr_base); break;
300                 default:
301                      if( p_aop->flags ) WARN(winsock,"Received unknown async request!\n");
302                      return AOP_CONTROL_REMOVE;
303             }
304         }
305         else lLength =  ((UINT32)LOWORD(lLength)) | ((unsigned)WSAENOBUFS << 16);
306     } /* failure */
307
308      /* was a __WS_ASYNC_DEBUG statement */
309      TRACE(winsock, "DNS aop completed: hWnd [%04x], uMsg [%04x], "
310           "aop [%04x], event [%08lx]\n",
311           p_aop->hWnd, p_aop->uMsg, __ws_gethandle(p_aop), (LPARAM)lLength);
312
313     /* FIXME: update num_async_rq */
314     EVENT_DeleteIO( p_aop->fd[0], EVENT_IO_READ );
315     PostMessage32A( p_aop->hWnd, p_aop->uMsg, __ws_gethandle(p_aop), (LPARAM)lLength );
316     
317     return AOP_CONTROL_REMOVE;  /* one-shot request */
318 }
319
320
321 HANDLE16 __WSAsyncDBQuery(LPWSINFO pwsi, HWND32 hWnd, UINT32 uMsg, INT32 type, 
322     LPCSTR init, INT32 len, LPCSTR proto, void* sbuf, INT32 buflen, UINT32 flag)
323 {
324     /* queue 'flag' request and fork off its handler */
325
326     async_ctl.ws_aop = (ws_async_op*)__ws_memalloc(sizeof(ws_async_op));
327
328     if( async_ctl.ws_aop )
329     {
330         HANDLE16        handle = __ws_gethandle(async_ctl.ws_aop);
331
332         if( pipe(async_ctl.ws_aop->fd) == 0 )
333         {
334             async_ctl.rq.init = (char*)init;
335             async_ctl.ilength = len;
336             async_ctl.buffer = (char*)proto;
337             async_ctl.type = type;
338
339             async_ctl.ws_aop->hWnd = hWnd;
340             async_ctl.ws_aop->uMsg = uMsg;
341             async_ctl.ws_aop->b.ptr_base = sbuf; 
342             async_ctl.ws_aop->buflen = buflen;
343             async_ctl.ws_aop->flags = flag;
344             async_ctl.ws_aop->aop_control = &aop_control;
345
346             WINSOCK_link_async_op( async_ctl.ws_aop );
347
348             EVENT_AddIO( async_ctl.ws_aop->fd[0], EVENT_IO_READ );
349             pwsi->num_async_rq++;
350
351             async_ctl.ws_aop->pid = fork();
352             if( async_ctl.ws_aop->pid )
353             {
354                 TRACE(winsock, "\tasync_op = %04x (child %i)\n", 
355                                 handle, async_ctl.ws_aop->pid);
356
357                 close(async_ctl.ws_aop->fd[1]);  /* write endpoint */
358                 if( async_ctl.ws_aop->pid > 0 )
359                     return __ws_gethandle(async_ctl.ws_aop);
360
361                 /* fork() failed */
362
363                 pwsi->num_async_rq--;
364                 EVENT_DeleteIO( async_ctl.ws_aop->fd[0], EVENT_IO_READ );
365                 close(async_ctl.ws_aop->fd[0]);
366                 pwsi->err = WSAEWOULDBLOCK;
367             }
368             else
369             {
370                 extern BOOL32 THREAD_InitDone;
371
372                 THREAD_InitDone = FALSE;
373                 /* child process */
374
375                 close(async_ctl.ws_aop->fd[0]);  /* read endpoint */
376                 switch( flag & WSMSG_ASYNC_RQMASK )
377                 {
378                     case WSMSG_ASYNC_HOSTBYADDR:
379                     case WSMSG_ASYNC_HOSTBYNAME:
380                         WS_do_async_gethost(pwsi, flag);
381                         break;
382                     case WSMSG_ASYNC_PROTOBYNUM:
383                     case WSMSG_ASYNC_PROTOBYNAME:
384                         WS_do_async_getproto(pwsi, flag);
385                         break;
386                     case WSMSG_ASYNC_SERVBYPORT:
387                     case WSMSG_ASYNC_SERVBYNAME:
388                         WS_do_async_getserv(pwsi, flag);
389                         break;
390                 }
391                 _exit(0);       /* skip  atexit()'ed cleanup */
392             }
393         }
394         else pwsi->err = wsaErrno(); /* failed to create pipe */
395
396         __ws_memfree((void*)async_ctl.ws_aop);
397     } else pwsi->err = WSAEWOULDBLOCK;
398     return 0;
399 }
400
401 static int _async_notify()
402 {
403     /* use half-duplex pipe to send variable length packets 
404      * to the parent process */
405      
406     write(async_ctl.ws_aop->fd[1], &async_ctl.ilength, sizeof(unsigned));
407     write(async_ctl.ws_aop->fd[1], async_ctl.buffer, async_ctl.ilength );
408
409 #ifndef __EMX__
410     kill(getppid(), SIGIO);    /* simulate async I/O */
411 #endif
412
413     /* was a __WS_ASYNC_DEBUG statement */
414     TRACE(winsock, "handler - notify aop [%d, buf %d]\n", 
415           async_ctl.ilength, async_ctl.ws_aop->buflen);
416     return 1;
417 }
418
419 static void _async_fail()
420 {
421      /* write a DWORD with error code (low word is zero) */
422
423      async_ctl.ilength =
424         (h_errno < 0) ? (unsigned)WSAMAKEASYNCREPLY( 0, wsaErrno() )
425                       : (unsigned)WSAMAKEASYNCREPLY( 0, wsaHerrno() );
426      write(async_ctl.ws_aop->fd[1], &async_ctl.ilength, sizeof(unsigned) );
427 #ifndef __EMX__
428      kill(getppid(), SIGIO);    /* simulate async I/O */
429 #endif
430
431     /* was a __WS_ASYNC_DEBUG statement */
432     TRACE(winsock, "handler - failed aop [%d, buf %d]\n", 
433           async_ctl.ilength, async_ctl.ws_aop->buflen);
434 }
435
436 void dump_ws_hostent_offset(struct ws_hostent* wshe)
437 {
438   int           i;
439   char*         base = (char*)wshe;
440   unsigned*     ptr;
441
442   DUMP("h_name = %08x\t[%s]\n", 
443        (unsigned)wshe->h_name, base + (unsigned)wshe->h_name);
444   DUMP("h_aliases = %08x\t[%08x]\n", 
445        (unsigned)wshe->h_aliases, (unsigned)(base+(unsigned)wshe->h_aliases));
446   ptr = (unsigned*)(base + (unsigned)wshe->h_aliases);
447   for(i = 0; ptr[i]; i++ )
448   {
449         DUMP("%i - %08x [%s]\n", i + 1, ptr[i], ((char*)base) + ptr[i]);
450   }
451   DUMP("h_length = %i\n", wshe->h_length);
452 }
453
454 void WS_do_async_gethost(LPWSINFO pwsi, unsigned flag )
455 {  
456   int                   size = 0;
457   struct hostent*       p_he;
458
459   close(async_ctl.ws_aop->fd[0]);
460
461   p_he = (flag & WSMSG_ASYNC_HOSTBYNAME)
462          ? gethostbyname(async_ctl.rq.name)
463          : gethostbyaddr(async_ctl.rq.name,
464                          async_ctl.ilength, async_ctl.type);
465
466   TRACE(winsock,"DNS: got hostent for [%s]\n", async_ctl.rq.name );
467
468   if( p_he ) /* convert to the Winsock format with internal pointers as offsets */
469       size = WS_dup_he(pwsi, p_he, WS_DUP_OFFSET | 
470                      ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
471   if( size )
472   {
473       async_ctl.buffer = (char*)pwsi->he;
474       async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
475      _async_notify( flag );
476   }
477   else _async_fail();
478 }
479
480 void WS_do_async_getproto(LPWSINFO pwsi, unsigned flag )
481 {
482   int                   size = 0;
483   struct protoent*      p_pe;
484
485   close(async_ctl.ws_aop->fd[0]);
486   p_pe = (flag & WSMSG_ASYNC_PROTOBYNAME)
487          ? getprotobyname(async_ctl.rq.name)
488          : getprotobynumber(async_ctl.type);
489
490   TRACE(winsock,"DNS: got protoent for [%s]\n", async_ctl.rq.name );
491
492   if( p_pe ) /* convert to the Winsock format with internal pointers as offsets */
493       size = WS_dup_pe(pwsi, p_pe, WS_DUP_OFFSET |
494                      ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
495   if( size )
496   {
497       async_ctl.buffer = (char*)pwsi->pe;
498       async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
499      _async_notify( flag );
500   } 
501   else _async_fail();
502 }
503
504 void WS_do_async_getserv(LPWSINFO pwsi, unsigned flag )
505 {
506   int                   size = 0;
507   struct servent*       p_se;
508
509   close(async_ctl.ws_aop->fd[0]);
510   p_se = (flag & WSMSG_ASYNC_SERVBYNAME)
511          ? getservbyname(async_ctl.rq.name, async_ctl.buffer)
512          : getservbyport(async_ctl.type, async_ctl.buffer);
513
514   if( p_se ) /* convert to the Winsock format with internal pointers as offsets */
515       size = WS_dup_se(pwsi, p_se, WS_DUP_OFFSET |
516                       ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
517   if( size )
518   {
519       async_ctl.buffer = (char*)pwsi->se;
520       async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
521      _async_notify( flag );
522   }
523   else _async_fail();
524 }
525
526 /* ----------------------------------- helper functions -
527  *
528  * Raw results from the pipe contain internal pointers stored as
529  * offsets relative to the beginning of the buffer and we need
530  * to apply a fixup before passing them to applications.
531  *
532  * NOTE: It is possible to exploit the fact that fork() doesn't 
533  * change the buffer address by storing fixed up pointers right 
534  * in the handler. However, this will get in the way if we ever 
535  * get around to implementing DNS helper daemon a-la Netscape 4.x.
536  */
537
538 void fixup_wshe(struct ws_hostent* p_wshe, void* base)
539 {
540    /* add 'base' to ws_hostent pointers to convert them from offsets */
541
542    int i;
543    unsigned*    p_aliases,*p_addr;
544
545    p_aliases = (unsigned*)((char*)p_wshe + (unsigned)p_wshe->h_aliases);
546    p_addr = (unsigned*)((char*)p_wshe + (unsigned)p_wshe->h_addr_list);
547    ((unsigned)(p_wshe->h_name)) += (unsigned)base;
548    ((unsigned)(p_wshe->h_aliases)) += (unsigned)base;
549    ((unsigned)(p_wshe->h_addr_list)) += (unsigned)base;
550    for(i=0;p_aliases[i];i++) p_aliases[i] += (unsigned)base;
551    for(i=0;p_addr[i];i++) p_addr[i] += (unsigned)base;
552 }
553
554 void fixup_wspe(struct ws_protoent* p_wspe, void* base)
555 {
556    int i;
557    unsigned*       p_aliases = (unsigned*)((char*)p_wspe + (unsigned)p_wspe->p_aliases);
558    ((unsigned)(p_wspe->p_name)) += (unsigned)base;
559    ((unsigned)(p_wspe->p_aliases)) += (unsigned)base;
560    for(i=0;p_aliases[i];i++) p_aliases[i] += (unsigned)base;
561 }
562
563 void fixup_wsse(struct ws_servent* p_wsse, void* base)
564 {
565    int i;
566    unsigned*       p_aliases = (unsigned*)((char*)p_wsse + (unsigned)p_wsse->s_aliases);
567    ((unsigned)(p_wsse->s_name)) += (unsigned)base;
568    ((p_wsse->s_proto)) += (unsigned)base;
569    ((p_wsse->s_aliases)) += (unsigned)base;
570    for(i=0;p_aliases[i];i++) p_aliases[i] += (unsigned)base;
571 }