Release 970824
[wine/multimedia.git] / misc / winsock_dns.c
blob8042489d6fc340a338d1b2ae9049fc2c0e570bfd
1 /*
2 * asynchronous DNS services
3 *
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
9 * Netscape 4.0).
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
30 extern int h_errno;
32 #include "windows.h"
33 #include "heap.h"
34 #include "ldt.h"
35 #include "message.h"
36 #include "miscemu.h"
37 #include "winsock.h"
38 #include "debug.h"
40 #ifndef FASYNC
41 #define FASYNC FIOASYNC
42 #endif
44 #define __WS_ASYNC_DEBUG 0
46 typedef struct /* async DNS op control struct */
48 ws_async_op* ws_aop;
49 char* buffer;
50 int type;
51 union
53 char* init;
54 char* name;
55 char* addr;
56 } rq;
57 unsigned ilength;
58 } ws_async_ctl;
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)
81 int fd_flags;
83 #ifndef __EMX__
84 fcntl(fd, F_SETOWN, getpid());
85 #endif
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;
93 int WINSOCK_unblock_io(int fd, int noblock)
95 int fd_flags;
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;
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;
107 else p = p->next;
108 return 0;
111 int WINSOCK_cancel_async_op(ws_async_op* p_aop)
113 /* SIGIO unsafe! */
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 */
121 close(p_aop->fd[0]);
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;
129 return 0;
132 void WINSOCK_cancel_task_aops(HTASK16 hTask, void (*__opfree)(void*))
134 /* SIGIO safe, hTask == 0 cancels all outstanding async ops */
136 int num = 0;
137 ws_async_op* p, *next;
139 dprintf_winsock(stddeb,"\tcancelling async DNS requests... ");
141 SIGNAL_MaskAsyncEvents( TRUE );
142 next = __async_op_list;
143 while( (p = next) )
145 HTASK16 hWndTask = GetWindowTask16(p->hWnd);
147 next = p->next;
148 if(!hTask || !hWndTask || (hTask == hWndTask))
150 WINSOCK_cancel_async_op(p);
151 if( __opfree ) __opfree(p);
152 num++;
155 SIGNAL_MaskAsyncEvents( FALSE );
156 dprintf_winsock(stddeb,"%i total\n", num );
159 void WINSOCK_link_async_op(ws_async_op* p_aop)
161 /* SIGIO safe */
163 p_aop->prev = NULL;
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 */
171 while( p )
173 if( p->flags & WSMSG_DEAD_AOP )
175 ws_async_op* dead = p;
177 dprintf_winsock(stddeb,"\treaping dead aop [%08x]\n", (unsigned)p );
179 p = p->next;
180 WINSOCK_unlink_async_op( dead );
181 __ws_memfree( dead );
182 continue;
184 p = p->next;
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)
199 /* SIGIO unsafe! */
201 if( p_aop == __async_op_list ) __async_op_list = p_aop->next;
202 else
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 )
208 __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;
222 fd_set check_set;
223 ws_async_op* p_aop;
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 */
237 close(p_aop->fd[0]);
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];
241 if( p_aop->pid )
243 kill(p_aop->pid, SIGKILL);
244 waitpid(p_aop->pid, NULL, WNOHANG);
245 p_aop->pid = 0;
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 )
258 unsigned lLength;
260 /* success: LOWORD(lLength) has the length of the struct
261 * to read.
262 * failure: LOWORD(lLength) is zero, HIWORD(lLength) contains
263 * the error code.
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;
284 default:
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);
290 } /* failure */
292 #if __WS_ASYNC_DEBUG
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);
295 #endif
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);
344 /* fork() failed */
345 close(async_ctl.ws_aop->fd[0]);
346 pwsi->err = WSAEWOULDBLOCK;
348 else
350 /* child process */
352 close(async_ctl.ws_aop->fd[0]); /* read endpoint */
353 switch( flag )
355 case WSMSG_ASYNC_HOSTBYADDR:
356 case WSMSG_ASYNC_HOSTBYNAME:
357 WS_do_async_gethost(pwsi, flag);
358 break;
359 case WSMSG_ASYNC_PROTOBYNUM:
360 case WSMSG_ASYNC_PROTOBYNAME:
361 WS_do_async_getproto(pwsi, flag);
362 break;
363 case WSMSG_ASYNC_SERVBYPORT:
364 case WSMSG_ASYNC_SERVBYNAME:
365 WS_do_async_getserv(pwsi, flag);
366 break;
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;
375 return 0;
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 );
386 #ifndef __EMX__
387 kill(getppid(), SIGIO); /* simulate async I/O */
388 #endif
390 #if __WS_ASYNC_DEBUG
391 printf("handler - notify aop [%d, buf %d]\n", async_ctl.ilength, async_ctl.ws_aop->buflen);
392 #endif
393 return 1;
396 static void _async_fail()
398 /* write a DWORD with error code (low word is zero) */
400 async_ctl.ilength =
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) );
404 #ifndef __EMX__
405 kill(getppid(), SIGIO); /* simulate async I/O */
406 #endif
408 #if __WS_ASYNC_DEBUG
409 printf("handler - failed aop [%d, buf %d]\n", async_ctl.ilength, async_ctl.ws_aop->buflen);
410 #endif
413 void dump_ws_hostent_offset(struct ws_hostent* wshe)
415 int i;
416 char* base = (char*)wshe;
417 unsigned* ptr;
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 )
433 int size = 0;
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 );
447 if( size )
449 async_ctl.buffer = pwsi->buffer;
450 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
451 _async_notify( flag );
453 else _async_fail();
456 void WS_do_async_getproto(LPWSINFO pwsi, unsigned flag )
458 int size = 0;
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 );
466 if( size )
468 async_ctl.buffer = pwsi->buffer;
469 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
470 _async_notify( flag );
472 else _async_fail();
475 void WS_do_async_getserv(LPWSINFO pwsi, unsigned flag )
477 int size = 0;
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 );
485 if( size )
487 async_ctl.buffer = pwsi->buffer;
488 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
489 _async_notify( flag );
491 else _async_fail();
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 */
500 int i;
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)
514 int i;
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)
523 int i;
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;