Removed deferred Expose events handling.
[wine/multimedia.git] / misc / winsock_dns.c
blob113c50e0d041c0e3f618a790241d358978bc5a54
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 "config.h"
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
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"
46 #ifndef FASYNC
47 #define FASYNC FIOASYNC
48 #endif
50 /* async DNS op control struct */
51 typedef struct
53 ws_async_op* ws_aop;
54 char* buffer;
55 int type;
56 union
58 char* init;
59 char* name;
60 char* addr;
61 } rq;
62 unsigned ilength;
63 } ws_async_ctl;
65 extern HANDLE16 __ws_gethandle( void* ptr );
66 extern void* __ws_memalloc( int size );
67 extern void __ws_memfree( void* ptr );
69 /* NOTE: ws_async_op list is traversed inside the SIGIO handler! */
71 static int __async_io_max_fd = 0;
72 static fd_set __async_io_fdset;
73 static ws_async_op* __async_op_list = NULL;
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);
79 /* ----------------------------------- async/non-blocking I/O */
81 int WINSOCK_async_io(int fd, int async)
83 int fd_flags;
85 #ifndef __EMX__
86 fcntl(fd, F_SETOWN, getpid());
87 #endif
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;
95 int WINSOCK_unblock_io(int fd, int noblock)
97 int fd_flags;
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;
105 int WINSOCK_check_async_op(ws_async_op* p_aop)
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;
113 int WINSOCK_cancel_async_op(ws_async_op* p_aop)
115 /* SIGIO unsafe! */
117 if( WINSOCK_check_async_op(p_aop) )
119 if( !(p_aop->flags & WSMSG_DEAD_AOP) )
121 kill(p_aop->pid, SIGKILL);
122 waitpid(p_aop->pid, NULL, 0); /* just in case */
123 close(p_aop->fd[0]);
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;
131 return 0;
134 void WINSOCK_cancel_task_aops(HTASK16 hTask, void (*__opfree)(void*))
136 /* SIGIO safe, hTask == 0 cancels all outstanding async ops */
138 int num = 0, num_dead = 0;
139 ws_async_op* p, *next;
141 TRACE(winsock," cancelling async DNS requests... \n");
143 SIGNAL_MaskAsyncEvents( TRUE );
144 next = __async_op_list;
145 while( (p = next) )
147 HTASK16 hWndTask = GetWindowTask16(p->hWnd);
149 next = p->next;
150 if(!hTask || !hWndTask || (hTask == hWndTask))
152 num++;
153 if( p->flags & WSMSG_DEAD_AOP )
154 num_dead++;
156 WINSOCK_cancel_async_op(p);
157 if( __opfree ) __opfree(p);
160 SIGNAL_MaskAsyncEvents( FALSE );
161 TRACE(winsock," -> %i total (%i active)\n", num, num - num_dead );
164 void WINSOCK_link_async_op(ws_async_op* p_aop)
166 /* SIGIO safe */
168 p_aop->prev = NULL;
169 SIGNAL_MaskAsyncEvents( TRUE );
170 if( __async_op_list )
172 ws_async_op* p = __async_op_list;
173 __async_op_list->prev = p_aop;
175 /* traverse the list and retire dead ops created
176 * by the signal handler (see below). */
178 while( p )
180 if( p->flags & WSMSG_DEAD_AOP )
182 ws_async_op* dead = p;
184 TRACE(winsock,"\treaping dead aop [%08x]\n", (unsigned)p );
186 p = p->next;
187 WINSOCK_unlink_async_op( dead );
188 __ws_memfree( dead );
189 continue;
191 p = p->next;
194 else FD_ZERO(&__async_io_fdset);
195 p_aop->next = __async_op_list;
196 __async_op_list = p_aop;
197 SIGNAL_MaskAsyncEvents( FALSE );
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];
204 void WINSOCK_unlink_async_op(ws_async_op* p_aop)
206 /* SIGIO unsafe! */
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;
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--;
218 /* ----------------------------------- SIGIO handler -
220 * link_async_op/unlink_async_op allow to install generic
221 * async IO handlers (provided that aop_control function is defined).
223 * Note: pipe-based handlers must raise explicit SIGIO with kill(2).
226 HANDLER_DEF(WINSOCK_sigio)
228 struct timeval timeout;
229 fd_set check_set;
230 ws_async_op* p_aop;
232 HANDLER_INIT();
234 check_set = __async_io_fdset;
235 memset(&timeout, 0, sizeof(timeout));
237 while( select(__async_io_max_fd + 1,
238 &check_set, NULL, NULL, &timeout) > 0)
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 )
245 /* NOTE: memory management is signal-unsafe, therefore
246 * we can only set a flag to remove this p_aop later on.
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 )
256 kill(p_aop->pid, SIGKILL);
257 waitpid(p_aop->pid, NULL, WNOHANG);
258 p_aop->pid = 0;
261 check_set = __async_io_fdset;
265 /* ----------------------------------- getXbyY requests */
267 /* child process control struct */
268 static ws_async_ctl async_ctl;
270 static int aop_control(ws_async_op* p_aop, int flag )
272 unsigned lLength;
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.
280 read(p_aop->fd[0], &lLength, sizeof(unsigned));
281 if( LOWORD(lLength) )
283 if( (int)LOWORD(lLength) <= p_aop->buflen )
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);
288 read(p_aop->fd[0], buffer, LOWORD(lLength));
289 switch( p_aop->flags & WSMSG_ASYNC_RQMASK )
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;
305 else lLength = ((UINT32)LOWORD(lLength)) | ((unsigned)WSAENOBUFS << 16);
306 } /* failure */
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);
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 );
317 return AOP_CONTROL_REMOVE; /* one-shot request */
321 HANDLE16 __WSAsyncDBQuery(LPWSINFO pwsi, HWND32 hWnd, UINT32 uMsg, INT32 type,
322 LPCSTR init, INT32 len, LPCSTR proto, void* sbuf, INT32 buflen, UINT32 flag)
324 /* queue 'flag' request and fork off its handler */
326 async_ctl.ws_aop = (ws_async_op*)__ws_memalloc(sizeof(ws_async_op));
328 if( async_ctl.ws_aop )
330 HANDLE16 handle = __ws_gethandle(async_ctl.ws_aop);
332 if( pipe(async_ctl.ws_aop->fd) == 0 )
334 async_ctl.rq.init = (char*)init;
335 async_ctl.ilength = len;
336 async_ctl.buffer = (char*)proto;
337 async_ctl.type = type;
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;
346 WINSOCK_link_async_op( async_ctl.ws_aop );
348 EVENT_AddIO( async_ctl.ws_aop->fd[0], EVENT_IO_READ );
349 pwsi->num_async_rq++;
351 async_ctl.ws_aop->pid = fork();
352 if( async_ctl.ws_aop->pid )
354 TRACE(winsock, "\tasync_op = %04x (child %i)\n",
355 handle, async_ctl.ws_aop->pid);
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);
361 /* fork() failed */
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;
368 else
370 extern BOOL32 THREAD_InitDone;
372 THREAD_InitDone = FALSE;
373 /* child process */
375 close(async_ctl.ws_aop->fd[0]); /* read endpoint */
376 switch( flag & WSMSG_ASYNC_RQMASK )
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;
391 _exit(0); /* skip atexit()'ed cleanup */
394 else pwsi->err = wsaErrno(); /* failed to create pipe */
396 __ws_memfree((void*)async_ctl.ws_aop);
397 } else pwsi->err = WSAEWOULDBLOCK;
398 return 0;
401 static int _async_notify()
403 /* use half-duplex pipe to send variable length packets
404 * to the parent process */
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 );
409 #ifndef __EMX__
410 kill(getppid(), SIGIO); /* simulate async I/O */
411 #endif
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;
419 static void _async_fail()
421 /* write a DWORD with error code (low word is zero) */
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
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);
436 void dump_ws_hostent_offset(struct ws_hostent* wshe)
438 int i;
439 char* base = (char*)wshe;
440 unsigned* ptr;
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++ )
449 DUMP("%i - %08x [%s]\n", i + 1, ptr[i], ((char*)base) + ptr[i]);
451 DUMP("h_length = %i\n", wshe->h_length);
454 void WS_do_async_gethost(LPWSINFO pwsi, unsigned flag )
456 int size = 0;
457 struct hostent* p_he;
459 close(async_ctl.ws_aop->fd[0]);
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);
466 TRACE(winsock,"DNS: got hostent for [%s]\n", async_ctl.rq.name );
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 )
473 async_ctl.buffer = (char*)pwsi->he;
474 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
475 _async_notify( flag );
477 else _async_fail();
480 void WS_do_async_getproto(LPWSINFO pwsi, unsigned flag )
482 int size = 0;
483 struct protoent* p_pe;
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);
490 TRACE(winsock,"DNS: got protoent for [%s]\n", async_ctl.rq.name );
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 )
497 async_ctl.buffer = (char*)pwsi->pe;
498 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
499 _async_notify( flag );
501 else _async_fail();
504 void WS_do_async_getserv(LPWSINFO pwsi, unsigned flag )
506 int size = 0;
507 struct servent* p_se;
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);
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 )
519 async_ctl.buffer = (char*)pwsi->se;
520 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
521 _async_notify( flag );
523 else _async_fail();
526 /* ----------------------------------- helper functions -
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.
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.
538 void fixup_wshe(struct ws_hostent* p_wshe, void* base)
540 /* add 'base' to ws_hostent pointers to convert them from offsets */
542 int i;
543 unsigned* p_aliases,*p_addr;
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;
554 void fixup_wspe(struct ws_protoent* p_wspe, void* base)
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;
563 void fixup_wsse(struct ws_servent* p_wsse, void* base)
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;