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