mshtml: Move the MessageEvent construction to a helper.
[wine.git] / dlls / ws2_32 / unixlib.c
blob0625c5c72ce2a3df1b15091d809cad947062b1f3
1 /*
2 * Unix library functions
4 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
5 * Copyright (C) 2001 Stefan Leichter
6 * Copyright (C) 2004 Hans Leidekker
7 * Copyright (C) 2005 Marcus Meissner
8 * Copyright (C) 2006-2008 Kai Blin
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #if 0
26 #pragma makedep unix
27 #endif
29 #include "config.h"
30 #include <errno.h>
31 #include <pthread.h>
32 #include <stdarg.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #ifdef HAVE_NETDB_H
38 # include <netdb.h>
39 #endif
40 #ifdef HAVE_SYS_PARAM_H
41 # include <sys/param.h>
42 #endif
43 #ifdef HAVE_SYS_SOCKIO_H
44 # include <sys/sockio.h>
45 #endif
46 #ifdef HAVE_NETINET_IN_H
47 # include <netinet/in.h>
48 #endif
49 #ifdef HAVE_NETINET_TCP_H
50 # include <netinet/tcp.h>
51 #endif
52 #ifdef HAVE_ARPA_INET_H
53 # include <arpa/inet.h>
54 #endif
55 #ifdef HAVE_NET_IF_H
56 # define if_indextoname unix_if_indextoname
57 # define if_nametoindex unix_if_nametoindex
58 # include <net/if.h>
59 # undef if_indextoname
60 # undef if_nametoindex
61 #endif
62 #ifdef HAVE_IFADDRS_H
63 # include <ifaddrs.h>
64 #endif
65 #include <poll.h>
67 #ifdef HAVE_NETIPX_IPX_H
68 # include <netipx/ipx.h>
69 #elif defined(HAVE_LINUX_IPX_H)
70 # ifdef HAVE_ASM_TYPES_H
71 # include <asm/types.h>
72 # endif
73 # ifdef HAVE_LINUX_TYPES_H
74 # include <linux/types.h>
75 # endif
76 # include <linux/ipx.h>
77 #endif
78 #if defined(SOL_IPX) || defined(SO_DEFAULT_HEADERS)
79 # define HAS_IPX
80 #endif
82 #ifdef HAVE_LINUX_IRDA_H
83 # ifdef HAVE_LINUX_TYPES_H
84 # include <linux/types.h>
85 # endif
86 # include <linux/irda.h>
87 # define HAS_IRDA
88 #endif
90 #include "ntstatus.h"
91 #define WIN32_NO_STATUS
92 #include "windef.h"
93 #include "winerror.h"
94 #include "winternl.h"
95 #define USE_WS_PREFIX
96 #include "winsock2.h"
97 #include "ws2tcpip.h"
98 #include "wsipx.h"
99 #include "af_irda.h"
100 #include "wine/debug.h"
102 #include "ws2_32_private.h"
104 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
106 #ifndef HAVE_LINUX_GETHOSTBYNAME_R_6
107 static pthread_mutex_t host_mutex = PTHREAD_MUTEX_INITIALIZER;
108 #endif
110 #define MAP(x) {WS_ ## x, x}
112 static const int addrinfo_flag_map[][2] =
114 MAP( AI_PASSIVE ),
115 MAP( AI_CANONNAME ),
116 MAP( AI_NUMERICHOST ),
117 #ifdef AI_NUMERICSERV
118 MAP( AI_NUMERICSERV ),
119 #endif
120 #ifdef AI_V4MAPPED
121 MAP( AI_V4MAPPED ),
122 #endif
123 MAP( AI_ALL ),
124 MAP( AI_ADDRCONFIG ),
127 static const int nameinfo_flag_map[][2] =
129 MAP( NI_DGRAM ),
130 MAP( NI_NAMEREQD ),
131 MAP( NI_NOFQDN ),
132 MAP( NI_NUMERICHOST ),
133 MAP( NI_NUMERICSERV ),
136 static const int family_map[][2] =
138 MAP( AF_UNSPEC ),
139 MAP( AF_INET ),
140 MAP( AF_INET6 ),
141 #ifdef AF_IPX
142 MAP( AF_IPX ),
143 #endif
144 #ifdef AF_IRDA
145 MAP( AF_IRDA ),
146 #endif
149 static const int socktype_map[][2] =
151 MAP( SOCK_STREAM ),
152 MAP( SOCK_DGRAM ),
153 MAP( SOCK_RAW ),
156 static const int ip_protocol_map[][2] =
158 MAP( IPPROTO_IP ),
159 MAP( IPPROTO_TCP ),
160 MAP( IPPROTO_UDP ),
161 MAP( IPPROTO_IPV6 ),
162 MAP( IPPROTO_ICMP ),
163 MAP( IPPROTO_IGMP ),
164 MAP( IPPROTO_RAW ),
165 {WS_IPPROTO_IPV4, IPPROTO_IPIP},
168 #undef MAP
170 static int addrinfo_flags_from_unix( int flags )
172 int ws_flags = 0;
173 unsigned int i;
175 for (i = 0; i < ARRAY_SIZE(addrinfo_flag_map); ++i)
177 if (flags & addrinfo_flag_map[i][1])
179 ws_flags |= addrinfo_flag_map[i][0];
180 flags &= ~addrinfo_flag_map[i][1];
184 if (flags)
185 FIXME( "unhandled flags %#x\n", flags );
186 return ws_flags;
189 static int addrinfo_flags_to_unix( int flags )
191 int unix_flags = 0;
192 unsigned int i;
194 for (i = 0; i < ARRAY_SIZE(addrinfo_flag_map); ++i)
196 if (flags & addrinfo_flag_map[i][0])
198 unix_flags |= addrinfo_flag_map[i][1];
199 flags &= ~addrinfo_flag_map[i][0];
203 if (flags)
204 FIXME( "unhandled flags %#x\n", flags );
205 return unix_flags;
208 static int nameinfo_flags_to_unix( int flags )
210 int unix_flags = 0;
211 unsigned int i;
213 for (i = 0; i < ARRAY_SIZE(nameinfo_flag_map); ++i)
215 if (flags & nameinfo_flag_map[i][0])
217 unix_flags |= nameinfo_flag_map[i][1];
218 flags &= ~nameinfo_flag_map[i][0];
222 if (flags)
223 FIXME( "unhandled flags %#x\n", flags );
224 return unix_flags;
227 static int family_from_unix( int family )
229 unsigned int i;
231 for (i = 0; i < ARRAY_SIZE(family_map); ++i)
233 if (family == family_map[i][1])
234 return family_map[i][0];
237 FIXME( "unhandled family %u\n", family );
238 return -1;
241 static int family_to_unix( int family )
243 unsigned int i;
245 for (i = 0; i < ARRAY_SIZE(family_map); ++i)
247 if (family == family_map[i][0])
248 return family_map[i][1];
251 FIXME( "unhandled family %u\n", family );
252 return -1;
255 static int socktype_from_unix( int type )
257 unsigned int i;
259 for (i = 0; i < ARRAY_SIZE(socktype_map); ++i)
261 if (type == socktype_map[i][1])
262 return socktype_map[i][0];
265 FIXME( "unhandled type %u\n", type );
266 return -1;
269 static int socktype_to_unix( int type )
271 unsigned int i;
273 for (i = 0; i < ARRAY_SIZE(socktype_map); ++i)
275 if (type == socktype_map[i][0])
276 return socktype_map[i][1];
279 FIXME( "unhandled type %u\n", type );
280 return -1;
283 static int protocol_from_unix( int protocol )
285 unsigned int i;
287 for (i = 0; i < ARRAY_SIZE(ip_protocol_map); ++i)
289 if (protocol == ip_protocol_map[i][1])
290 return ip_protocol_map[i][0];
293 if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255)
294 return protocol;
296 FIXME( "unhandled protocol %u\n", protocol );
297 return -1;
300 static int protocol_to_unix( int protocol )
302 unsigned int i;
304 for (i = 0; i < ARRAY_SIZE(ip_protocol_map); ++i)
306 if (protocol == ip_protocol_map[i][0])
307 return ip_protocol_map[i][1];
310 if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255)
311 return protocol;
313 FIXME( "unhandled protocol %u\n", protocol );
314 return -1;
317 static unsigned int errno_from_unix( int err )
319 switch (err)
321 case EINTR: return WSAEINTR;
322 case EBADF: return WSAEBADF;
323 case EPERM:
324 case EACCES: return WSAEACCES;
325 case EFAULT: return WSAEFAULT;
326 case EINVAL: return WSAEINVAL;
327 case EMFILE: return WSAEMFILE;
328 case EINPROGRESS:
329 case EWOULDBLOCK: return WSAEWOULDBLOCK;
330 case EALREADY: return WSAEALREADY;
331 case ENOTSOCK: return WSAENOTSOCK;
332 case EDESTADDRREQ: return WSAEDESTADDRREQ;
333 case EMSGSIZE: return WSAEMSGSIZE;
334 case EPROTOTYPE: return WSAEPROTOTYPE;
335 case ENOPROTOOPT: return WSAENOPROTOOPT;
336 case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
337 case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
338 case EOPNOTSUPP: return WSAEOPNOTSUPP;
339 case EPFNOSUPPORT: return WSAEPFNOSUPPORT;
340 case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
341 case EADDRINUSE: return WSAEADDRINUSE;
342 case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
343 case ENETDOWN: return WSAENETDOWN;
344 case ENETUNREACH: return WSAENETUNREACH;
345 case ENETRESET: return WSAENETRESET;
346 case ECONNABORTED: return WSAECONNABORTED;
347 case EPIPE:
348 case ECONNRESET: return WSAECONNRESET;
349 case ENOBUFS: return WSAENOBUFS;
350 case EISCONN: return WSAEISCONN;
351 case ENOTCONN: return WSAENOTCONN;
352 case ESHUTDOWN: return WSAESHUTDOWN;
353 case ETOOMANYREFS: return WSAETOOMANYREFS;
354 case ETIMEDOUT: return WSAETIMEDOUT;
355 case ECONNREFUSED: return WSAECONNREFUSED;
356 case ELOOP: return WSAELOOP;
357 case ENAMETOOLONG: return WSAENAMETOOLONG;
358 case EHOSTDOWN: return WSAEHOSTDOWN;
359 case EHOSTUNREACH: return WSAEHOSTUNREACH;
360 case ENOTEMPTY: return WSAENOTEMPTY;
361 #ifdef EPROCLIM
362 case EPROCLIM: return WSAEPROCLIM;
363 #endif
364 #ifdef EUSERS
365 case EUSERS: return WSAEUSERS;
366 #endif
367 #ifdef EDQUOT
368 case EDQUOT: return WSAEDQUOT;
369 #endif
370 #ifdef ESTALE
371 case ESTALE: return WSAESTALE;
372 #endif
373 #ifdef EREMOTE
374 case EREMOTE: return WSAEREMOTE;
375 #endif
376 default:
377 FIXME( "unknown error: %s\n", strerror( err ) );
378 return WSAEFAULT;
382 static UINT host_errno_from_unix( int err )
384 WARN( "%d\n", err );
386 switch (err)
388 case HOST_NOT_FOUND: return WSAHOST_NOT_FOUND;
389 case TRY_AGAIN: return WSATRY_AGAIN;
390 case NO_RECOVERY: return WSANO_RECOVERY;
391 case NO_DATA: return WSANO_DATA;
392 case ENOBUFS: return WSAENOBUFS;
393 case 0: return 0;
394 default:
395 WARN( "Unknown h_errno %d!\n", err );
396 return WSAEOPNOTSUPP;
400 static int addrinfo_err_from_unix( int err )
402 switch (err)
404 case 0: return 0;
405 case EAI_AGAIN: return WS_EAI_AGAIN;
406 case EAI_BADFLAGS: return WS_EAI_BADFLAGS;
407 case EAI_FAIL: return WS_EAI_FAIL;
408 case EAI_FAMILY: return WS_EAI_FAMILY;
409 case EAI_MEMORY: return WS_EAI_MEMORY;
410 /* EAI_NODATA is deprecated, but still used by Windows and Linux. We map
411 * the newer EAI_NONAME to EAI_NODATA for now until Windows changes too. */
412 #ifdef EAI_NODATA
413 case EAI_NODATA: return WS_EAI_NODATA;
414 #endif
415 #ifdef EAI_NONAME
416 case EAI_NONAME: return WS_EAI_NODATA;
417 #endif
418 case EAI_SERVICE: return WS_EAI_SERVICE;
419 case EAI_SOCKTYPE: return WS_EAI_SOCKTYPE;
420 case EAI_SYSTEM:
421 /* some broken versions of glibc return EAI_SYSTEM and set errno to
422 * 0 instead of returning EAI_NONAME */
423 return errno ? errno_from_unix( errno ) : WS_EAI_NONAME;
425 default:
426 FIXME( "unhandled error %d\n", err );
427 return err;
431 union unix_sockaddr
433 struct sockaddr addr;
434 struct sockaddr_in in;
435 struct sockaddr_in6 in6;
436 #ifdef HAS_IPX
437 struct sockaddr_ipx ipx;
438 #endif
439 #ifdef HAS_IRDA
440 struct sockaddr_irda irda;
441 #endif
444 /* different from the version in ntdll and server; it does not return failure if
445 * given a short buffer */
446 static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_sockaddr *wsaddr, socklen_t wsaddrlen )
448 memset( wsaddr, 0, wsaddrlen );
450 switch (uaddr->addr.sa_family)
452 case AF_INET:
454 struct WS_sockaddr_in win = {0};
456 if (wsaddrlen >= sizeof(win))
458 win.sin_family = WS_AF_INET;
459 win.sin_port = uaddr->in.sin_port;
460 memcpy( &win.sin_addr, &uaddr->in.sin_addr, sizeof(win.sin_addr) );
461 memcpy( wsaddr, &win, sizeof(win) );
463 return sizeof(win);
466 case AF_INET6:
468 struct WS_sockaddr_in6 win = {0};
470 if (wsaddrlen >= sizeof(win))
472 win.sin6_family = WS_AF_INET6;
473 win.sin6_port = uaddr->in6.sin6_port;
474 win.sin6_flowinfo = uaddr->in6.sin6_flowinfo;
475 memcpy( &win.sin6_addr, &uaddr->in6.sin6_addr, sizeof(win.sin6_addr) );
476 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
477 win.sin6_scope_id = uaddr->in6.sin6_scope_id;
478 #endif
479 memcpy( wsaddr, &win, sizeof(win) );
481 return sizeof(win);
484 #ifdef HAS_IPX
485 case AF_IPX:
487 struct WS_sockaddr_ipx win = {0};
489 if (wsaddrlen >= sizeof(win))
491 win.sa_family = WS_AF_IPX;
492 memcpy( win.sa_netnum, &uaddr->ipx.sipx_network, sizeof(win.sa_netnum) );
493 memcpy( win.sa_nodenum, &uaddr->ipx.sipx_node, sizeof(win.sa_nodenum) );
494 win.sa_socket = uaddr->ipx.sipx_port;
495 memcpy( wsaddr, &win, sizeof(win) );
497 return sizeof(win);
499 #endif
501 #ifdef HAS_IRDA
502 case AF_IRDA:
504 SOCKADDR_IRDA win;
506 if (wsaddrlen >= sizeof(win))
508 win.irdaAddressFamily = WS_AF_IRDA;
509 memcpy( win.irdaDeviceID, &uaddr->irda.sir_addr, sizeof(win.irdaDeviceID) );
510 if (uaddr->irda.sir_lsap_sel != LSAP_ANY)
511 snprintf( win.irdaServiceName, sizeof(win.irdaServiceName), "LSAP-SEL%u", uaddr->irda.sir_lsap_sel );
512 else
513 memcpy( win.irdaServiceName, uaddr->irda.sir_name, sizeof(win.irdaServiceName) );
514 memcpy( wsaddr, &win, sizeof(win) );
516 return sizeof(win);
518 #endif
520 case AF_UNSPEC:
521 return 0;
523 default:
524 FIXME( "unknown address family %d\n", uaddr->addr.sa_family );
525 return 0;
529 static socklen_t sockaddr_to_unix( const struct WS_sockaddr *wsaddr, int wsaddrlen, union unix_sockaddr *uaddr )
531 memset( uaddr, 0, sizeof(*uaddr) );
533 switch (wsaddr->sa_family)
535 case WS_AF_INET:
537 struct WS_sockaddr_in win = {0};
539 if (wsaddrlen < sizeof(win)) return 0;
540 memcpy( &win, wsaddr, sizeof(win) );
541 uaddr->in.sin_family = AF_INET;
542 uaddr->in.sin_port = win.sin_port;
543 memcpy( &uaddr->in.sin_addr, &win.sin_addr, sizeof(win.sin_addr) );
544 return sizeof(uaddr->in);
547 case WS_AF_INET6:
549 struct WS_sockaddr_in6 win = {0};
551 if (wsaddrlen < sizeof(win)) return 0;
552 memcpy( &win, wsaddr, sizeof(win) );
553 uaddr->in6.sin6_family = AF_INET6;
554 uaddr->in6.sin6_port = win.sin6_port;
555 uaddr->in6.sin6_flowinfo = win.sin6_flowinfo;
556 memcpy( &uaddr->in6.sin6_addr, &win.sin6_addr, sizeof(win.sin6_addr) );
557 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
558 uaddr->in6.sin6_scope_id = win.sin6_scope_id;
559 #endif
560 return sizeof(uaddr->in6);
563 #ifdef HAS_IPX
564 case WS_AF_IPX:
566 struct WS_sockaddr_ipx win = {0};
568 if (wsaddrlen < sizeof(win)) return 0;
569 memcpy( &win, wsaddr, sizeof(win) );
570 uaddr->ipx.sipx_family = AF_IPX;
571 memcpy( &uaddr->ipx.sipx_network, win.sa_netnum, sizeof(win.sa_netnum) );
572 memcpy( &uaddr->ipx.sipx_node, win.sa_nodenum, sizeof(win.sa_nodenum) );
573 uaddr->ipx.sipx_port = win.sa_socket;
574 return sizeof(uaddr->ipx);
576 #endif
578 #ifdef HAS_IRDA
579 case WS_AF_IRDA:
581 SOCKADDR_IRDA win = {0};
582 unsigned int lsap_sel;
584 if (wsaddrlen < sizeof(win)) return 0;
585 memcpy( &win, wsaddr, sizeof(win) );
586 uaddr->irda.sir_family = AF_IRDA;
587 if (sscanf( win.irdaServiceName, "LSAP-SEL%u", &lsap_sel ) == 1)
588 uaddr->irda.sir_lsap_sel = lsap_sel;
589 else
591 uaddr->irda.sir_lsap_sel = LSAP_ANY;
592 memcpy( uaddr->irda.sir_name, win.irdaServiceName, sizeof(win.irdaServiceName) );
594 memcpy( &uaddr->irda.sir_addr, win.irdaDeviceID, sizeof(win.irdaDeviceID) );
595 return sizeof(uaddr->irda);
597 #endif
599 case WS_AF_UNSPEC:
600 switch (wsaddrlen)
602 default: /* likely an ipv4 address */
603 case sizeof(struct WS_sockaddr_in):
604 return sizeof(uaddr->in);
606 #ifdef HAS_IPX
607 case sizeof(struct WS_sockaddr_ipx):
608 return sizeof(uaddr->ipx);
609 #endif
611 #ifdef HAS_IRDA
612 case sizeof(SOCKADDR_IRDA):
613 return sizeof(uaddr->irda);
614 #endif
616 case sizeof(struct WS_sockaddr_in6):
617 return sizeof(uaddr->in6);
620 default:
621 FIXME( "unknown address family %u\n", wsaddr->sa_family );
622 return 0;
626 static BOOL addrinfo_in_list( const struct WS_addrinfo *list, const struct WS_addrinfo *ai )
628 const struct WS_addrinfo *cursor = list;
629 while (cursor)
631 if (ai->ai_flags == cursor->ai_flags &&
632 ai->ai_family == cursor->ai_family &&
633 ai->ai_socktype == cursor->ai_socktype &&
634 ai->ai_protocol == cursor->ai_protocol &&
635 ai->ai_addrlen == cursor->ai_addrlen &&
636 !memcmp( ai->ai_addr, cursor->ai_addr, ai->ai_addrlen ) &&
637 ((ai->ai_canonname && cursor->ai_canonname && !strcmp( ai->ai_canonname, cursor->ai_canonname ))
638 || (!ai->ai_canonname && !cursor->ai_canonname)))
640 return TRUE;
642 cursor = cursor->ai_next;
644 return FALSE;
647 static NTSTATUS unix_getaddrinfo( void *args )
649 #ifdef HAVE_GETADDRINFO
650 struct getaddrinfo_params *params = args;
651 const char *service = params->service;
652 const struct WS_addrinfo *hints = params->hints;
653 struct addrinfo unix_hints = {0};
654 struct addrinfo *unix_info, *src;
655 struct WS_addrinfo *dst, *prev = NULL;
656 unsigned int needed_size = 0;
657 int ret;
659 /* servname tweak required by OSX and BSD kernels */
660 if (service && !service[0]) service = "0";
662 if (hints)
664 unix_hints.ai_flags = addrinfo_flags_to_unix( hints->ai_flags );
666 if (hints->ai_family)
667 unix_hints.ai_family = family_to_unix( hints->ai_family );
669 if (hints->ai_socktype)
671 if ((unix_hints.ai_socktype = socktype_to_unix( hints->ai_socktype )) < 0)
672 return WSAESOCKTNOSUPPORT;
675 if (hints->ai_protocol)
676 unix_hints.ai_protocol = max( protocol_to_unix( hints->ai_protocol ), 0 );
678 /* Windows allows some invalid combinations */
679 if (unix_hints.ai_protocol == IPPROTO_TCP
680 && unix_hints.ai_socktype != SOCK_STREAM
681 && unix_hints.ai_socktype != SOCK_SEQPACKET)
683 WARN( "ignoring invalid type %u for TCP\n", unix_hints.ai_socktype );
684 unix_hints.ai_socktype = 0;
686 else if (unix_hints.ai_protocol == IPPROTO_UDP && unix_hints.ai_socktype != SOCK_DGRAM)
688 WARN( "ignoring invalid type %u for UDP\n", unix_hints.ai_socktype );
689 unix_hints.ai_socktype = 0;
691 else if (unix_hints.ai_protocol >= WS_NSPROTO_IPX && unix_hints.ai_protocol <= WS_NSPROTO_IPX + 255
692 && unix_hints.ai_socktype != SOCK_DGRAM)
694 WARN( "ignoring invalid type %u for IPX\n", unix_hints.ai_socktype );
695 unix_hints.ai_socktype = 0;
697 else if (unix_hints.ai_protocol == IPPROTO_IPV6)
699 WARN( "ignoring protocol IPv6\n" );
700 unix_hints.ai_protocol = 0;
704 ret = getaddrinfo( params->node, service, hints ? &unix_hints : NULL, &unix_info );
705 if (ret)
706 return addrinfo_err_from_unix( ret );
708 for (src = unix_info; src != NULL; src = src->ai_next)
710 needed_size += sizeof(struct WS_addrinfo);
711 if (src->ai_canonname)
712 needed_size += strlen( src->ai_canonname ) + 1;
713 needed_size += sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, NULL, 0 );
716 if (*params->size < needed_size)
718 *params->size = needed_size;
719 freeaddrinfo( unix_info );
720 return ERROR_INSUFFICIENT_BUFFER;
723 dst = params->info;
725 memset( params->info, 0, needed_size );
727 for (src = unix_info; src != NULL; src = src->ai_next)
729 void *next = dst + 1;
731 dst->ai_flags = addrinfo_flags_from_unix( src->ai_flags );
732 dst->ai_family = family_from_unix( src->ai_family );
733 if (hints)
735 dst->ai_socktype = hints->ai_socktype;
736 dst->ai_protocol = hints->ai_protocol;
738 else
740 dst->ai_socktype = socktype_from_unix( src->ai_socktype );
741 dst->ai_protocol = protocol_from_unix( src->ai_protocol );
743 if (src->ai_canonname)
745 size_t len = strlen( src->ai_canonname ) + 1;
747 dst->ai_canonname = next;
748 memcpy( dst->ai_canonname, src->ai_canonname, len );
749 next = dst->ai_canonname + len;
752 dst->ai_addrlen = sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, NULL, 0 );
753 dst->ai_addr = next;
754 sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, dst->ai_addr, dst->ai_addrlen );
755 dst->ai_next = NULL;
756 next = (char *)dst->ai_addr + dst->ai_addrlen;
758 if (dst == params->info || !addrinfo_in_list( params->info, dst ))
760 if (prev)
761 prev->ai_next = dst;
762 prev = dst;
763 dst = next;
767 freeaddrinfo( unix_info );
768 return 0;
769 #else
770 FIXME( "getaddrinfo() not found during build time\n" );
771 return WS_EAI_FAIL;
772 #endif
776 static int hostent_from_unix( const struct hostent *unix_host, struct WS_hostent *host, unsigned int *const size )
778 unsigned int needed_size = sizeof( struct WS_hostent ), alias_count = 0, addr_count = 0, i;
779 char *p;
781 needed_size += strlen( unix_host->h_name ) + 1;
783 for (alias_count = 0; unix_host->h_aliases[alias_count] != NULL; ++alias_count)
784 needed_size += sizeof(char *) + strlen( unix_host->h_aliases[alias_count] ) + 1;
785 needed_size += sizeof(char *); /* null terminator */
787 for (addr_count = 0; unix_host->h_addr_list[addr_count] != NULL; ++addr_count)
788 needed_size += sizeof(char *) + unix_host->h_length;
789 needed_size += sizeof(char *); /* null terminator */
791 if (*size < needed_size)
793 *size = needed_size;
794 return ERROR_INSUFFICIENT_BUFFER;
797 memset( host, 0, needed_size );
799 /* arrange the memory in the same order as windows >= XP */
801 host->h_addrtype = family_from_unix( unix_host->h_addrtype );
802 host->h_length = unix_host->h_length;
804 p = (char *)(host + 1);
805 host->h_aliases = (char **)p;
806 p += (alias_count + 1) * sizeof(char *);
807 host->h_addr_list = (char **)p;
808 p += (addr_count + 1) * sizeof(char *);
810 for (i = 0; i < addr_count; ++i)
812 host->h_addr_list[i] = p;
813 memcpy( host->h_addr_list[i], unix_host->h_addr_list[i], unix_host->h_length );
814 p += unix_host->h_length;
817 for (i = 0; i < alias_count; ++i)
819 size_t len = strlen( unix_host->h_aliases[i] ) + 1;
821 host->h_aliases[i] = p;
822 memcpy( host->h_aliases[i], unix_host->h_aliases[i], len );
823 p += len;
826 host->h_name = p;
827 strcpy( host->h_name, unix_host->h_name );
829 return 0;
833 static NTSTATUS unix_gethostbyaddr( void *args )
835 struct gethostbyaddr_params *params = args;
836 const void *addr = params->addr;
837 const struct in_addr loopback = { htonl( INADDR_LOOPBACK ) };
838 int unix_family = family_to_unix( params->family );
839 struct hostent *unix_host;
840 int ret;
842 if (params->family == WS_AF_INET && params->len == 4 && !memcmp( addr, magic_loopback_addr, 4 ))
843 addr = &loopback;
845 #ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
847 char *unix_buffer, *new_buffer;
848 struct hostent stack_host;
849 int unix_size = 1024;
850 int locerr;
852 if (!(unix_buffer = malloc( unix_size )))
853 return WSAENOBUFS;
855 while (gethostbyaddr_r( addr, params->len, unix_family, &stack_host, unix_buffer,
856 unix_size, &unix_host, &locerr ) == ERANGE)
858 unix_size *= 2;
859 if (!(new_buffer = realloc( unix_buffer, unix_size )))
861 free( unix_buffer );
862 return WSAENOBUFS;
864 unix_buffer = new_buffer;
867 if (!unix_host)
868 ret = (locerr < 0 ? errno_from_unix( errno ) : host_errno_from_unix( locerr ));
869 else
870 ret = hostent_from_unix( unix_host, params->host, params->size );
872 free( unix_buffer );
873 return ret;
875 #else
876 pthread_mutex_lock( &host_mutex );
878 if (!(unix_host = gethostbyaddr( addr, params->len, unix_family )))
880 ret = (h_errno < 0 ? errno_from_unix( errno ) : host_errno_from_unix( h_errno ));
881 pthread_mutex_unlock( &host_mutex );
882 return ret;
885 ret = hostent_from_unix( unix_host, params->host, params->size );
887 pthread_mutex_unlock( &host_mutex );
888 return ret;
889 #endif
893 #ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
894 static NTSTATUS unix_gethostbyname( void *args )
896 struct gethostbyname_params *params = args;
897 struct hostent stack_host, *unix_host;
898 char *unix_buffer, *new_buffer;
899 int unix_size = 1024;
900 int locerr;
901 int ret;
903 if (!(unix_buffer = malloc( unix_size )))
904 return WSAENOBUFS;
906 while (gethostbyname_r( params->name, &stack_host, unix_buffer, unix_size, &unix_host, &locerr ) == ERANGE)
908 unix_size *= 2;
909 if (!(new_buffer = realloc( unix_buffer, unix_size )))
911 free( unix_buffer );
912 return WSAENOBUFS;
914 unix_buffer = new_buffer;
917 if (!unix_host)
918 ret = (locerr < 0 ? errno_from_unix( errno ) : host_errno_from_unix( locerr ));
919 else
920 ret = hostent_from_unix( unix_host, params->host, params->size );
922 free( unix_buffer );
923 return ret;
925 #else
926 static NTSTATUS unix_gethostbyname( void *args )
928 struct gethostbyname_params *params = args;
929 struct hostent *unix_host;
930 int ret;
932 pthread_mutex_lock( &host_mutex );
934 if (!(unix_host = gethostbyname( params->name )))
936 ret = (h_errno < 0 ? errno_from_unix( errno ) : host_errno_from_unix( h_errno ));
937 pthread_mutex_unlock( &host_mutex );
938 return ret;
941 ret = hostent_from_unix( unix_host, params->host, params->size );
943 pthread_mutex_unlock( &host_mutex );
944 return ret;
946 #endif
949 static NTSTATUS unix_gethostname( void *args )
951 struct gethostname_params *params = args;
953 if (!gethostname( params->name, params->size ))
954 return 0;
955 return errno_from_unix( errno );
959 static NTSTATUS unix_getnameinfo( void *args )
961 struct getnameinfo_params *params = args;
962 union unix_sockaddr unix_addr;
963 socklen_t unix_addr_len;
965 unix_addr_len = sockaddr_to_unix( params->addr, params->addr_len, &unix_addr );
967 return addrinfo_err_from_unix( getnameinfo( &unix_addr.addr, unix_addr_len, params->host, params->host_len,
968 params->serv, params->serv_len,
969 nameinfo_flags_to_unix( params->flags ) ) );
973 const unixlib_entry_t __wine_unix_call_funcs[] =
975 unix_getaddrinfo,
976 unix_gethostbyaddr,
977 unix_gethostbyname,
978 unix_gethostname,
979 unix_getnameinfo,
982 #ifdef _WIN64
984 typedef ULONG PTR32;
986 struct WS_addrinfo32
988 int ai_flags;
989 int ai_family;
990 int ai_socktype;
991 int ai_protocol;
992 PTR32 ai_addrlen;
993 PTR32 ai_canonname;
994 PTR32 ai_addr;
995 PTR32 ai_next;
998 struct WS_hostent32
1000 PTR32 h_name;
1001 PTR32 h_aliases;
1002 short h_addrtype;
1003 short h_length;
1004 PTR32 h_addr_list;
1007 static NTSTATUS put_addrinfo32( const struct WS_addrinfo *info, struct WS_addrinfo32 *info32,
1008 unsigned int *size )
1010 struct WS_addrinfo32 *dst = info32, *prev = NULL;
1011 const struct WS_addrinfo *src;
1012 unsigned int needed_size = 0;
1014 for (src = info; src != NULL; src = src->ai_next)
1016 needed_size += sizeof(struct WS_addrinfo32);
1017 if (src->ai_canonname) needed_size += strlen( src->ai_canonname ) + 1;
1018 needed_size += src->ai_addrlen;
1021 if (*size < needed_size)
1023 *size = needed_size;
1024 return ERROR_INSUFFICIENT_BUFFER;
1027 memset( info32, 0, needed_size );
1029 for (src = info; src != NULL; src = src->ai_next)
1031 char *next = (char *)(dst + 1);
1033 dst->ai_flags = src->ai_flags;
1034 dst->ai_family = src->ai_family;
1035 dst->ai_socktype = src->ai_socktype;
1036 dst->ai_protocol = src->ai_protocol;
1037 if (src->ai_canonname)
1039 dst->ai_canonname = PtrToUlong( next );
1040 strcpy( next, src->ai_canonname );
1041 next += strlen(next) + 1;
1043 dst->ai_addrlen = src->ai_addrlen;
1044 dst->ai_addr = PtrToUlong(next);
1045 memcpy( next, src->ai_addr, dst->ai_addrlen );
1046 next += dst->ai_addrlen;
1047 if (prev) prev->ai_next = PtrToUlong(dst);
1048 prev = dst;
1049 dst = (struct WS_addrinfo32 *)next;
1051 return STATUS_SUCCESS;
1054 static NTSTATUS put_hostent32( const struct WS_hostent *host, struct WS_hostent32 *host32,
1055 unsigned int *size )
1057 unsigned int needed_size = sizeof( struct WS_hostent32 ), alias_count = 0, addr_count = 0, i;
1058 char *p;
1059 ULONG *aliases, *addr_list;
1061 needed_size += strlen( host->h_name ) + 1;
1063 for (alias_count = 0; host->h_aliases[alias_count] != NULL; ++alias_count)
1064 needed_size += sizeof(ULONG) + strlen( host->h_aliases[alias_count] ) + 1;
1065 needed_size += sizeof(ULONG); /* null terminator */
1067 for (addr_count = 0; host->h_addr_list[addr_count] != NULL; ++addr_count)
1068 needed_size += sizeof(ULONG) + host->h_length;
1069 needed_size += sizeof(ULONG); /* null terminator */
1071 if (*size < needed_size)
1073 *size = needed_size;
1074 return ERROR_INSUFFICIENT_BUFFER;
1077 memset( host32, 0, needed_size );
1079 /* arrange the memory in the same order as windows >= XP */
1081 host32->h_addrtype = host->h_addrtype;
1082 host32->h_length = host->h_length;
1084 aliases = (ULONG *)(host32 + 1);
1085 addr_list = aliases + alias_count + 1;
1086 p = (char *)(addr_list + addr_count + 1);
1088 host32->h_aliases = PtrToUlong( aliases );
1089 host32->h_addr_list = PtrToUlong( addr_list );
1091 for (i = 0; i < addr_count; ++i)
1093 addr_list[i] = PtrToUlong( p );
1094 memcpy( p, host->h_addr_list[i], host->h_length );
1095 p += host->h_length;
1098 for (i = 0; i < alias_count; ++i)
1100 size_t len = strlen( host->h_aliases[i] ) + 1;
1102 aliases[i] = PtrToUlong( p );
1103 memcpy( p, host->h_aliases[i], len );
1104 p += len;
1107 host32->h_name = PtrToUlong( p );
1108 strcpy( p, host->h_name );
1109 return STATUS_SUCCESS;
1113 static NTSTATUS wow64_unix_getaddrinfo( void *args )
1115 struct
1117 PTR32 node;
1118 PTR32 service;
1119 PTR32 hints;
1120 PTR32 info;
1121 PTR32 size;
1122 } const *params32 = args;
1124 NTSTATUS status;
1125 struct WS_addrinfo hints;
1126 struct getaddrinfo_params params =
1128 ULongToPtr( params32->node ),
1129 ULongToPtr( params32->service ),
1130 NULL,
1131 NULL,
1132 ULongToPtr(params32->size)
1135 if (params32->hints)
1137 const struct WS_addrinfo32 *hints32 = ULongToPtr(params32->hints);
1138 hints.ai_flags = hints32->ai_flags;
1139 hints.ai_family = hints32->ai_family;
1140 hints.ai_socktype = hints32->ai_socktype;
1141 hints.ai_protocol = hints32->ai_protocol;
1142 params.hints = &hints;
1145 if (!(params.info = malloc( *params.size ))) return WSAENOBUFS;
1146 status = unix_getaddrinfo( &params );
1147 if (!status) put_addrinfo32( params.info, ULongToPtr(params32->info), ULongToPtr(params32->size) );
1148 free( params.info );
1149 return status;
1153 static NTSTATUS wow64_unix_gethostbyaddr( void *args )
1155 struct
1157 PTR32 addr;
1158 int len;
1159 int family;
1160 PTR32 host;
1161 PTR32 size;
1162 } const *params32 = args;
1164 NTSTATUS status;
1165 struct gethostbyaddr_params params =
1167 ULongToPtr( params32->addr ),
1168 params32->len,
1169 params32->family,
1170 NULL,
1171 ULongToPtr(params32->size)
1174 if (!(params.host = malloc( *params.size ))) return WSAENOBUFS;
1175 status = unix_gethostbyaddr( &params );
1176 if (!status)
1177 status = put_hostent32( params.host, ULongToPtr(params32->host), ULongToPtr(params32->size) );
1178 free( params.host );
1179 return status;
1183 static NTSTATUS wow64_unix_gethostbyname( void *args )
1185 struct
1187 PTR32 name;
1188 PTR32 host;
1189 PTR32 size;
1190 } const *params32 = args;
1192 NTSTATUS status;
1193 struct gethostbyname_params params =
1195 ULongToPtr( params32->name ),
1196 NULL,
1197 ULongToPtr(params32->size)
1200 if (!(params.host = malloc( *params.size ))) return WSAENOBUFS;
1201 status = unix_gethostbyname( &params );
1202 if (!status)
1203 status = put_hostent32( params.host, ULongToPtr(params32->host), ULongToPtr(params32->size) );
1204 free( params.host );
1205 return status;
1209 static NTSTATUS wow64_unix_gethostname( void *args )
1211 struct
1213 PTR32 name;
1214 unsigned int size;
1215 } const *params32 = args;
1217 struct gethostname_params params = { ULongToPtr(params32->name), params32->size };
1219 if (!unix_gethostname( &params )) return 0;
1220 return errno_from_unix( errno );
1224 static NTSTATUS wow64_unix_getnameinfo( void *args )
1226 struct
1228 PTR32 addr;
1229 int addr_len;
1230 PTR32 host;
1231 DWORD host_len;
1232 PTR32 serv;
1233 DWORD serv_len;
1234 unsigned int flags;
1235 } const *params32 = args;
1237 struct getnameinfo_params params =
1239 ULongToPtr( params32->addr ),
1240 params32->addr_len,
1241 ULongToPtr( params32->host ),
1242 params32->host_len,
1243 ULongToPtr( params32->serv ),
1244 params32->serv_len,
1245 params32->flags
1248 return unix_getnameinfo( &params );
1251 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
1253 wow64_unix_getaddrinfo,
1254 wow64_unix_gethostbyaddr,
1255 wow64_unix_gethostbyname,
1256 wow64_unix_gethostname,
1257 wow64_unix_getnameinfo,
1260 #endif /* _WIN64 */