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
34 #include <sys/types.h>
35 #include <sys/socket.h>
40 #ifdef HAVE_SYS_PARAM_H
41 # include <sys/param.h>
43 #ifdef HAVE_SYS_SOCKIO_H
44 # include <sys/sockio.h>
46 #ifdef HAVE_NETINET_IN_H
47 # include <netinet/in.h>
49 #ifdef HAVE_NETINET_TCP_H
50 # include <netinet/tcp.h>
52 #ifdef HAVE_ARPA_INET_H
53 # include <arpa/inet.h>
56 # define if_indextoname unix_if_indextoname
57 # define if_nametoindex unix_if_nametoindex
59 # undef if_indextoname
60 # undef if_nametoindex
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>
73 # ifdef HAVE_LINUX_TYPES_H
74 # include <linux/types.h>
76 # include <linux/ipx.h>
78 #if defined(SOL_IPX) || defined(SO_DEFAULT_HEADERS)
82 #ifdef HAVE_LINUX_IRDA_H
83 # ifdef HAVE_LINUX_TYPES_H
84 # include <linux/types.h>
86 # include <linux/irda.h>
91 #define WIN32_NO_STATUS
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
;
111 #define MAP(x) {WS_ ## x, x}
113 static const int addrinfo_flag_map
[][2] =
117 MAP( AI_NUMERICHOST
),
118 #ifdef AI_NUMERICSERV
119 MAP( AI_NUMERICSERV
),
125 MAP( AI_ADDRCONFIG
),
128 static const int nameinfo_flag_map
[][2] =
133 MAP( NI_NUMERICHOST
),
134 MAP( NI_NUMERICSERV
),
137 static const int family_map
[][2] =
150 static const int socktype_map
[][2] =
157 static const int ip_protocol_map
[][2] =
166 {WS_IPPROTO_IPV4
, IPPROTO_IPIP
},
171 static pthread_once_t hash_init_once
= PTHREAD_ONCE_INIT
;
172 static BYTE byte_hash
[256];
174 static void init_hash(void)
181 for (i
= 0; i
< sizeof(byte_hash
); ++i
)
184 buf_len
= sizeof(SYSTEM_INTERRUPT_INFORMATION
) * NtCurrentTeb()->Peb
->NumberOfProcessors
;
185 if (!(buf
= malloc( buf_len
)))
187 ERR( "No memory.\n" );
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" );
200 index
= i
+ buf
[i
% buf_len
] % (sizeof(byte_hash
) - i
);
201 tmp
= byte_hash
[index
];
202 byte_hash
[index
] = byte_hash
[i
];
208 static void hash_random( BYTE
*d
, const BYTE
*s
, unsigned int len
)
212 for (i
= 0; i
< len
; ++i
)
213 d
[i
] = byte_hash
[s
[i
]];
216 static int addrinfo_flags_from_unix( int flags
)
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];
231 FIXME( "unhandled flags %#x\n", flags
);
235 static int addrinfo_flags_to_unix( int flags
)
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];
250 FIXME( "unhandled flags %#x\n", flags
);
254 static int nameinfo_flags_to_unix( int flags
)
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];
269 FIXME( "unhandled flags %#x\n", flags
);
273 static int family_from_unix( int family
)
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
);
287 static int family_to_unix( int family
)
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
);
301 static int socktype_from_unix( int type
)
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
);
315 static int socktype_to_unix( int type
)
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
);
329 static int protocol_from_unix( int protocol
)
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)
342 FIXME( "unhandled protocol %u\n", protocol
);
346 static int protocol_to_unix( int protocol
)
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)
359 FIXME( "unhandled protocol %u\n", protocol
);
363 static unsigned int errno_from_unix( int err
)
367 case EINTR
: return WSAEINTR
;
368 case EBADF
: return WSAEBADF
;
370 case EACCES
: return WSAEACCES
;
371 case EFAULT
: return WSAEFAULT
;
372 case EINVAL
: return WSAEINVAL
;
373 case EMFILE
: return WSAEMFILE
;
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
;
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
;
408 case EPROCLIM
: return WSAEPROCLIM
;
411 case EUSERS
: return WSAEUSERS
;
414 case EDQUOT
: return WSAEDQUOT
;
417 case ESTALE
: return WSAESTALE
;
420 case EREMOTE
: return WSAEREMOTE
;
423 FIXME( "unknown error: %s\n", strerror( err
) );
428 static UINT
host_errno_from_unix( int 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
;
441 WARN( "Unknown h_errno %d!\n", err
);
442 return WSAEOPNOTSUPP
;
446 static int addrinfo_err_from_unix( int err
)
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. */
459 case EAI_NODATA
: return WS_EAI_NODATA
;
462 case EAI_NONAME
: return WS_EAI_NODATA
;
464 case EAI_SERVICE
: return WS_EAI_SERVICE
;
465 case EAI_SOCKTYPE
: return WS_EAI_SOCKTYPE
;
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
;
473 FIXME( "unhandled error %d\n", err
);
480 struct sockaddr addr
;
481 struct sockaddr_in in
;
482 struct sockaddr_in6 in6
;
484 struct sockaddr_ipx ipx
;
487 struct sockaddr_irda irda
;
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
)
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
) );
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
;
526 memcpy( wsaddr
, &win
, sizeof(win
) );
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
) );
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
);
560 memcpy( win
.irdaServiceName
, uaddr
->irda
.sir_name
, sizeof(win
.irdaServiceName
) );
561 memcpy( wsaddr
, &win
, sizeof(win
) );
571 FIXME( "unknown address family %d\n", uaddr
->addr
.sa_family
);
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
)
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
);
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
;
607 return sizeof(uaddr
->in6
);
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
);
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
;
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
);
649 default: /* likely an ipv4 address */
650 case sizeof(struct WS_sockaddr_in
):
651 return sizeof(uaddr
->in
);
654 case sizeof(struct WS_sockaddr_ipx
):
655 return sizeof(uaddr
->ipx
);
659 case sizeof(SOCKADDR_IRDA
):
660 return sizeof(uaddr
->irda
);
663 case sizeof(struct WS_sockaddr_in6
):
664 return sizeof(uaddr
->in6
);
668 FIXME( "unknown address family %u\n", wsaddr
->sa_family
);
673 static BOOL
addrinfo_in_list( const struct WS_addrinfo
*list
, const struct WS_addrinfo
*ai
)
675 const struct WS_addrinfo
*cursor
= list
;
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
)))
689 cursor
= cursor
->ai_next
;
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;
706 /* servname tweak required by OSX and BSD kernels */
707 if (service
&& !service
[0]) service
= "0";
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
);
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
;
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
);
782 dst
->ai_socktype
= hints
->ai_socktype
;
783 dst
->ai_protocol
= hints
->ai_protocol
;
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 );
801 sockaddr_from_unix( (const union unix_sockaddr
*)src
->ai_addr
, dst
->ai_addr
, dst
->ai_addrlen
);
803 next
= (char *)dst
->ai_addr
+ dst
->ai_addrlen
;
805 if (dst
== params
->info
|| !addrinfo_in_list( params
->info
, dst
))
814 freeaddrinfo( unix_info
);
817 FIXME( "getaddrinfo() not found during build time\n" );
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
;
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
)
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
);
874 strcpy( host
->h_name
, unix_host
->h_name
);
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
;
889 if (params
->family
== WS_AF_INET
&& params
->len
== 4 && !memcmp( addr
, magic_loopback_addr
, 4 ))
892 #ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
894 char *unix_buffer
, *new_buffer
;
895 struct hostent stack_host
;
896 int unix_size
= 1024;
899 if (!(unix_buffer
= malloc( unix_size
)))
902 while (gethostbyaddr_r( addr
, params
->len
, unix_family
, &stack_host
, unix_buffer
,
903 unix_size
, &unix_host
, &locerr
) == ERANGE
)
906 if (!(new_buffer
= realloc( unix_buffer
, unix_size
)))
911 unix_buffer
= new_buffer
;
915 ret
= (locerr
< 0 ? errno_from_unix( errno
) : host_errno_from_unix( locerr
));
917 ret
= hostent_from_unix( unix_host
, params
->host
, params
->size
);
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
);
932 ret
= hostent_from_unix( unix_host
, params
->host
, params
->size
);
934 pthread_mutex_unlock( &host_mutex
);
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
957 * Just sorting the addresses would break server load balancing provided by gethostbyname(), so randomize the
958 * sort once per process. */
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;
988 if (!(unix_buffer
= malloc( unix_size
)))
991 while (gethostbyname_r( params
->name
, &stack_host
, unix_buffer
, unix_size
, &unix_host
, &locerr
) == ERANGE
)
994 if (!(new_buffer
= realloc( unix_buffer
, unix_size
)))
999 unix_buffer
= new_buffer
;
1004 ret
= (locerr
< 0 ? errno_from_unix( errno
) : host_errno_from_unix( locerr
));
1008 sort_addrs_hashed( unix_host
);
1009 ret
= hostent_from_unix( unix_host
, params
->host
, params
->size
);
1012 free( unix_buffer
);
1016 static NTSTATUS
unix_gethostbyname( void *args
)
1018 struct gethostbyname_params
*params
= args
;
1019 struct hostent
*unix_host
;
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
);
1031 sort_addrs_hashed( unix_host
);
1032 ret
= hostent_from_unix( unix_host
, params
->host
, params
->size
);
1034 pthread_mutex_unlock( &host_mutex
);
1040 static NTSTATUS
unix_gethostname( void *args
)
1042 struct gethostname_params
*params
= args
;
1044 if (!gethostname( params
->name
, params
->size
))
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
[] =
1075 typedef ULONG PTR32
;
1077 struct WS_addrinfo32
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
);
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
;
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
);
1198 host32
->h_name
= PtrToUlong( p
);
1199 strcpy( p
, host
->h_name
);
1200 return STATUS_SUCCESS
;
1204 static NTSTATUS
wow64_unix_getaddrinfo( void *args
)
1213 } const *params32
= args
;
1216 struct WS_addrinfo hints
;
1217 struct getaddrinfo_params params
=
1219 ULongToPtr( params32
->node
),
1220 ULongToPtr( params32
->service
),
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( ¶ms
);
1238 if (!status
) put_addrinfo32( params
.info
, ULongToPtr(params32
->info
), ULongToPtr(params32
->size
) );
1239 free( params
.info
);
1244 static NTSTATUS
wow64_unix_gethostbyaddr( void *args
)
1253 } const *params32
= args
;
1256 struct gethostbyaddr_params params
=
1258 ULongToPtr( params32
->addr
),
1262 ULongToPtr(params32
->size
)
1265 if (!(params
.host
= malloc( *params
.size
))) return WSAENOBUFS
;
1266 status
= unix_gethostbyaddr( ¶ms
);
1268 status
= put_hostent32( params
.host
, ULongToPtr(params32
->host
), ULongToPtr(params32
->size
) );
1269 free( params
.host
);
1274 static NTSTATUS
wow64_unix_gethostbyname( void *args
)
1281 } const *params32
= args
;
1284 struct gethostbyname_params params
=
1286 ULongToPtr( params32
->name
),
1288 ULongToPtr(params32
->size
)
1291 if (!(params
.host
= malloc( *params
.size
))) return WSAENOBUFS
;
1292 status
= unix_gethostbyname( ¶ms
);
1294 status
= put_hostent32( params
.host
, ULongToPtr(params32
->host
), ULongToPtr(params32
->size
) );
1295 free( params
.host
);
1300 static NTSTATUS
wow64_unix_gethostname( void *args
)
1306 } const *params32
= args
;
1308 struct gethostname_params params
= { ULongToPtr(params32
->name
), params32
->size
};
1310 if (!unix_gethostname( ¶ms
)) return 0;
1311 return errno_from_unix( errno
);
1315 static NTSTATUS
wow64_unix_getnameinfo( void *args
)
1326 } const *params32
= args
;
1328 struct getnameinfo_params params
=
1330 ULongToPtr( params32
->addr
),
1332 ULongToPtr( params32
->host
),
1334 ULongToPtr( params32
->serv
),
1339 return unix_getnameinfo( ¶ms
);
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
,