CLIENT_WaitReply: don't clear last error on success; fixed callers
[wine.git] / misc / winsock_dns.c
blobb3f1ecbbf1cd07609bade1bd355376e733cc220f
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 <assert.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <signal.h>
18 #include <sys/ioctl.h>
19 #include <sys/types.h>
20 #include <sys/ipc.h>
21 #include <sys/msg.h>
22 #include <sys/wait.h>
23 #include <errno.h>
24 #ifdef __EMX__
25 # include <sys/so_ioctl.h>
26 #endif
27 #ifdef HAVE_SYS_PARAM_H
28 # include <sys/param.h>
29 #endif
30 #ifdef HAVE_SYS_FILIO_H
31 # include <sys/filio.h>
32 #endif
33 #ifdef HAVE_SYS_FILE_H
34 # include <sys/file.h>
35 #endif
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <netdb.h>
40 #ifdef HAVE_ARPA_NAMESER_H
41 # include <arpa/nameser.h>
42 #endif
43 #ifdef HAVE_RESOLV_H
44 # include <resolv.h>
45 #endif
47 #include "wine/winuser16.h"
48 #include "winsock.h"
49 #include "heap.h"
50 #include "ldt.h"
51 #include "message.h"
52 #include "miscemu.h"
53 #include "async.h"
54 #include "debug.h"
56 static void WINSOCK_async_handler(int unixfd,void *private);
58 /* async DNS op control struct */
59 typedef struct
61 ws_async_op* ws_aop;
62 char* buffer;
63 int type;
64 union
66 char* init;
67 char* name;
68 char* addr;
69 } rq;
70 unsigned ilength;
71 } ws_async_ctl;
73 extern HANDLE16 __ws_gethandle( void* ptr );
74 extern void* __ws_memalloc( int size );
75 extern void __ws_memfree( void* ptr );
77 /* NOTE: ws_async_op list is traversed inside the SIGIO handler! */
78 static ws_async_op* __async_op_list = NULL;
80 static void fixup_wshe(struct ws_hostent* p_wshe, void* base);
81 static void fixup_wspe(struct ws_protoent* p_wspe, void* base);
82 static void fixup_wsse(struct ws_servent* p_wsse, void* base);
84 /* ----------------------------------- async/non-blocking I/O */
86 int WINSOCK_unblock_io(int fd, int noblock)
88 int fd_flags;
90 fd_flags = fcntl(fd, F_GETFL, 0);
91 if (fcntl(fd, F_SETFL, (noblock)? fd_flags | O_NONBLOCK
92 : fd_flags & ~O_NONBLOCK ) != -1) return 0;
93 return -1;
96 int WINSOCK_check_async_op(ws_async_op* p_aop)
98 ws_async_op* p = __async_op_list;
99 while( p ) if( p == p_aop ) return 1;
100 else p = p->next;
101 return 0;
104 int WINSOCK_cancel_async_op(ws_async_op* p_aop)
106 /* SIGIO unsafe! */
108 if( WINSOCK_check_async_op(p_aop) )
110 if( !(p_aop->flags & WSMSG_DEAD_AOP) )
112 kill(p_aop->pid, SIGKILL);
113 waitpid(p_aop->pid, NULL, 0); /* just in case */
114 close(p_aop->fd[0]);
116 WINSOCK_unlink_async_op(p_aop);
117 EVENT_DeleteIO( p_aop->fd[0], EVENT_IO_READ );
118 p_aop->flags = 0;
119 p_aop->hWnd = p_aop->uMsg = 0;
120 return 1;
122 return 0;
125 void WINSOCK_cancel_task_aops(HTASK16 hTask, void (*__opfree)(void*))
127 /* SIGIO safe, hTask == 0 cancels all outstanding async ops */
129 int num = 0, num_dead = 0;
130 ws_async_op* p, *next;
132 TRACE(winsock," cancelling async DNS requests... \n");
134 SIGNAL_MaskAsyncEvents( TRUE );
135 next = __async_op_list;
136 while( (p = next) )
138 HTASK16 hWndTask = GetWindowTask16(p->hWnd);
140 next = p->next;
141 if(!hTask || !hWndTask || (hTask == hWndTask))
143 num++;
144 if( p->flags & WSMSG_DEAD_AOP )
145 num_dead++;
147 WINSOCK_cancel_async_op(p);
148 if( __opfree ) __opfree(p);
151 SIGNAL_MaskAsyncEvents( FALSE );
152 TRACE(winsock," -> %i total (%i active)\n", num, num - num_dead );
155 void WINSOCK_link_async_op(ws_async_op* p_aop)
157 /* SIGIO safe */
159 p_aop->prev = NULL;
160 SIGNAL_MaskAsyncEvents( TRUE );
161 if( __async_op_list )
163 ws_async_op* p = __async_op_list;
164 __async_op_list->prev = p_aop;
166 /* traverse the list and retire dead ops created
167 * by the signal handler (see below). */
169 while( p )
171 if( p->flags & WSMSG_DEAD_AOP )
173 ws_async_op* dead = p;
175 TRACE(winsock,"\treaping dead aop [%08x]\n", (unsigned)p );
177 p = p->next;
178 WINSOCK_unlink_async_op( dead );
179 __ws_memfree( dead );
180 continue;
182 p = p->next;
185 p_aop->next = __async_op_list;
186 __async_op_list = p_aop;
188 SIGNAL_MaskAsyncEvents( FALSE );
190 ASYNC_RegisterFD(p_aop->fd[0],WINSOCK_async_handler,p_aop);
193 void WINSOCK_unlink_async_op(ws_async_op* p_aop)
195 /* SIGIO unsafe! */
197 if( p_aop == __async_op_list ) __async_op_list = p_aop->next;
198 else
199 p_aop->prev->next = p_aop->next;
200 if( p_aop->next ) p_aop->next->prev = p_aop->prev;
202 ASYNC_UnregisterFD(p_aop->fd[0],WINSOCK_async_handler);
205 /* ----------------------------------- SIGIO handler -
207 * link_async_op/unlink_async_op allow to install generic
208 * async IO handlers (provided that aop_control function is defined).
210 * Note: pipe-based handlers must raise explicit SIGIO with kill(2).
213 static void WINSOCK_async_handler(int unixfd,void *private)
215 ws_async_op* p_aop = (ws_async_op*)private;
217 if( p_aop->aop_control(p_aop, AOP_IO) == AOP_CONTROL_REMOVE )
219 /* NOTE: memory management is signal-unsafe, therefore
220 * we can only set a flag to remove this p_aop later on.
222 p_aop->flags = WSMSG_DEAD_AOP;
223 close(p_aop->fd[0]);
224 if( p_aop->pid )
226 kill(p_aop->pid, SIGKILL);
227 waitpid(p_aop->pid, NULL, WNOHANG);
228 p_aop->pid = 0;
233 /* ----------------------------------- getXbyY requests */
235 /* child process control struct */
236 static ws_async_ctl async_ctl;
238 static int aop_control(ws_async_op* p_aop, int flag )
240 unsigned lLength;
242 /* success: LOWORD(lLength) has the length of the struct
243 * to read.
244 * failure: LOWORD(lLength) is zero, HIWORD(lLength) contains
245 * the error code.
248 read(p_aop->fd[0], &lLength, sizeof(unsigned));
249 if( LOWORD(lLength) )
251 if( (int)LOWORD(lLength) <= p_aop->buflen )
253 char* buffer = (p_aop->flags & WSMSG_WIN32_AOP)
254 ? p_aop->b.lin_base : (char*)PTR_SEG_TO_LIN(p_aop->b.seg_base);
256 read(p_aop->fd[0], buffer, LOWORD(lLength));
257 switch( p_aop->flags & WSMSG_ASYNC_RQMASK )
259 case WSMSG_ASYNC_HOSTBYNAME:
260 case WSMSG_ASYNC_HOSTBYADDR:
261 fixup_wshe((struct ws_hostent*)buffer, p_aop->b.ptr_base); break;
262 case WSMSG_ASYNC_PROTOBYNAME:
263 case WSMSG_ASYNC_PROTOBYNUM:
264 fixup_wspe((struct ws_protoent*)buffer, p_aop->b.ptr_base); break;
265 case WSMSG_ASYNC_SERVBYNAME:
266 case WSMSG_ASYNC_SERVBYPORT:
267 fixup_wsse((struct ws_servent*)buffer, p_aop->b.ptr_base); break;
268 default:
269 if( p_aop->flags ) WARN(winsock,"Received unknown async request!\n");
270 return AOP_CONTROL_REMOVE;
273 else lLength = ((UINT)LOWORD(lLength)) | ((unsigned)WSAENOBUFS << 16);
274 } /* failure */
276 /* was a __WS_ASYNC_DEBUG statement */
277 TRACE(winsock, "DNS aop completed: hWnd [%04x], uMsg [%04x], "
278 "aop [%04x], event [%08lx]\n",
279 p_aop->hWnd, p_aop->uMsg, __ws_gethandle(p_aop), (LPARAM)lLength);
281 /* FIXME: update num_async_rq */
282 EVENT_DeleteIO( p_aop->fd[0], EVENT_IO_READ );
283 PostMessageA( p_aop->hWnd, p_aop->uMsg, __ws_gethandle(p_aop), (LPARAM)lLength );
285 return AOP_CONTROL_REMOVE; /* one-shot request */
289 HANDLE16 __WSAsyncDBQuery(LPWSINFO pwsi, HWND hWnd, UINT uMsg, INT type,
290 LPCSTR init, INT len, LPCSTR proto, void* sbuf, INT buflen, UINT flag)
292 /* queue 'flag' request and fork off its handler */
294 async_ctl.ws_aop = (ws_async_op*)__ws_memalloc(sizeof(ws_async_op));
296 if( async_ctl.ws_aop )
298 HANDLE16 handle = __ws_gethandle(async_ctl.ws_aop);
300 if( pipe(async_ctl.ws_aop->fd) == 0 )
302 async_ctl.rq.init = (char*)init;
303 async_ctl.ilength = len;
304 async_ctl.buffer = (char*)proto;
305 async_ctl.type = type;
307 async_ctl.ws_aop->hWnd = hWnd;
308 async_ctl.ws_aop->uMsg = uMsg;
309 async_ctl.ws_aop->b.ptr_base = sbuf;
310 async_ctl.ws_aop->buflen = buflen;
311 async_ctl.ws_aop->flags = flag;
312 async_ctl.ws_aop->aop_control = &aop_control;
314 WINSOCK_link_async_op( async_ctl.ws_aop );
316 EVENT_AddIO( async_ctl.ws_aop->fd[0], EVENT_IO_READ );
317 pwsi->num_async_rq++;
319 async_ctl.ws_aop->pid = fork();
320 if( async_ctl.ws_aop->pid )
322 TRACE(winsock, "\tasync_op = %04x (child %i)\n",
323 handle, async_ctl.ws_aop->pid);
325 close(async_ctl.ws_aop->fd[1]); /* write endpoint */
326 if( async_ctl.ws_aop->pid > 0 )
327 return __ws_gethandle(async_ctl.ws_aop);
329 /* fork() failed */
331 pwsi->num_async_rq--;
332 EVENT_DeleteIO( async_ctl.ws_aop->fd[0], EVENT_IO_READ );
333 close(async_ctl.ws_aop->fd[0]);
334 pwsi->err = WSAEWOULDBLOCK;
336 else
338 extern BOOL THREAD_InitDone;
340 THREAD_InitDone = FALSE;
341 /* child process */
343 close(async_ctl.ws_aop->fd[0]); /* read endpoint */
344 switch( flag & WSMSG_ASYNC_RQMASK )
346 case WSMSG_ASYNC_HOSTBYADDR:
347 case WSMSG_ASYNC_HOSTBYNAME:
348 WS_do_async_gethost(pwsi, flag);
349 break;
350 case WSMSG_ASYNC_PROTOBYNUM:
351 case WSMSG_ASYNC_PROTOBYNAME:
352 WS_do_async_getproto(pwsi, flag);
353 break;
354 case WSMSG_ASYNC_SERVBYPORT:
355 case WSMSG_ASYNC_SERVBYNAME:
356 WS_do_async_getserv(pwsi, flag);
357 break;
359 _exit(0); /* skip atexit()'ed cleanup */
362 else pwsi->err = wsaErrno(); /* failed to create pipe */
364 __ws_memfree((void*)async_ctl.ws_aop);
365 } else pwsi->err = WSAEWOULDBLOCK;
366 return 0;
369 static int _async_notify()
371 /* use half-duplex pipe to send variable length packets
372 * to the parent process */
374 write(async_ctl.ws_aop->fd[1], &async_ctl.ilength, sizeof(unsigned));
375 write(async_ctl.ws_aop->fd[1], async_ctl.buffer, async_ctl.ilength );
377 #ifndef __EMX__
378 kill(getppid(), SIGIO); /* simulate async I/O */
379 #endif
381 /* was a __WS_ASYNC_DEBUG statement */
382 TRACE(winsock, "handler - notify aop [%d, buf %d]\n",
383 async_ctl.ilength, async_ctl.ws_aop->buflen);
384 return 1;
387 static void _async_fail()
389 /* write a DWORD with error code (low word is zero) */
391 async_ctl.ilength =
392 (h_errno < 0) ? (unsigned)WSAMAKEASYNCREPLY( 0, wsaErrno() )
393 : (unsigned)WSAMAKEASYNCREPLY( 0, wsaHerrno() );
394 write(async_ctl.ws_aop->fd[1], &async_ctl.ilength, sizeof(unsigned) );
395 #ifndef __EMX__
396 kill(getppid(), SIGIO); /* simulate async I/O */
397 #endif
399 /* was a __WS_ASYNC_DEBUG statement */
400 TRACE(winsock, "handler - failed aop [%d, buf %d]\n",
401 async_ctl.ilength, async_ctl.ws_aop->buflen);
404 void dump_ws_hostent_offset(struct ws_hostent* wshe)
406 int i;
407 char* base = (char*)wshe;
408 unsigned* ptr;
410 DUMP("h_name = %08x\t[%s]\n",
411 (unsigned)wshe->h_name, base + (unsigned)wshe->h_name);
412 DUMP("h_aliases = %08x\t[%08x]\n",
413 (unsigned)wshe->h_aliases, (unsigned)(base+(unsigned)wshe->h_aliases));
414 ptr = (unsigned*)(base + (unsigned)wshe->h_aliases);
415 for(i = 0; ptr[i]; i++ )
417 DUMP("%i - %08x [%s]\n", i + 1, ptr[i], ((char*)base) + ptr[i]);
419 DUMP("h_length = %i\n", wshe->h_length);
422 void WS_do_async_gethost(LPWSINFO pwsi, unsigned flag )
424 int size = 0;
425 struct hostent* p_he;
427 close(async_ctl.ws_aop->fd[0]);
429 p_he = (flag & WSMSG_ASYNC_HOSTBYNAME)
430 ? gethostbyname(async_ctl.rq.name)
431 : gethostbyaddr(async_ctl.rq.name,
432 async_ctl.ilength, async_ctl.type);
434 TRACE(winsock,"DNS: got hostent for [%s]\n", async_ctl.rq.name );
436 if( p_he ) /* convert to the Winsock format with internal pointers as offsets */
437 size = WS_dup_he(pwsi, p_he, WS_DUP_OFFSET |
438 ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
439 if( size )
441 async_ctl.buffer = (char*)pwsi->he;
442 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
443 _async_notify( flag );
445 else _async_fail();
448 void WS_do_async_getproto(LPWSINFO pwsi, unsigned flag )
450 int size = 0;
451 struct protoent* p_pe;
453 close(async_ctl.ws_aop->fd[0]);
454 p_pe = (flag & WSMSG_ASYNC_PROTOBYNAME)
455 ? getprotobyname(async_ctl.rq.name)
456 : getprotobynumber(async_ctl.type);
458 TRACE(winsock,"DNS: got protoent for [%s]\n", async_ctl.rq.name );
460 if( p_pe ) /* convert to the Winsock format with internal pointers as offsets */
461 size = WS_dup_pe(pwsi, p_pe, WS_DUP_OFFSET |
462 ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
463 if( size )
465 async_ctl.buffer = (char*)pwsi->pe;
466 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
467 _async_notify( flag );
469 else _async_fail();
472 void WS_do_async_getserv(LPWSINFO pwsi, unsigned flag )
474 int size = 0;
475 struct servent* p_se;
477 close(async_ctl.ws_aop->fd[0]);
478 p_se = (flag & WSMSG_ASYNC_SERVBYNAME)
479 ? getservbyname(async_ctl.rq.name, async_ctl.buffer)
480 : getservbyport(async_ctl.type, async_ctl.buffer);
482 if( p_se ) /* convert to the Winsock format with internal pointers as offsets */
483 size = WS_dup_se(pwsi, p_se, WS_DUP_OFFSET |
484 ((flag & WSMSG_WIN32_AOP) ? WS_DUP_LINEAR : WS_DUP_SEGPTR) );
485 if( size )
487 async_ctl.buffer = (char*)pwsi->se;
488 async_ctl.ilength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
489 _async_notify( flag );
491 else _async_fail();
494 /* ----------------------------------- helper functions -
496 * Raw results from the pipe contain internal pointers stored as
497 * offsets relative to the beginning of the buffer and we need
498 * to apply a fixup before passing them to applications.
500 * NOTE: It is possible to exploit the fact that fork() doesn't
501 * change the buffer address by storing fixed up pointers right
502 * in the handler. However, this will get in the way if we ever
503 * get around to implementing DNS helper daemon a-la Netscape 4.x.
506 void fixup_wshe(struct ws_hostent* p_wshe, void* base)
508 /* add 'base' to ws_hostent pointers to convert them from offsets */
510 int i;
511 unsigned* p_aliases,*p_addr;
513 p_aliases = (unsigned*)((char*)p_wshe + (unsigned)p_wshe->h_aliases);
514 p_addr = (unsigned*)((char*)p_wshe + (unsigned)p_wshe->h_addr_list);
515 ((unsigned)(p_wshe->h_name)) += (unsigned)base;
516 ((unsigned)(p_wshe->h_aliases)) += (unsigned)base;
517 ((unsigned)(p_wshe->h_addr_list)) += (unsigned)base;
518 for(i=0;p_aliases[i];i++) p_aliases[i] += (unsigned)base;
519 for(i=0;p_addr[i];i++) p_addr[i] += (unsigned)base;
522 void fixup_wspe(struct ws_protoent* p_wspe, void* base)
524 int i;
525 unsigned* p_aliases = (unsigned*)((char*)p_wspe + (unsigned)p_wspe->p_aliases);
526 ((unsigned)(p_wspe->p_name)) += (unsigned)base;
527 ((unsigned)(p_wspe->p_aliases)) += (unsigned)base;
528 for(i=0;p_aliases[i];i++) p_aliases[i] += (unsigned)base;
531 void fixup_wsse(struct ws_servent* p_wsse, void* base)
533 int i;
534 unsigned* p_aliases = (unsigned*)((char*)p_wsse + (unsigned)p_wsse->s_aliases);
535 ((unsigned)(p_wsse->s_name)) += (unsigned)base;
536 ((p_wsse->s_proto)) += (unsigned)base;
537 ((p_wsse->s_aliases)) += (unsigned)base;
538 for(i=0;p_aliases[i];i++) p_aliases[i] += (unsigned)base;