Added/fixed some documentation reported by winapi_check.
[wine] / dlls / winsock / async.c
1 /* Async WINSOCK DNS services
2  * 
3  * (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
4  * (C) 1999 Marcus Meissner
5  *
6  * NOTE: If you make any changes to fix a particular app, make sure
7  * they don't break something else like Netscape or telnet and ftp
8  * clients and servers (www.winsite.com got a lot of those).
9  * 
10  * FIXME:
11  *      - Add WSACancel* and correct handle management. (works rather well for
12  *        now without it.)
13  *      - Verify & Check all calls for correctness
14  *        (currently only WSAGetHostByName*, WSAGetServByPort* calls)
15  *      - Check error returns.
16  *      - mirc/mirc32 Finger @linux.kernel.org sometimes fails in threaded mode.
17  *        (not sure why)
18  *      - This implementation did ignore the "NOTE:" section above (since the
19  *        whole stuff did not work anyway to other changes).
20  */
21  
22 #include "config.h"
23
24 #include <string.h>
25 #include <sys/types.h>
26 #ifdef HAVE_SYS_IPC_H
27 # include <sys/ipc.h>
28 #endif
29 #include <sys/ioctl.h>
30 #ifdef HAVE_SYS_FILIO_H
31 # include <sys/filio.h>
32 #endif
33 #if defined(__svr4__)
34 #include <sys/ioccom.h>
35 #ifdef HAVE_SYS_SOCKIO_H
36 # include <sys/sockio.h>
37 #endif
38 #endif
39
40 #if defined(__EMX__)
41 # include <sys/so_ioctl.h>
42 #endif
43
44 #ifdef HAVE_SYS_PARAM_H
45 # include <sys/param.h>
46 #endif
47
48 #ifdef HAVE_SYS_MSG_H
49 # include <sys/msg.h>
50 #endif
51 #ifdef HAVE_SYS_WAIT_H
52 #include <sys/wait.h>
53 #endif
54 #ifdef HAVE_SYS_SOCKET_H
55 #include <sys/socket.h>
56 #endif
57 #ifdef HAVE_NETINET_IN_H
58 # include <netinet/in.h>
59 #endif
60 #ifdef HAVE_ARPA_INET_H
61 # include <arpa/inet.h>
62 #endif
63 #include <ctype.h>
64 #include <fcntl.h>
65 #include <errno.h>
66 #ifdef HAVE_SYS_ERRNO_H
67 #include <sys/errno.h>
68 #endif
69 #include <netdb.h>
70 #include <unistd.h>
71 #include <stdlib.h>
72 #ifdef HAVE_ARPA_NAMESER_H
73 # include <arpa/nameser.h>
74 #endif
75 #ifdef HAVE_RESOLV_H
76 # include <resolv.h>
77 #endif
78
79 #include "wine/winbase16.h"
80 #include "wingdi.h"
81 #include "winuser.h"
82 #include "winsock.h"
83 #include "winnt.h"
84 #include "heap.h"
85 #include "task.h"
86 #include "message.h"
87 #include "miscemu.h"
88 #include "wine/port.h"
89 #include "debugtools.h"
90
91 DEFAULT_DEBUG_CHANNEL(winsock)
92
93 /* ----------------------------------- helper functions - */
94
95 static int list_size(char** l, int item_size)
96 {
97   int i,j = 0;
98   if(l)
99   { for(i=0;l[i];i++) 
100         j += (item_size) ? item_size : strlen(l[i]) + 1;
101     j += (i + 1) * sizeof(char*); }
102   return j;
103 }
104
105 static int list_dup(char** l_src, char* ref, char* base, int item_size)
106
107    /* base is either either equal to ref or 0 or SEGPTR */
108
109    char*                p = ref;
110    char**               l_to = (char**)ref;
111    int                  i,j,k;
112
113    for(j=0;l_src[j];j++) ;
114    p += (j + 1) * sizeof(char*);
115    for(i=0;i<j;i++)
116    { l_to[i] = base + (p - ref);
117      k = ( item_size ) ? item_size : strlen(l_src[i]) + 1;
118      memcpy(p, l_src[i], k); p += k; }
119    l_to[i] = NULL;
120    return (p - ref);
121 }
122
123 /* ----- hostent */
124
125 static int hostent_size(struct hostent* p_he)
126 {
127   int size = 0;
128   if( p_he )
129   { size  = sizeof(struct hostent); 
130     size += strlen(p_he->h_name) + 1;
131     size += list_size(p_he->h_aliases, 0);  
132     size += list_size(p_he->h_addr_list, p_he->h_length ); }
133   return size;
134 }
135
136 /* Copy hostent to p_to, fix up inside pointers using p_base (different for
137  * Win16 (linear vs. segmented). Return -neededsize on overrun.
138  */
139 static int WS_copy_he(struct ws_hostent *p_to,char *p_base,int t_size,struct hostent* p_he)
140 {
141         char* p_name,*p_aliases,*p_addr,*p;
142         int     size=hostent_size(p_he)+(sizeof(struct ws_hostent)-sizeof(struct hostent));
143
144         if (t_size < size)
145                 return -size;
146         p = (char*)p_to;
147         p += sizeof(struct ws_hostent);
148         p_name = p;
149         strcpy(p, p_he->h_name); p += strlen(p) + 1;
150         p_aliases = p;
151         p += list_dup(p_he->h_aliases, p, p_base + (p - (char*)p_to), 0);
152         p_addr = p;
153         list_dup(p_he->h_addr_list, p, p_base + (p - (char*)p_to), p_he->h_length);
154
155         p_to->h_addrtype = (INT16)p_he->h_addrtype; 
156         p_to->h_length = (INT16)p_he->h_length;
157         p_to->h_name = (SEGPTR)(p_base + (p_name - (char*)p_to));
158         p_to->h_aliases = (SEGPTR)(p_base + (p_aliases - (char*)p_to));
159         p_to->h_addr_list = (SEGPTR)(p_base + (p_addr - (char*)p_to));
160
161         return size;
162 }
163
164 /* ----- protoent */
165
166 static int protoent_size(struct protoent* p_pe)
167 {
168   int size = 0;
169   if( p_pe )
170   { size  = sizeof(struct protoent);
171     size += strlen(p_pe->p_name) + 1;
172     size += list_size(p_pe->p_aliases, 0); }
173   return size;
174 }
175
176 /* Copy protoent to p_to, fix up inside pointers using p_base (different for
177  * Win16 (linear vs. segmented). Return -neededsize on overrun.
178  */
179 static int WS_copy_pe(struct ws_protoent *p_to,char *p_base,int t_size,struct protoent* p_pe)
180 {
181         char* p_name,*p_aliases,*p;
182         int     size=protoent_size(p_pe)+(sizeof(struct ws_protoent)-sizeof(struct protoent));
183
184         if (t_size < size)
185                 return -size;
186         p = (char*)p_to;
187         p += sizeof(struct ws_protoent);
188         p_name = p;
189         strcpy(p, p_pe->p_name); p += strlen(p) + 1;
190         p_aliases = p;
191         list_dup(p_pe->p_aliases, p, p_base + (p - (char*)p_to), 0);
192
193         p_to->p_proto = (INT16)p_pe->p_proto;
194         p_to->p_name = (SEGPTR)(p_base) + (p_name - (char*)p_to);
195         p_to->p_aliases = (SEGPTR)((p_base) + (p_aliases - (char*)p_to)); 
196
197
198         return size;
199 }
200
201 /* ----- servent */
202
203 static int servent_size(struct servent* p_se)
204 {
205         int size = 0;
206         if( p_se ) {
207                 size += sizeof(struct servent);
208                 size += strlen(p_se->s_proto) + strlen(p_se->s_name) + 2;
209                 size += list_size(p_se->s_aliases, 0);
210         }
211         return size;
212 }
213
214 /* Copy servent to p_to, fix up inside pointers using p_base (different for
215  * Win16 (linear vs. segmented). Return -neededsize on overrun.
216  */
217 static int WS_copy_se(struct ws_servent *p_to,char *p_base,int t_size,struct servent* p_se)
218 {
219         char* p_name,*p_aliases,*p_proto,*p;
220         int     size = servent_size(p_se)+(sizeof(struct ws_servent)-sizeof(struct servent));
221
222         if (t_size < size )
223                 return -size;
224         p = (char*)p_to;
225         p += sizeof(struct ws_servent);
226         p_name = p;
227         strcpy(p, p_se->s_name); p += strlen(p) + 1;
228         p_proto = p;
229         strcpy(p, p_se->s_proto); p += strlen(p) + 1;
230         p_aliases = p;
231         list_dup(p_se->s_aliases, p, p_base + (p - (char*)p_to), 0);
232
233         p_to->s_port = (INT16)p_se->s_port;
234         p_to->s_name = (SEGPTR)(p_base + (p_name - (char*)p_to));
235         p_to->s_proto = (SEGPTR)(p_base + (p_proto - (char*)p_to));
236         p_to->s_aliases = (SEGPTR)(p_base + (p_aliases - (char*)p_to)); 
237
238         return size;
239 }
240
241 static HANDLE __ws_async_handle = 0xdead;
242
243 /* Generic async query struct. we use symbolic names for the different queries
244  * for readability.
245  */
246 typedef struct _async_query {
247         HWND16          hWnd;
248         UINT16          uMsg;
249         LPCSTR          ptr1;
250 #define host_name       ptr1
251 #define host_addr       ptr1
252 #define serv_name       ptr1
253 #define proto_name      ptr1
254         LPCSTR          ptr2;
255 #define serv_proto      ptr2
256         int             int1;
257 #define host_len        int1
258 #define proto_number    int1
259 #define serv_port       int1
260         int             int2;
261 #define host_type       int2
262         SEGPTR          sbuf;
263         INT16           sbuflen;
264
265         HANDLE16        async_handle;
266         int             flags;
267 #define AQ_WIN16        0
268 #define AQ_WIN32        4
269 #define HB_WIN32(hb) (hb->flags & AQ_WIN32)
270 #define AQ_NUMBER       0
271 #define AQ_NAME         8
272
273 #define AQ_GETHOST      0
274 #define AQ_GETPROTO     1
275 #define AQ_GETSERV      2
276 #define AQ_GETMASK      3
277         int             qt;
278 } async_query;
279
280 /****************************************************************************
281  * The async query function.
282  *
283  * It is either called as a thread startup routine or directly. It has
284  * to free the passed arg from the process heap and PostMessageA the async
285  * result or the error code.
286  * 
287  * FIXME:
288  *      - errorhandling not verified.
289  */
290 static DWORD WINAPI _async_queryfun(LPVOID arg) {
291         async_query     *aq = (async_query*)arg;
292         int             size = 0;
293         WORD            fail = 0;
294         char            *targetptr = (HB_WIN32(aq)?(char*)aq->sbuf:(char*)PTR_SEG_TO_LIN(aq->sbuf));
295
296         switch (aq->flags & AQ_GETMASK) {
297         case AQ_GETHOST: {
298                         struct hostent          *he;
299                         struct ws_hostent       *wshe = (struct ws_hostent*)targetptr;
300
301                         he = (aq->flags & AQ_NAME) ?
302                                 gethostbyname(aq->host_name):
303                                 gethostbyaddr(aq->host_addr,aq->host_len,aq->host_type);
304                         if (he) {
305                                 size = WS_copy_he(wshe,(char*)aq->sbuf,aq->sbuflen,he);
306                                 if (size < 0) {
307                                         fail = WSAENOBUFS;
308                                         size = -size;
309                                 }
310                         } else {
311                                 fail = WSAENOBUFS;
312                         }
313                 }
314                 break;
315         case AQ_GETPROTO: {
316                         struct  protoent        *pe;
317                         struct ws_protoent      *wspe = (struct ws_protoent*)targetptr;
318                         pe = (aq->flags & AQ_NAME)?
319                                 getprotobyname(aq->proto_name) : 
320                                 getprotobynumber(aq->proto_number);
321                         if (pe) {
322                                 size = WS_copy_pe(wspe,(char*)aq->sbuf,aq->sbuflen,pe);
323                                 if (size < 0) {
324                                         fail = WSAENOBUFS;
325                                         size = -size;
326                                 }
327                         } else {
328                                 fail = WSAENOBUFS;
329                         }
330                 }
331                 break;
332         case AQ_GETSERV: {
333                         struct  servent *se;
334                         struct ws_servent       *wsse = (struct ws_servent*)targetptr;
335                         se = (aq->flags & AQ_NAME)?
336                                 getservbyname(aq->serv_name,aq->serv_proto) : 
337                                 getservbyport(aq->serv_port,aq->serv_proto);
338                         if (se) {
339                                 size = WS_copy_se(wsse,(char*)aq->sbuf,aq->sbuflen,se);
340                                 if (size < 0) {
341                                         fail = WSAENOBUFS;
342                                         size = -size;
343                                 }
344                         } else {
345                                 fail = WSAENOBUFS;
346                         }
347                 }
348                 break;
349         }
350         PostMessageA(aq->hWnd,aq->uMsg,aq->async_handle,size|(fail<<16));
351         HeapFree(GetProcessHeap(),0,arg);
352         return 0;
353 }
354
355 /****************************************************************************
356  * The main async help function. 
357  * 
358  * It either starts a thread or just calls the function directly for platforms
359  * with no thread support. This relies on the fact that PostMessage() does
360  * not actually call the windowproc before the function returns.
361  */
362 static HANDLE16 __WSAsyncDBQuery(
363         HWND hWnd, UINT uMsg,INT int1,LPCSTR ptr1, INT int2, LPCSTR ptr2,
364         void *sbuf, INT sbuflen, UINT flags
365 ) {
366         async_query     *aq = HeapAlloc(GetProcessHeap(),0,sizeof(async_query));
367         HANDLE  hthread;
368
369         aq->hWnd        = hWnd;
370         aq->uMsg        = uMsg;
371         aq->int1        = int1;
372         aq->ptr1        = ptr1;
373         aq->int2        = int2;
374         aq->ptr2        = ptr2;
375         aq->async_handle = ++__ws_async_handle;
376         aq->flags       = flags;
377         aq->sbuf        = (SEGPTR)sbuf;
378         aq->sbuflen     = sbuflen;
379 #if 1
380         hthread = CreateThread(NULL,0,_async_queryfun,aq,0,NULL);
381         if (hthread==INVALID_HANDLE_VALUE)
382 #endif
383                 _async_queryfun(aq);
384         return __ws_async_handle;
385 }
386
387
388 /***********************************************************************
389  *       WSAAsyncGetHostByAddr()        (WINSOCK.102)
390  */
391 HANDLE16 WINAPI WSAAsyncGetHostByAddr16(HWND16 hWnd, UINT16 uMsg, LPCSTR addr,
392                                INT16 len, INT16 type, SEGPTR sbuf, INT16 buflen)
393 {
394         TRACE("hwnd %04x, msg %04x, addr %08x[%i]\n",
395                hWnd, uMsg, (unsigned)addr , len );
396         return __WSAsyncDBQuery(hWnd,uMsg,len,addr,type,NULL,(void*)sbuf,buflen,AQ_NUMBER|AQ_WIN16|AQ_GETHOST);
397 }
398
399 /***********************************************************************
400  *       WSAAsyncGetHostByAddr()        (WSOCK32.102)
401  */
402 HANDLE WINAPI WSAAsyncGetHostByAddr(HWND hWnd, UINT uMsg, LPCSTR addr,
403                                INT len, INT type, LPSTR sbuf, INT buflen)
404 {
405         TRACE("hwnd %04x, msg %04x, addr %08x[%i]\n",
406                hWnd, uMsg, (unsigned)addr , len );
407         return __WSAsyncDBQuery(hWnd,uMsg,len,addr,type,NULL,sbuf,buflen,AQ_NUMBER|AQ_WIN32|AQ_GETHOST);
408 }
409
410 /***********************************************************************
411  *       WSAAsyncGetHostByName()        (WINSOCK.103)
412  */
413 HANDLE16 WINAPI WSAAsyncGetHostByName16(HWND16 hWnd, UINT16 uMsg, LPCSTR name, 
414                                       SEGPTR sbuf, INT16 buflen)
415 {
416         TRACE("hwnd %04x, msg %04x, host %s, buffer %i\n", hWnd, uMsg, (name)?name:"<null>", (int)buflen );
417
418         return __WSAsyncDBQuery(hWnd,uMsg,0,name,0,NULL,(void*)sbuf,buflen,AQ_NAME|AQ_WIN16|AQ_GETHOST);
419 }                     
420
421 /***********************************************************************
422  *       WSAAsyncGetHostByName()        (WSOCK32.103)
423  */
424 HANDLE WINAPI WSAAsyncGetHostByName(HWND hWnd, UINT uMsg, LPCSTR name, 
425                                         LPSTR sbuf, INT buflen)
426 {
427         TRACE("hwnd %04x, msg %08x, host %s, buffer %i\n", 
428                (HWND16)hWnd, uMsg, (name)?name:"<null>", (int)buflen );
429         return __WSAsyncDBQuery(hWnd,uMsg,0,name,0,NULL,sbuf,buflen,AQ_NAME|AQ_WIN32|AQ_GETHOST);
430 }
431
432 /***********************************************************************
433  *       WSAAsyncGetProtoByName()       (WINSOCK.105)
434  */
435 HANDLE16 WINAPI WSAAsyncGetProtoByName16(HWND16 hWnd, UINT16 uMsg, LPCSTR name, 
436                                          SEGPTR sbuf, INT16 buflen)
437 {
438         TRACE("hwnd %04x, msg %08x, protocol %s\n",
439                (HWND16)hWnd, uMsg, (name)?name:"<null>" );
440         return __WSAsyncDBQuery(hWnd,uMsg,0,name,0,NULL,(void*)sbuf,buflen,AQ_GETPROTO|AQ_NAME|AQ_WIN16);
441 }
442
443 /***********************************************************************
444  *       WSAAsyncGetProtoByName()       (WSOCK32.105)
445  */
446 HANDLE WINAPI WSAAsyncGetProtoByName(HWND hWnd, UINT uMsg, LPCSTR name,
447                                          LPSTR sbuf, INT buflen)
448 {
449         TRACE("hwnd %04x, msg %08x, protocol %s\n",
450                (HWND16)hWnd, uMsg, (name)?name:"<null>" );
451         return __WSAsyncDBQuery(hWnd,uMsg,0,name,0,NULL,sbuf,buflen,AQ_GETPROTO|AQ_NAME|AQ_WIN32);
452 }
453
454
455 /***********************************************************************
456  *       WSAAsyncGetProtoByNumber()     (WINSOCK.104)
457  */
458 HANDLE16 WINAPI WSAAsyncGetProtoByNumber16(HWND16 hWnd,UINT16 uMsg,INT16 number,
459                                            SEGPTR sbuf, INT16 buflen)
460 {
461         TRACE("hwnd %04x, msg %04x, num %i\n", hWnd, uMsg, number );
462         return __WSAsyncDBQuery(hWnd,uMsg,number,NULL,0,NULL,(void*)sbuf,buflen,AQ_GETPROTO|AQ_NUMBER|AQ_WIN16);
463 }
464
465 /***********************************************************************
466  *       WSAAsyncGetProtoByNumber()     (WSOCK32.104)
467  */
468 HANDLE WINAPI WSAAsyncGetProtoByNumber(HWND hWnd, UINT uMsg, INT number,
469                                            LPSTR sbuf, INT buflen)
470 {
471         TRACE("hwnd %04x, msg %04x, num %i\n", hWnd, uMsg, number );
472
473         return __WSAsyncDBQuery(hWnd,uMsg,number,NULL,0,NULL,sbuf,buflen,AQ_GETPROTO|AQ_NUMBER|AQ_WIN32);
474 }
475
476 /***********************************************************************
477  *       WSAAsyncGetServByName()        (WINSOCK.107)
478  */
479 HANDLE16 WINAPI WSAAsyncGetServByName16(HWND16 hWnd, UINT16 uMsg, LPCSTR name, 
480                                         LPCSTR proto, SEGPTR sbuf, INT16 buflen)
481 {
482         TRACE("hwnd %04x, msg %04x, name %s, proto %s\n",
483                hWnd, uMsg, (name)?name:"<null>", (proto)?proto:"<null>" );
484
485         return __WSAsyncDBQuery(hWnd,uMsg,0,name,0,proto,(void*)sbuf,buflen,AQ_GETSERV|AQ_NAME|AQ_WIN16);
486 }
487
488 /***********************************************************************
489  *       WSAAsyncGetServByName()        (WSOCK32.107)
490  */
491 HANDLE WINAPI WSAAsyncGetServByName(HWND hWnd, UINT uMsg, LPCSTR name,
492                                         LPCSTR proto, LPSTR sbuf, INT buflen)
493 {
494         TRACE("hwnd %04x, msg %04x, name %s, proto %s\n",
495                hWnd, uMsg, (name)?name:"<null>", (proto)?proto:"<null>" );
496         return __WSAsyncDBQuery(hWnd,uMsg,0,name,0,proto,sbuf,buflen,AQ_GETSERV|AQ_NAME|AQ_WIN32);
497 }
498
499 /***********************************************************************
500  *       WSAAsyncGetServByPort()        (WINSOCK.106)
501  */
502 HANDLE16 WINAPI WSAAsyncGetServByPort16(HWND16 hWnd, UINT16 uMsg, INT16 port, 
503                                         LPCSTR proto, SEGPTR sbuf, INT16 buflen)
504 {
505         TRACE("hwnd %04x, msg %04x, port %i, proto %s\n",
506                hWnd, uMsg, port, (proto)?proto:"<null>" );
507         return __WSAsyncDBQuery(hWnd,uMsg,port,NULL,0,proto,(void*)sbuf,buflen,AQ_GETSERV|AQ_NUMBER|AQ_WIN16);
508 }
509
510 /***********************************************************************
511  *       WSAAsyncGetServByPort()        (WSOCK32.106)
512  */
513 HANDLE WINAPI WSAAsyncGetServByPort(HWND hWnd, UINT uMsg, INT port,
514                                         LPCSTR proto, LPSTR sbuf, INT buflen)
515 {
516         TRACE("hwnd %04x, msg %04x, port %i, proto %s\n",
517                hWnd, uMsg, port, (proto)?proto:"<null>" );
518         return __WSAsyncDBQuery(hWnd,uMsg,port,NULL,0,proto,sbuf,buflen,AQ_GETSERV|AQ_NUMBER|AQ_WIN32);
519 }
520
521 /***********************************************************************
522  *       WSACancelAsyncRequest()        (WINSOCK.108)(WSOCK32.109)
523  */
524 INT WINAPI WSACancelAsyncRequest(HANDLE hAsyncTaskHandle)
525 {
526     FIXME("(%08x),stub\n", hAsyncTaskHandle);
527     return 0;
528 }
529
530 INT16 WINAPI WSACancelAsyncRequest16(HANDLE16 hAsyncTaskHandle)
531 {
532     return (HANDLE16)WSACancelAsyncRequest((HANDLE)hAsyncTaskHandle);
533 }