sapi: Add SpMMAudioOut stub.
[wine.git] / dlls / ws2_32 / unixlib.c
blob4646e8ff26f034ab4036dcb1a6ae758ef3270b94
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);
105 WINE_DECLARE_DEBUG_CHANNEL(winediag);
107 #ifndef HAVE_LINUX_GETHOSTBYNAME_R_6
108 static pthread_mutex_t host_mutex = PTHREAD_MUTEX_INITIALIZER;
109 #endif
111 #define MAP(x) {WS_ ## x, x}
113 static const int addrinfo_flag_map[][2] =
115 MAP( AI_PASSIVE ),
116 MAP( AI_CANONNAME ),
117 MAP( AI_NUMERICHOST ),
118 #ifdef AI_NUMERICSERV
119 MAP( AI_NUMERICSERV ),
120 #endif
121 #ifdef AI_V4MAPPED
122 MAP( AI_V4MAPPED ),
123 #endif
124 MAP( AI_ALL ),
125 MAP( AI_ADDRCONFIG ),
128 static const int nameinfo_flag_map[][2] =
130 MAP( NI_DGRAM ),
131 MAP( NI_NAMEREQD ),
132 MAP( NI_NOFQDN ),
133 MAP( NI_NUMERICHOST ),
134 MAP( NI_NUMERICSERV ),
137 static const int family_map[][2] =
139 MAP( AF_UNSPEC ),
140 MAP( AF_INET ),
141 MAP( AF_INET6 ),
142 #ifdef AF_IPX
143 MAP( AF_IPX ),
144 #endif
145 #ifdef AF_IRDA
146 MAP( AF_IRDA ),
147 #endif
150 static const int socktype_map[][2] =
152 MAP( SOCK_STREAM ),
153 MAP( SOCK_DGRAM ),
154 MAP( SOCK_RAW ),
157 static const int ip_protocol_map[][2] =
159 MAP( IPPROTO_IP ),
160 MAP( IPPROTO_TCP ),
161 MAP( IPPROTO_UDP ),
162 MAP( IPPROTO_IPV6 ),
163 MAP( IPPROTO_ICMP ),
164 MAP( IPPROTO_IGMP ),
165 MAP( IPPROTO_RAW ),
166 {WS_IPPROTO_IPV4, IPPROTO_IPIP},
169 #undef MAP
171 static pthread_once_t hash_init_once = PTHREAD_ONCE_INIT;
172 static BYTE byte_hash[256];
174 static void init_hash(void)
176 unsigned i, index;
177 NTSTATUS status;
178 BYTE *buf, tmp;
179 ULONG buf_len;
181 for (i = 0; i < sizeof(byte_hash); ++i)
182 byte_hash[i] = i;
184 buf_len = sizeof(SYSTEM_INTERRUPT_INFORMATION) * NtCurrentTeb()->Peb->NumberOfProcessors;
185 if (!(buf = malloc( buf_len )))
187 ERR( "No memory.\n" );
188 return;
191 for (i = 0; i < sizeof(byte_hash) - 1; ++i)
193 if (!(i % buf_len) && (status = NtQuerySystemInformation( SystemInterruptInformation, buf,
194 buf_len, &buf_len )))
196 ERR( "Failed to get random bytes.\n" );
197 free( buf );
198 return;
200 index = i + buf[i % buf_len] % (sizeof(byte_hash) - i);
201 tmp = byte_hash[index];
202 byte_hash[index] = byte_hash[i];
203 byte_hash[i] = tmp;
205 free( buf );
208 static void hash_random( BYTE *d, const BYTE *s, unsigned int len )
210 unsigned int i;
212 for (i = 0; i < len; ++i)
213 d[i] = byte_hash[s[i]];
216 static int addrinfo_flags_from_unix( int flags )
218 int ws_flags = 0;
219 unsigned int i;
221 for (i = 0; i < ARRAY_SIZE(addrinfo_flag_map); ++i)
223 if (flags & addrinfo_flag_map[i][1])
225 ws_flags |= addrinfo_flag_map[i][0];
226 flags &= ~addrinfo_flag_map[i][1];
230 if (flags)
231 FIXME( "unhandled flags %#x\n", flags );
232 return ws_flags;
235 static int addrinfo_flags_to_unix( int flags )
237 int unix_flags = 0;
238 unsigned int i;
240 for (i = 0; i < ARRAY_SIZE(addrinfo_flag_map); ++i)
242 if (flags & addrinfo_flag_map[i][0])
244 unix_flags |= addrinfo_flag_map[i][1];
245 flags &= ~addrinfo_flag_map[i][0];
249 if (flags)
250 FIXME( "unhandled flags %#x\n", flags );
251 return unix_flags;
254 static int nameinfo_flags_to_unix( int flags )
256 int unix_flags = 0;
257 unsigned int i;
259 for (i = 0; i < ARRAY_SIZE(nameinfo_flag_map); ++i)
261 if (flags & nameinfo_flag_map[i][0])
263 unix_flags |= nameinfo_flag_map[i][1];
264 flags &= ~nameinfo_flag_map[i][0];
268 if (flags)
269 FIXME( "unhandled flags %#x\n", flags );
270 return unix_flags;
273 static int family_from_unix( int family )
275 unsigned int i;
277 for (i = 0; i < ARRAY_SIZE(family_map); ++i)
279 if (family == family_map[i][1])
280 return family_map[i][0];
283 FIXME( "unhandled family %u\n", family );
284 return -1;
287 static int family_to_unix( int family )
289 unsigned int i;
291 for (i = 0; i < ARRAY_SIZE(family_map); ++i)
293 if (family == family_map[i][0])
294 return family_map[i][1];
297 FIXME( "unhandled family %u\n", family );
298 return -1;
301 static int socktype_from_unix( int type )
303 unsigned int i;
305 for (i = 0; i < ARRAY_SIZE(socktype_map); ++i)
307 if (type == socktype_map[i][1])
308 return socktype_map[i][0];
311 FIXME( "unhandled type %u\n", type );
312 return -1;
315 static int socktype_to_unix( int type )
317 unsigned int i;
319 for (i = 0; i < ARRAY_SIZE(socktype_map); ++i)
321 if (type == socktype_map[i][0])
322 return socktype_map[i][1];
325 FIXME( "unhandled type %u\n", type );
326 return -1;
329 static int protocol_from_unix( int protocol )
331 unsigned int i;
333 for (i = 0; i < ARRAY_SIZE(ip_protocol_map); ++i)
335 if (protocol == ip_protocol_map[i][1])
336 return ip_protocol_map[i][0];
339 if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255)
340 return protocol;
342 FIXME( "unhandled protocol %u\n", protocol );
343 return -1;
346 static int protocol_to_unix( int protocol )
348 unsigned int i;
350 for (i = 0; i < ARRAY_SIZE(ip_protocol_map); ++i)
352 if (protocol == ip_protocol_map[i][0])
353 return ip_protocol_map[i][1];
356 if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255)
357 return protocol;
359 FIXME( "unhandled protocol %u\n", protocol );
360 return -1;
363 static unsigned int errno_from_unix( int err )
365 switch (err)
367 case EINTR: return WSAEINTR;
368 case EBADF: return WSAEBADF;
369 case EPERM:
370 case EACCES: return WSAEACCES;
371 case EFAULT: return WSAEFAULT;
372 case EINVAL: return WSAEINVAL;
373 case EMFILE: return WSAEMFILE;
374 case EINPROGRESS:
375 case EWOULDBLOCK: return WSAEWOULDBLOCK;
376 case EALREADY: return WSAEALREADY;
377 case ENOTSOCK: return WSAENOTSOCK;
378 case EDESTADDRREQ: return WSAEDESTADDRREQ;
379 case EMSGSIZE: return WSAEMSGSIZE;
380 case EPROTOTYPE: return WSAEPROTOTYPE;
381 case ENOPROTOOPT: return WSAENOPROTOOPT;
382 case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
383 case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
384 case EOPNOTSUPP: return WSAEOPNOTSUPP;
385 case EPFNOSUPPORT: return WSAEPFNOSUPPORT;
386 case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
387 case EADDRINUSE: return WSAEADDRINUSE;
388 case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
389 case ENETDOWN: return WSAENETDOWN;
390 case ENETUNREACH: return WSAENETUNREACH;
391 case ENETRESET: return WSAENETRESET;
392 case ECONNABORTED: return WSAECONNABORTED;
393 case EPIPE:
394 case ECONNRESET: return WSAECONNRESET;
395 case ENOBUFS: return WSAENOBUFS;
396 case EISCONN: return WSAEISCONN;
397 case ENOTCONN: return WSAENOTCONN;
398 case ESHUTDOWN: return WSAESHUTDOWN;
399 case ETOOMANYREFS: return WSAETOOMANYREFS;
400 case ETIMEDOUT: return WSAETIMEDOUT;
401 case ECONNREFUSED: return WSAECONNREFUSED;
402 case ELOOP: return WSAELOOP;
403 case ENAMETOOLONG: return WSAENAMETOOLONG;
404 case EHOSTDOWN: return WSAEHOSTDOWN;
405 case EHOSTUNREACH: return WSAEHOSTUNREACH;
406 case ENOTEMPTY: return WSAENOTEMPTY;
407 #ifdef EPROCLIM
408 case EPROCLIM: return WSAEPROCLIM;
409 #endif
410 #ifdef EUSERS
411 case EUSERS: return WSAEUSERS;
412 #endif
413 #ifdef EDQUOT
414 case EDQUOT: return WSAEDQUOT;
415 #endif
416 #ifdef ESTALE
417 case ESTALE: return WSAESTALE;
418 #endif
419 #ifdef EREMOTE
420 case EREMOTE: return WSAEREMOTE;
421 #endif
422 default:
423 FIXME( "unknown error: %s\n", strerror( err ) );
424 return WSAEFAULT;
428 static UINT host_errno_from_unix( int err )
430 WARN( "%d\n", err );
432 switch (err)
434 case HOST_NOT_FOUND: return WSAHOST_NOT_FOUND;
435 case TRY_AGAIN: return WSATRY_AGAIN;
436 case NO_RECOVERY: return WSANO_RECOVERY;
437 case NO_DATA: return WSANO_DATA;
438 case ENOBUFS: return WSAENOBUFS;
439 case 0: return 0;
440 default:
441 WARN( "Unknown h_errno %d!\n", err );
442 return WSAEOPNOTSUPP;
446 static int addrinfo_err_from_unix( int err )
448 switch (err)
450 case 0: return 0;
451 case EAI_AGAIN: return WS_EAI_AGAIN;
452 case EAI_BADFLAGS: return WS_EAI_BADFLAGS;
453 case EAI_FAIL: return WS_EAI_FAIL;
454 case EAI_FAMILY: return WS_EAI_FAMILY;
455 case EAI_MEMORY: return WS_EAI_MEMORY;
456 /* EAI_NODATA is deprecated, but still used by Windows and Linux. We map
457 * the newer EAI_NONAME to EAI_NODATA for now until Windows changes too. */
458 #ifdef EAI_NODATA
459 case EAI_NODATA: return WS_EAI_NODATA;
460 #endif
461 #ifdef EAI_NONAME
462 case EAI_NONAME: return WS_EAI_NODATA;
463 #endif
464 case EAI_SERVICE: return WS_EAI_SERVICE;
465 case EAI_SOCKTYPE: return WS_EAI_SOCKTYPE;
466 case EAI_SYSTEM:
467 if (errno == EBUSY) ERR_(winediag)("getaddrinfo() returned EBUSY. You may be missing a libnss plugin\n");
468 /* some broken versions of glibc return EAI_SYSTEM and set errno to
469 * 0 instead of returning EAI_NONAME */
470 return errno ? errno_from_unix( errno ) : WS_EAI_NONAME;
472 default:
473 FIXME( "unhandled error %d\n", err );
474 return err;
478 union unix_sockaddr
480 struct sockaddr addr;
481 struct sockaddr_in in;
482 struct sockaddr_in6 in6;
483 #ifdef HAS_IPX
484 struct sockaddr_ipx ipx;
485 #endif
486 #ifdef HAS_IRDA
487 struct sockaddr_irda irda;
488 #endif
491 /* different from the version in ntdll and server; it does not return failure if
492 * given a short buffer */
493 static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_sockaddr *wsaddr, socklen_t wsaddrlen )
495 memset( wsaddr, 0, wsaddrlen );
497 switch (uaddr->addr.sa_family)
499 case AF_INET:
501 struct WS_sockaddr_in win = {0};
503 if (wsaddrlen >= sizeof(win))
505 win.sin_family = WS_AF_INET;
506 win.sin_port = uaddr->in.sin_port;
507 memcpy( &win.sin_addr, &uaddr->in.sin_addr, sizeof(win.sin_addr) );
508 memcpy( wsaddr, &win, sizeof(win) );
510 return sizeof(win);
513 case AF_INET6:
515 struct WS_sockaddr_in6 win = {0};
517 if (wsaddrlen >= sizeof(win))
519 win.sin6_family = WS_AF_INET6;
520 win.sin6_port = uaddr->in6.sin6_port;
521 win.sin6_flowinfo = uaddr->in6.sin6_flowinfo;
522 memcpy( &win.sin6_addr, &uaddr->in6.sin6_addr, sizeof(win.sin6_addr) );
523 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
524 win.sin6_scope_id = uaddr->in6.sin6_scope_id;
525 #endif
526 memcpy( wsaddr, &win, sizeof(win) );
528 return sizeof(win);
531 #ifdef HAS_IPX
532 case AF_IPX:
534 struct WS_sockaddr_ipx win = {0};
536 if (wsaddrlen >= sizeof(win))
538 win.sa_family = WS_AF_IPX;
539 memcpy( win.sa_netnum, &uaddr->ipx.sipx_network, sizeof(win.sa_netnum) );
540 memcpy( win.sa_nodenum, &uaddr->ipx.sipx_node, sizeof(win.sa_nodenum) );
541 win.sa_socket = uaddr->ipx.sipx_port;
542 memcpy( wsaddr, &win, sizeof(win) );
544 return sizeof(win);
546 #endif
548 #ifdef HAS_IRDA
549 case AF_IRDA:
551 SOCKADDR_IRDA win;
553 if (wsaddrlen >= sizeof(win))
555 win.irdaAddressFamily = WS_AF_IRDA;
556 memcpy( win.irdaDeviceID, &uaddr->irda.sir_addr, sizeof(win.irdaDeviceID) );
557 if (uaddr->irda.sir_lsap_sel != LSAP_ANY)
558 snprintf( win.irdaServiceName, sizeof(win.irdaServiceName), "LSAP-SEL%u", uaddr->irda.sir_lsap_sel );
559 else
560 memcpy( win.irdaServiceName, uaddr->irda.sir_name, sizeof(win.irdaServiceName) );
561 memcpy( wsaddr, &win, sizeof(win) );
563 return sizeof(win);
565 #endif
567 case AF_UNSPEC:
568 return 0;
570 default:
571 FIXME( "unknown address family %d\n", uaddr->addr.sa_family );
572 return 0;
576 static socklen_t sockaddr_to_unix( const struct WS_sockaddr *wsaddr, int wsaddrlen, union unix_sockaddr *uaddr )
578 memset( uaddr, 0, sizeof(*uaddr) );
580 switch (wsaddr->sa_family)
582 case WS_AF_INET:
584 struct WS_sockaddr_in win = {0};
586 if (wsaddrlen < sizeof(win)) return 0;
587 memcpy( &win, wsaddr, sizeof(win) );
588 uaddr->in.sin_family = AF_INET;
589 uaddr->in.sin_port = win.sin_port;
590 memcpy( &uaddr->in.sin_addr, &win.sin_addr, sizeof(win.sin_addr) );
591 return sizeof(uaddr->in);
594 case WS_AF_INET6:
596 struct WS_sockaddr_in6 win = {0};
598 if (wsaddrlen < sizeof(win)) return 0;
599 memcpy( &win, wsaddr, sizeof(win) );
600 uaddr->in6.sin6_family = AF_INET6;
601 uaddr->in6.sin6_port = win.sin6_port;
602 uaddr->in6.sin6_flowinfo = win.sin6_flowinfo;
603 memcpy( &uaddr->in6.sin6_addr, &win.sin6_addr, sizeof(win.sin6_addr) );
604 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
605 uaddr->in6.sin6_scope_id = win.sin6_scope_id;
606 #endif
607 return sizeof(uaddr->in6);
610 #ifdef HAS_IPX
611 case WS_AF_IPX:
613 struct WS_sockaddr_ipx win = {0};
615 if (wsaddrlen < sizeof(win)) return 0;
616 memcpy( &win, wsaddr, sizeof(win) );
617 uaddr->ipx.sipx_family = AF_IPX;
618 memcpy( &uaddr->ipx.sipx_network, win.sa_netnum, sizeof(win.sa_netnum) );
619 memcpy( &uaddr->ipx.sipx_node, win.sa_nodenum, sizeof(win.sa_nodenum) );
620 uaddr->ipx.sipx_port = win.sa_socket;
621 return sizeof(uaddr->ipx);
623 #endif
625 #ifdef HAS_IRDA
626 case WS_AF_IRDA:
628 SOCKADDR_IRDA win = {0};
629 unsigned int lsap_sel;
631 if (wsaddrlen < sizeof(win)) return 0;
632 memcpy( &win, wsaddr, sizeof(win) );
633 uaddr->irda.sir_family = AF_IRDA;
634 if (sscanf( win.irdaServiceName, "LSAP-SEL%u", &lsap_sel ) == 1)
635 uaddr->irda.sir_lsap_sel = lsap_sel;
636 else
638 uaddr->irda.sir_lsap_sel = LSAP_ANY;
639 memcpy( uaddr->irda.sir_name, win.irdaServiceName, sizeof(win.irdaServiceName) );
641 memcpy( &uaddr->irda.sir_addr, win.irdaDeviceID, sizeof(win.irdaDeviceID) );
642 return sizeof(uaddr->irda);
644 #endif
646 case WS_AF_UNSPEC:
647 switch (wsaddrlen)
649 default: /* likely an ipv4 address */
650 case sizeof(struct WS_sockaddr_in):
651 return sizeof(uaddr->in);
653 #ifdef HAS_IPX
654 case sizeof(struct WS_sockaddr_ipx):
655 return sizeof(uaddr->ipx);
656 #endif
658 #ifdef HAS_IRDA
659 case sizeof(SOCKADDR_IRDA):
660 return sizeof(uaddr->irda);
661 #endif
663 case sizeof(struct WS_sockaddr_in6):
664 return sizeof(uaddr->in6);
667 default:
668 FIXME( "unknown address family %u\n", wsaddr->sa_family );
669 return 0;
673 static BOOL addrinfo_in_list( const struct WS_addrinfo *list, const struct WS_addrinfo *ai )
675 const struct WS_addrinfo *cursor = list;
676 while (cursor)
678 if (ai->ai_flags == cursor->ai_flags &&
679 ai->ai_family == cursor->ai_family &&
680 ai->ai_socktype == cursor->ai_socktype &&
681 ai->ai_protocol == cursor->ai_protocol &&
682 ai->ai_addrlen == cursor->ai_addrlen &&
683 !memcmp( ai->ai_addr, cursor->ai_addr, ai->ai_addrlen ) &&
684 ((ai->ai_canonname && cursor->ai_canonname && !strcmp( ai->ai_canonname, cursor->ai_canonname ))
685 || (!ai->ai_canonname && !cursor->ai_canonname)))
687 return TRUE;
689 cursor = cursor->ai_next;
691 return FALSE;
694 static NTSTATUS unix_getaddrinfo( void *args )
696 #ifdef HAVE_GETADDRINFO
697 struct getaddrinfo_params *params = args;
698 const char *service = params->service;
699 const struct WS_addrinfo *hints = params->hints;
700 struct addrinfo unix_hints = {0};
701 struct addrinfo *unix_info, *src;
702 struct WS_addrinfo *dst, *prev = NULL;
703 unsigned int needed_size = 0;
704 int ret;
706 /* servname tweak required by OSX and BSD kernels */
707 if (service && !service[0]) service = "0";
709 if (hints)
711 unix_hints.ai_flags = addrinfo_flags_to_unix( hints->ai_flags );
713 if (hints->ai_family)
714 unix_hints.ai_family = family_to_unix( hints->ai_family );
716 if (hints->ai_socktype)
718 if ((unix_hints.ai_socktype = socktype_to_unix( hints->ai_socktype )) < 0)
719 return WSAESOCKTNOSUPPORT;
722 if (hints->ai_protocol)
723 unix_hints.ai_protocol = max( protocol_to_unix( hints->ai_protocol ), 0 );
725 /* Windows allows some invalid combinations */
726 if (unix_hints.ai_protocol == IPPROTO_TCP
727 && unix_hints.ai_socktype != SOCK_STREAM
728 && unix_hints.ai_socktype != SOCK_SEQPACKET)
730 WARN( "ignoring invalid type %u for TCP\n", unix_hints.ai_socktype );
731 unix_hints.ai_socktype = 0;
733 else if (unix_hints.ai_protocol == IPPROTO_UDP && unix_hints.ai_socktype != SOCK_DGRAM)
735 WARN( "ignoring invalid type %u for UDP\n", unix_hints.ai_socktype );
736 unix_hints.ai_socktype = 0;
738 else if (unix_hints.ai_protocol >= WS_NSPROTO_IPX && unix_hints.ai_protocol <= WS_NSPROTO_IPX + 255
739 && unix_hints.ai_socktype != SOCK_DGRAM)
741 WARN( "ignoring invalid type %u for IPX\n", unix_hints.ai_socktype );
742 unix_hints.ai_socktype = 0;
744 else if (unix_hints.ai_protocol == IPPROTO_IPV6)
746 WARN( "ignoring protocol IPv6\n" );
747 unix_hints.ai_protocol = 0;
751 ret = getaddrinfo( params->node, service, hints ? &unix_hints : NULL, &unix_info );
752 if (ret)
753 return addrinfo_err_from_unix( ret );
755 for (src = unix_info; src != NULL; src = src->ai_next)
757 needed_size += sizeof(struct WS_addrinfo);
758 if (src->ai_canonname)
759 needed_size += strlen( src->ai_canonname ) + 1;
760 needed_size += sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, NULL, 0 );
763 if (*params->size < needed_size)
765 *params->size = needed_size;
766 freeaddrinfo( unix_info );
767 return ERROR_INSUFFICIENT_BUFFER;
770 dst = params->info;
772 memset( params->info, 0, needed_size );
774 for (src = unix_info; src != NULL; src = src->ai_next)
776 void *next = dst + 1;
778 dst->ai_flags = addrinfo_flags_from_unix( src->ai_flags );
779 dst->ai_family = family_from_unix( src->ai_family );
780 if (hints)
782 dst->ai_socktype = hints->ai_socktype;
783 dst->ai_protocol = hints->ai_protocol;
785 else
787 dst->ai_socktype = socktype_from_unix( src->ai_socktype );
788 dst->ai_protocol = protocol_from_unix( src->ai_protocol );
790 if (src->ai_canonname)
792 size_t len = strlen( src->ai_canonname ) + 1;
794 dst->ai_canonname = next;
795 memcpy( dst->ai_canonname, src->ai_canonname, len );
796 next = dst->ai_canonname + len;
799 dst->ai_addrlen = sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, NULL, 0 );
800 dst->ai_addr = next;
801 sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, dst->ai_addr, dst->ai_addrlen );
802 dst->ai_next = NULL;
803 next = (char *)dst->ai_addr + dst->ai_addrlen;
805 if (dst == params->info || !addrinfo_in_list( params->info, dst ))
807 if (prev)
808 prev->ai_next = dst;
809 prev = dst;
810 dst = next;
814 freeaddrinfo( unix_info );
815 return 0;
816 #else
817 FIXME( "getaddrinfo() not found during build time\n" );
818 return WS_EAI_FAIL;
819 #endif
823 static int hostent_from_unix( const struct hostent *unix_host, struct WS_hostent *host, unsigned int *const size )
825 unsigned int needed_size = sizeof( struct WS_hostent ), alias_count = 0, addr_count = 0, i;
826 char *p;
828 needed_size += strlen( unix_host->h_name ) + 1;
830 for (alias_count = 0; unix_host->h_aliases[alias_count] != NULL; ++alias_count)
831 needed_size += sizeof(char *) + strlen( unix_host->h_aliases[alias_count] ) + 1;
832 needed_size += sizeof(char *); /* null terminator */
834 for (addr_count = 0; unix_host->h_addr_list[addr_count] != NULL; ++addr_count)
835 needed_size += sizeof(char *) + unix_host->h_length;
836 needed_size += sizeof(char *); /* null terminator */
838 if (*size < needed_size)
840 *size = needed_size;
841 return ERROR_INSUFFICIENT_BUFFER;
844 memset( host, 0, needed_size );
846 /* arrange the memory in the same order as windows >= XP */
848 host->h_addrtype = family_from_unix( unix_host->h_addrtype );
849 host->h_length = unix_host->h_length;
851 p = (char *)(host + 1);
852 host->h_aliases = (char **)p;
853 p += (alias_count + 1) * sizeof(char *);
854 host->h_addr_list = (char **)p;
855 p += (addr_count + 1) * sizeof(char *);
857 for (i = 0; i < addr_count; ++i)
859 host->h_addr_list[i] = p;
860 memcpy( host->h_addr_list[i], unix_host->h_addr_list[i], unix_host->h_length );
861 p += unix_host->h_length;
864 for (i = 0; i < alias_count; ++i)
866 size_t len = strlen( unix_host->h_aliases[i] ) + 1;
868 host->h_aliases[i] = p;
869 memcpy( host->h_aliases[i], unix_host->h_aliases[i], len );
870 p += len;
873 host->h_name = p;
874 strcpy( host->h_name, unix_host->h_name );
876 return 0;
880 static NTSTATUS unix_gethostbyaddr( void *args )
882 struct gethostbyaddr_params *params = args;
883 const void *addr = params->addr;
884 const struct in_addr loopback = { htonl( INADDR_LOOPBACK ) };
885 int unix_family = family_to_unix( params->family );
886 struct hostent *unix_host;
887 int ret;
889 if (params->family == WS_AF_INET && params->len == 4 && !memcmp( addr, magic_loopback_addr, 4 ))
890 addr = &loopback;
892 #ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
894 char *unix_buffer, *new_buffer;
895 struct hostent stack_host;
896 int unix_size = 1024;
897 int locerr;
899 if (!(unix_buffer = malloc( unix_size )))
900 return WSAENOBUFS;
902 while (gethostbyaddr_r( addr, params->len, unix_family, &stack_host, unix_buffer,
903 unix_size, &unix_host, &locerr ) == ERANGE)
905 unix_size *= 2;
906 if (!(new_buffer = realloc( unix_buffer, unix_size )))
908 free( unix_buffer );
909 return WSAENOBUFS;
911 unix_buffer = new_buffer;
914 if (!unix_host)
915 ret = (locerr < 0 ? errno_from_unix( errno ) : host_errno_from_unix( locerr ));
916 else
917 ret = hostent_from_unix( unix_host, params->host, params->size );
919 free( unix_buffer );
920 return ret;
922 #else
923 pthread_mutex_lock( &host_mutex );
925 if (!(unix_host = gethostbyaddr( addr, params->len, unix_family )))
927 ret = (h_errno < 0 ? errno_from_unix( errno ) : host_errno_from_unix( h_errno ));
928 pthread_mutex_unlock( &host_mutex );
929 return ret;
932 ret = hostent_from_unix( unix_host, params->host, params->size );
934 pthread_mutex_unlock( &host_mutex );
935 return ret;
936 #endif
939 static int compare_addrs_hashed( const void *a1, const void *a2, int addr_len )
941 char a1_hashed[16], a2_hashed[16];
943 assert( addr_len <= sizeof(a1_hashed) );
944 hash_random( (BYTE *)a1_hashed, a1, addr_len );
945 hash_random( (BYTE *)a2_hashed, a2, addr_len );
946 return memcmp( a1_hashed, a2_hashed, addr_len );
949 static void sort_addrs_hashed( struct hostent *host )
951 /* On Unix gethostbyname() may return IP addresses in random order on each call. On Windows the order of
952 * IP addresses is not determined as well but it is the same on consequent calls (changes after network
953 * resets and probably DNS timeout expiration).
954 * Life is Strange Remastered depends on gethostbyname() returning IP addresses in the same order to reuse
955 * the established TLS connection and avoid timeouts that happen in game when establishing multiple extra TLS
956 * connections.
957 * Just sorting the addresses would break server load balancing provided by gethostbyname(), so randomize the
958 * sort once per process. */
959 unsigned int i, j;
960 char *tmp;
962 pthread_once( &hash_init_once, init_hash );
964 for (i = 0; host->h_addr_list[i]; ++i)
966 for (j = i + 1; host->h_addr_list[j]; ++j)
968 if (compare_addrs_hashed( host->h_addr_list[j], host->h_addr_list[i], host->h_length ) < 0)
970 tmp = host->h_addr_list[j];
971 host->h_addr_list[j] = host->h_addr_list[i];
972 host->h_addr_list[i] = tmp;
978 #ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
979 static NTSTATUS unix_gethostbyname( void *args )
981 struct gethostbyname_params *params = args;
982 struct hostent stack_host, *unix_host;
983 char *unix_buffer, *new_buffer;
984 int unix_size = 1024;
985 int locerr;
986 int ret;
988 if (!(unix_buffer = malloc( unix_size )))
989 return WSAENOBUFS;
991 while (gethostbyname_r( params->name, &stack_host, unix_buffer, unix_size, &unix_host, &locerr ) == ERANGE)
993 unix_size *= 2;
994 if (!(new_buffer = realloc( unix_buffer, unix_size )))
996 free( unix_buffer );
997 return WSAENOBUFS;
999 unix_buffer = new_buffer;
1002 if (!unix_host)
1004 ret = (locerr < 0 ? errno_from_unix( errno ) : host_errno_from_unix( locerr ));
1006 else
1008 sort_addrs_hashed( unix_host );
1009 ret = hostent_from_unix( unix_host, params->host, params->size );
1012 free( unix_buffer );
1013 return ret;
1015 #else
1016 static NTSTATUS unix_gethostbyname( void *args )
1018 struct gethostbyname_params *params = args;
1019 struct hostent *unix_host;
1020 int ret;
1022 pthread_mutex_lock( &host_mutex );
1024 if (!(unix_host = gethostbyname( params->name )))
1026 ret = (h_errno < 0 ? errno_from_unix( errno ) : host_errno_from_unix( h_errno ));
1027 pthread_mutex_unlock( &host_mutex );
1028 return ret;
1031 sort_addrs_hashed( unix_host );
1032 ret = hostent_from_unix( unix_host, params->host, params->size );
1034 pthread_mutex_unlock( &host_mutex );
1035 return ret;
1037 #endif
1040 static NTSTATUS unix_gethostname( void *args )
1042 struct gethostname_params *params = args;
1044 if (!gethostname( params->name, params->size ))
1045 return 0;
1046 return errno_from_unix( errno );
1050 static NTSTATUS unix_getnameinfo( void *args )
1052 struct getnameinfo_params *params = args;
1053 union unix_sockaddr unix_addr;
1054 socklen_t unix_addr_len;
1056 unix_addr_len = sockaddr_to_unix( params->addr, params->addr_len, &unix_addr );
1058 return addrinfo_err_from_unix( getnameinfo( &unix_addr.addr, unix_addr_len, params->host, params->host_len,
1059 params->serv, params->serv_len,
1060 nameinfo_flags_to_unix( params->flags ) ) );
1064 const unixlib_entry_t __wine_unix_call_funcs[] =
1066 unix_getaddrinfo,
1067 unix_gethostbyaddr,
1068 unix_gethostbyname,
1069 unix_gethostname,
1070 unix_getnameinfo,
1073 #ifdef _WIN64
1075 typedef ULONG PTR32;
1077 struct WS_addrinfo32
1079 int ai_flags;
1080 int ai_family;
1081 int ai_socktype;
1082 int ai_protocol;
1083 PTR32 ai_addrlen;
1084 PTR32 ai_canonname;
1085 PTR32 ai_addr;
1086 PTR32 ai_next;
1089 struct WS_hostent32
1091 PTR32 h_name;
1092 PTR32 h_aliases;
1093 short h_addrtype;
1094 short h_length;
1095 PTR32 h_addr_list;
1098 static NTSTATUS put_addrinfo32( const struct WS_addrinfo *info, struct WS_addrinfo32 *info32,
1099 unsigned int *size )
1101 struct WS_addrinfo32 *dst = info32, *prev = NULL;
1102 const struct WS_addrinfo *src;
1103 unsigned int needed_size = 0;
1105 for (src = info; src != NULL; src = src->ai_next)
1107 needed_size += sizeof(struct WS_addrinfo32);
1108 if (src->ai_canonname) needed_size += strlen( src->ai_canonname ) + 1;
1109 needed_size += src->ai_addrlen;
1112 if (*size < needed_size)
1114 *size = needed_size;
1115 return ERROR_INSUFFICIENT_BUFFER;
1118 memset( info32, 0, needed_size );
1120 for (src = info; src != NULL; src = src->ai_next)
1122 char *next = (char *)(dst + 1);
1124 dst->ai_flags = src->ai_flags;
1125 dst->ai_family = src->ai_family;
1126 dst->ai_socktype = src->ai_socktype;
1127 dst->ai_protocol = src->ai_protocol;
1128 if (src->ai_canonname)
1130 dst->ai_canonname = PtrToUlong( next );
1131 strcpy( next, src->ai_canonname );
1132 next += strlen(next) + 1;
1134 dst->ai_addrlen = src->ai_addrlen;
1135 dst->ai_addr = PtrToUlong(next);
1136 memcpy( next, src->ai_addr, dst->ai_addrlen );
1137 next += dst->ai_addrlen;
1138 if (prev) prev->ai_next = PtrToUlong(dst);
1139 prev = dst;
1140 dst = (struct WS_addrinfo32 *)next;
1142 return STATUS_SUCCESS;
1145 static NTSTATUS put_hostent32( const struct WS_hostent *host, struct WS_hostent32 *host32,
1146 unsigned int *size )
1148 unsigned int needed_size = sizeof( struct WS_hostent32 ), alias_count = 0, addr_count = 0, i;
1149 char *p;
1150 ULONG *aliases, *addr_list;
1152 needed_size += strlen( host->h_name ) + 1;
1154 for (alias_count = 0; host->h_aliases[alias_count] != NULL; ++alias_count)
1155 needed_size += sizeof(ULONG) + strlen( host->h_aliases[alias_count] ) + 1;
1156 needed_size += sizeof(ULONG); /* null terminator */
1158 for (addr_count = 0; host->h_addr_list[addr_count] != NULL; ++addr_count)
1159 needed_size += sizeof(ULONG) + host->h_length;
1160 needed_size += sizeof(ULONG); /* null terminator */
1162 if (*size < needed_size)
1164 *size = needed_size;
1165 return ERROR_INSUFFICIENT_BUFFER;
1168 memset( host32, 0, needed_size );
1170 /* arrange the memory in the same order as windows >= XP */
1172 host32->h_addrtype = host->h_addrtype;
1173 host32->h_length = host->h_length;
1175 aliases = (ULONG *)(host32 + 1);
1176 addr_list = aliases + alias_count + 1;
1177 p = (char *)(addr_list + addr_count + 1);
1179 host32->h_aliases = PtrToUlong( aliases );
1180 host32->h_addr_list = PtrToUlong( addr_list );
1182 for (i = 0; i < addr_count; ++i)
1184 addr_list[i] = PtrToUlong( p );
1185 memcpy( p, host->h_addr_list[i], host->h_length );
1186 p += host->h_length;
1189 for (i = 0; i < alias_count; ++i)
1191 size_t len = strlen( host->h_aliases[i] ) + 1;
1193 aliases[i] = PtrToUlong( p );
1194 memcpy( p, host->h_aliases[i], len );
1195 p += len;
1198 host32->h_name = PtrToUlong( p );
1199 strcpy( p, host->h_name );
1200 return STATUS_SUCCESS;
1204 static NTSTATUS wow64_unix_getaddrinfo( void *args )
1206 struct
1208 PTR32 node;
1209 PTR32 service;
1210 PTR32 hints;
1211 PTR32 info;
1212 PTR32 size;
1213 } const *params32 = args;
1215 NTSTATUS status;
1216 struct WS_addrinfo hints;
1217 struct getaddrinfo_params params =
1219 ULongToPtr( params32->node ),
1220 ULongToPtr( params32->service ),
1221 NULL,
1222 NULL,
1223 ULongToPtr(params32->size)
1226 if (params32->hints)
1228 const struct WS_addrinfo32 *hints32 = ULongToPtr(params32->hints);
1229 hints.ai_flags = hints32->ai_flags;
1230 hints.ai_family = hints32->ai_family;
1231 hints.ai_socktype = hints32->ai_socktype;
1232 hints.ai_protocol = hints32->ai_protocol;
1233 params.hints = &hints;
1236 if (!(params.info = malloc( *params.size ))) return WSAENOBUFS;
1237 status = unix_getaddrinfo( &params );
1238 if (!status) put_addrinfo32( params.info, ULongToPtr(params32->info), ULongToPtr(params32->size) );
1239 free( params.info );
1240 return status;
1244 static NTSTATUS wow64_unix_gethostbyaddr( void *args )
1246 struct
1248 PTR32 addr;
1249 int len;
1250 int family;
1251 PTR32 host;
1252 PTR32 size;
1253 } const *params32 = args;
1255 NTSTATUS status;
1256 struct gethostbyaddr_params params =
1258 ULongToPtr( params32->addr ),
1259 params32->len,
1260 params32->family,
1261 NULL,
1262 ULongToPtr(params32->size)
1265 if (!(params.host = malloc( *params.size ))) return WSAENOBUFS;
1266 status = unix_gethostbyaddr( &params );
1267 if (!status)
1268 status = put_hostent32( params.host, ULongToPtr(params32->host), ULongToPtr(params32->size) );
1269 free( params.host );
1270 return status;
1274 static NTSTATUS wow64_unix_gethostbyname( void *args )
1276 struct
1278 PTR32 name;
1279 PTR32 host;
1280 PTR32 size;
1281 } const *params32 = args;
1283 NTSTATUS status;
1284 struct gethostbyname_params params =
1286 ULongToPtr( params32->name ),
1287 NULL,
1288 ULongToPtr(params32->size)
1291 if (!(params.host = malloc( *params.size ))) return WSAENOBUFS;
1292 status = unix_gethostbyname( &params );
1293 if (!status)
1294 status = put_hostent32( params.host, ULongToPtr(params32->host), ULongToPtr(params32->size) );
1295 free( params.host );
1296 return status;
1300 static NTSTATUS wow64_unix_gethostname( void *args )
1302 struct
1304 PTR32 name;
1305 unsigned int size;
1306 } const *params32 = args;
1308 struct gethostname_params params = { ULongToPtr(params32->name), params32->size };
1310 if (!unix_gethostname( &params )) return 0;
1311 return errno_from_unix( errno );
1315 static NTSTATUS wow64_unix_getnameinfo( void *args )
1317 struct
1319 PTR32 addr;
1320 int addr_len;
1321 PTR32 host;
1322 DWORD host_len;
1323 PTR32 serv;
1324 DWORD serv_len;
1325 unsigned int flags;
1326 } const *params32 = args;
1328 struct getnameinfo_params params =
1330 ULongToPtr( params32->addr ),
1331 params32->addr_len,
1332 ULongToPtr( params32->host ),
1333 params32->host_len,
1334 ULongToPtr( params32->serv ),
1335 params32->serv_len,
1336 params32->flags
1339 return unix_getnameinfo( &params );
1342 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
1344 wow64_unix_getaddrinfo,
1345 wow64_unix_gethostbyaddr,
1346 wow64_unix_gethostbyname,
1347 wow64_unix_gethostname,
1348 wow64_unix_getnameinfo,
1351 #endif /* _WIN64 */