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
);
106 #ifndef HAVE_LINUX_GETHOSTBYNAME_R_6
107 static pthread_mutex_t host_mutex
= PTHREAD_MUTEX_INITIALIZER
;
110 #define MAP(x) {WS_ ## x, x}
112 static const int addrinfo_flag_map
[][2] =
116 MAP( AI_NUMERICHOST
),
117 #ifdef AI_NUMERICSERV
118 MAP( AI_NUMERICSERV
),
124 MAP( AI_ADDRCONFIG
),
127 static const int nameinfo_flag_map
[][2] =
132 MAP( NI_NUMERICHOST
),
133 MAP( NI_NUMERICSERV
),
136 static const int family_map
[][2] =
149 static const int socktype_map
[][2] =
156 static const int ip_protocol_map
[][2] =
165 {WS_IPPROTO_IPV4
, IPPROTO_IPIP
},
170 static pthread_once_t hash_init_once
= PTHREAD_ONCE_INIT
;
171 static BYTE byte_hash
[256];
173 static void init_hash(void)
180 for (i
= 0; i
< sizeof(byte_hash
); ++i
)
183 buf_len
= sizeof(SYSTEM_INTERRUPT_INFORMATION
) * NtCurrentTeb()->Peb
->NumberOfProcessors
;
184 if (!(buf
= malloc( buf_len
)))
186 ERR( "No memory.\n" );
190 for (i
= 0; i
< sizeof(byte_hash
) - 1; ++i
)
192 if (!(i
% buf_len
) && (status
= NtQuerySystemInformation( SystemInterruptInformation
, buf
,
193 buf_len
, &buf_len
)))
195 ERR( "Failed to get random bytes.\n" );
199 index
= i
+ buf
[i
% buf_len
] % (sizeof(byte_hash
) - i
);
200 tmp
= byte_hash
[index
];
201 byte_hash
[index
] = byte_hash
[i
];
207 static void hash_random( BYTE
*d
, const BYTE
*s
, unsigned int len
)
211 for (i
= 0; i
< len
; ++i
)
212 d
[i
] = byte_hash
[s
[i
]];
215 static int addrinfo_flags_from_unix( int flags
)
220 for (i
= 0; i
< ARRAY_SIZE(addrinfo_flag_map
); ++i
)
222 if (flags
& addrinfo_flag_map
[i
][1])
224 ws_flags
|= addrinfo_flag_map
[i
][0];
225 flags
&= ~addrinfo_flag_map
[i
][1];
230 FIXME( "unhandled flags %#x\n", flags
);
234 static int addrinfo_flags_to_unix( int flags
)
239 for (i
= 0; i
< ARRAY_SIZE(addrinfo_flag_map
); ++i
)
241 if (flags
& addrinfo_flag_map
[i
][0])
243 unix_flags
|= addrinfo_flag_map
[i
][1];
244 flags
&= ~addrinfo_flag_map
[i
][0];
249 FIXME( "unhandled flags %#x\n", flags
);
253 static int nameinfo_flags_to_unix( int flags
)
258 for (i
= 0; i
< ARRAY_SIZE(nameinfo_flag_map
); ++i
)
260 if (flags
& nameinfo_flag_map
[i
][0])
262 unix_flags
|= nameinfo_flag_map
[i
][1];
263 flags
&= ~nameinfo_flag_map
[i
][0];
268 FIXME( "unhandled flags %#x\n", flags
);
272 static int family_from_unix( int family
)
276 for (i
= 0; i
< ARRAY_SIZE(family_map
); ++i
)
278 if (family
== family_map
[i
][1])
279 return family_map
[i
][0];
282 FIXME( "unhandled family %u\n", family
);
286 static int family_to_unix( int family
)
290 for (i
= 0; i
< ARRAY_SIZE(family_map
); ++i
)
292 if (family
== family_map
[i
][0])
293 return family_map
[i
][1];
296 FIXME( "unhandled family %u\n", family
);
300 static int socktype_from_unix( int type
)
304 for (i
= 0; i
< ARRAY_SIZE(socktype_map
); ++i
)
306 if (type
== socktype_map
[i
][1])
307 return socktype_map
[i
][0];
310 FIXME( "unhandled type %u\n", type
);
314 static int socktype_to_unix( int type
)
318 for (i
= 0; i
< ARRAY_SIZE(socktype_map
); ++i
)
320 if (type
== socktype_map
[i
][0])
321 return socktype_map
[i
][1];
324 FIXME( "unhandled type %u\n", type
);
328 static int protocol_from_unix( int protocol
)
332 for (i
= 0; i
< ARRAY_SIZE(ip_protocol_map
); ++i
)
334 if (protocol
== ip_protocol_map
[i
][1])
335 return ip_protocol_map
[i
][0];
338 if (protocol
>= WS_NSPROTO_IPX
&& protocol
<= WS_NSPROTO_IPX
+ 255)
341 FIXME( "unhandled protocol %u\n", protocol
);
345 static int protocol_to_unix( int protocol
)
349 for (i
= 0; i
< ARRAY_SIZE(ip_protocol_map
); ++i
)
351 if (protocol
== ip_protocol_map
[i
][0])
352 return ip_protocol_map
[i
][1];
355 if (protocol
>= WS_NSPROTO_IPX
&& protocol
<= WS_NSPROTO_IPX
+ 255)
358 FIXME( "unhandled protocol %u\n", protocol
);
362 static unsigned int errno_from_unix( int err
)
366 case EINTR
: return WSAEINTR
;
367 case EBADF
: return WSAEBADF
;
369 case EACCES
: return WSAEACCES
;
370 case EFAULT
: return WSAEFAULT
;
371 case EINVAL
: return WSAEINVAL
;
372 case EMFILE
: return WSAEMFILE
;
374 case EWOULDBLOCK
: return WSAEWOULDBLOCK
;
375 case EALREADY
: return WSAEALREADY
;
376 case ENOTSOCK
: return WSAENOTSOCK
;
377 case EDESTADDRREQ
: return WSAEDESTADDRREQ
;
378 case EMSGSIZE
: return WSAEMSGSIZE
;
379 case EPROTOTYPE
: return WSAEPROTOTYPE
;
380 case ENOPROTOOPT
: return WSAENOPROTOOPT
;
381 case EPROTONOSUPPORT
: return WSAEPROTONOSUPPORT
;
382 case ESOCKTNOSUPPORT
: return WSAESOCKTNOSUPPORT
;
383 case EOPNOTSUPP
: return WSAEOPNOTSUPP
;
384 case EPFNOSUPPORT
: return WSAEPFNOSUPPORT
;
385 case EAFNOSUPPORT
: return WSAEAFNOSUPPORT
;
386 case EADDRINUSE
: return WSAEADDRINUSE
;
387 case EADDRNOTAVAIL
: return WSAEADDRNOTAVAIL
;
388 case ENETDOWN
: return WSAENETDOWN
;
389 case ENETUNREACH
: return WSAENETUNREACH
;
390 case ENETRESET
: return WSAENETRESET
;
391 case ECONNABORTED
: return WSAECONNABORTED
;
393 case ECONNRESET
: return WSAECONNRESET
;
394 case ENOBUFS
: return WSAENOBUFS
;
395 case EISCONN
: return WSAEISCONN
;
396 case ENOTCONN
: return WSAENOTCONN
;
397 case ESHUTDOWN
: return WSAESHUTDOWN
;
398 case ETOOMANYREFS
: return WSAETOOMANYREFS
;
399 case ETIMEDOUT
: return WSAETIMEDOUT
;
400 case ECONNREFUSED
: return WSAECONNREFUSED
;
401 case ELOOP
: return WSAELOOP
;
402 case ENAMETOOLONG
: return WSAENAMETOOLONG
;
403 case EHOSTDOWN
: return WSAEHOSTDOWN
;
404 case EHOSTUNREACH
: return WSAEHOSTUNREACH
;
405 case ENOTEMPTY
: return WSAENOTEMPTY
;
407 case EPROCLIM
: return WSAEPROCLIM
;
410 case EUSERS
: return WSAEUSERS
;
413 case EDQUOT
: return WSAEDQUOT
;
416 case ESTALE
: return WSAESTALE
;
419 case EREMOTE
: return WSAEREMOTE
;
422 FIXME( "unknown error: %s\n", strerror( err
) );
427 static UINT
host_errno_from_unix( int err
)
433 case HOST_NOT_FOUND
: return WSAHOST_NOT_FOUND
;
434 case TRY_AGAIN
: return WSATRY_AGAIN
;
435 case NO_RECOVERY
: return WSANO_RECOVERY
;
436 case NO_DATA
: return WSANO_DATA
;
437 case ENOBUFS
: return WSAENOBUFS
;
440 WARN( "Unknown h_errno %d!\n", err
);
441 return WSAEOPNOTSUPP
;
445 static int addrinfo_err_from_unix( int err
)
450 case EAI_AGAIN
: return WS_EAI_AGAIN
;
451 case EAI_BADFLAGS
: return WS_EAI_BADFLAGS
;
452 case EAI_FAIL
: return WS_EAI_FAIL
;
453 case EAI_FAMILY
: return WS_EAI_FAMILY
;
454 case EAI_MEMORY
: return WS_EAI_MEMORY
;
455 /* EAI_NODATA is deprecated, but still used by Windows and Linux. We map
456 * the newer EAI_NONAME to EAI_NODATA for now until Windows changes too. */
458 case EAI_NODATA
: return WS_EAI_NODATA
;
461 case EAI_NONAME
: return WS_EAI_NODATA
;
463 case EAI_SERVICE
: return WS_EAI_SERVICE
;
464 case EAI_SOCKTYPE
: return WS_EAI_SOCKTYPE
;
466 /* some broken versions of glibc return EAI_SYSTEM and set errno to
467 * 0 instead of returning EAI_NONAME */
468 return errno
? errno_from_unix( errno
) : WS_EAI_NONAME
;
471 FIXME( "unhandled error %d\n", err
);
478 struct sockaddr addr
;
479 struct sockaddr_in in
;
480 struct sockaddr_in6 in6
;
482 struct sockaddr_ipx ipx
;
485 struct sockaddr_irda irda
;
489 /* different from the version in ntdll and server; it does not return failure if
490 * given a short buffer */
491 static int sockaddr_from_unix( const union unix_sockaddr
*uaddr
, struct WS_sockaddr
*wsaddr
, socklen_t wsaddrlen
)
493 memset( wsaddr
, 0, wsaddrlen
);
495 switch (uaddr
->addr
.sa_family
)
499 struct WS_sockaddr_in win
= {0};
501 if (wsaddrlen
>= sizeof(win
))
503 win
.sin_family
= WS_AF_INET
;
504 win
.sin_port
= uaddr
->in
.sin_port
;
505 memcpy( &win
.sin_addr
, &uaddr
->in
.sin_addr
, sizeof(win
.sin_addr
) );
506 memcpy( wsaddr
, &win
, sizeof(win
) );
513 struct WS_sockaddr_in6 win
= {0};
515 if (wsaddrlen
>= sizeof(win
))
517 win
.sin6_family
= WS_AF_INET6
;
518 win
.sin6_port
= uaddr
->in6
.sin6_port
;
519 win
.sin6_flowinfo
= uaddr
->in6
.sin6_flowinfo
;
520 memcpy( &win
.sin6_addr
, &uaddr
->in6
.sin6_addr
, sizeof(win
.sin6_addr
) );
521 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
522 win
.sin6_scope_id
= uaddr
->in6
.sin6_scope_id
;
524 memcpy( wsaddr
, &win
, sizeof(win
) );
532 struct WS_sockaddr_ipx win
= {0};
534 if (wsaddrlen
>= sizeof(win
))
536 win
.sa_family
= WS_AF_IPX
;
537 memcpy( win
.sa_netnum
, &uaddr
->ipx
.sipx_network
, sizeof(win
.sa_netnum
) );
538 memcpy( win
.sa_nodenum
, &uaddr
->ipx
.sipx_node
, sizeof(win
.sa_nodenum
) );
539 win
.sa_socket
= uaddr
->ipx
.sipx_port
;
540 memcpy( wsaddr
, &win
, sizeof(win
) );
551 if (wsaddrlen
>= sizeof(win
))
553 win
.irdaAddressFamily
= WS_AF_IRDA
;
554 memcpy( win
.irdaDeviceID
, &uaddr
->irda
.sir_addr
, sizeof(win
.irdaDeviceID
) );
555 if (uaddr
->irda
.sir_lsap_sel
!= LSAP_ANY
)
556 snprintf( win
.irdaServiceName
, sizeof(win
.irdaServiceName
), "LSAP-SEL%u", uaddr
->irda
.sir_lsap_sel
);
558 memcpy( win
.irdaServiceName
, uaddr
->irda
.sir_name
, sizeof(win
.irdaServiceName
) );
559 memcpy( wsaddr
, &win
, sizeof(win
) );
569 FIXME( "unknown address family %d\n", uaddr
->addr
.sa_family
);
574 static socklen_t
sockaddr_to_unix( const struct WS_sockaddr
*wsaddr
, int wsaddrlen
, union unix_sockaddr
*uaddr
)
576 memset( uaddr
, 0, sizeof(*uaddr
) );
578 switch (wsaddr
->sa_family
)
582 struct WS_sockaddr_in win
= {0};
584 if (wsaddrlen
< sizeof(win
)) return 0;
585 memcpy( &win
, wsaddr
, sizeof(win
) );
586 uaddr
->in
.sin_family
= AF_INET
;
587 uaddr
->in
.sin_port
= win
.sin_port
;
588 memcpy( &uaddr
->in
.sin_addr
, &win
.sin_addr
, sizeof(win
.sin_addr
) );
589 return sizeof(uaddr
->in
);
594 struct WS_sockaddr_in6 win
= {0};
596 if (wsaddrlen
< sizeof(win
)) return 0;
597 memcpy( &win
, wsaddr
, sizeof(win
) );
598 uaddr
->in6
.sin6_family
= AF_INET6
;
599 uaddr
->in6
.sin6_port
= win
.sin6_port
;
600 uaddr
->in6
.sin6_flowinfo
= win
.sin6_flowinfo
;
601 memcpy( &uaddr
->in6
.sin6_addr
, &win
.sin6_addr
, sizeof(win
.sin6_addr
) );
602 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
603 uaddr
->in6
.sin6_scope_id
= win
.sin6_scope_id
;
605 return sizeof(uaddr
->in6
);
611 struct WS_sockaddr_ipx win
= {0};
613 if (wsaddrlen
< sizeof(win
)) return 0;
614 memcpy( &win
, wsaddr
, sizeof(win
) );
615 uaddr
->ipx
.sipx_family
= AF_IPX
;
616 memcpy( &uaddr
->ipx
.sipx_network
, win
.sa_netnum
, sizeof(win
.sa_netnum
) );
617 memcpy( &uaddr
->ipx
.sipx_node
, win
.sa_nodenum
, sizeof(win
.sa_nodenum
) );
618 uaddr
->ipx
.sipx_port
= win
.sa_socket
;
619 return sizeof(uaddr
->ipx
);
626 SOCKADDR_IRDA win
= {0};
627 unsigned int lsap_sel
;
629 if (wsaddrlen
< sizeof(win
)) return 0;
630 memcpy( &win
, wsaddr
, sizeof(win
) );
631 uaddr
->irda
.sir_family
= AF_IRDA
;
632 if (sscanf( win
.irdaServiceName
, "LSAP-SEL%u", &lsap_sel
) == 1)
633 uaddr
->irda
.sir_lsap_sel
= lsap_sel
;
636 uaddr
->irda
.sir_lsap_sel
= LSAP_ANY
;
637 memcpy( uaddr
->irda
.sir_name
, win
.irdaServiceName
, sizeof(win
.irdaServiceName
) );
639 memcpy( &uaddr
->irda
.sir_addr
, win
.irdaDeviceID
, sizeof(win
.irdaDeviceID
) );
640 return sizeof(uaddr
->irda
);
647 default: /* likely an ipv4 address */
648 case sizeof(struct WS_sockaddr_in
):
649 return sizeof(uaddr
->in
);
652 case sizeof(struct WS_sockaddr_ipx
):
653 return sizeof(uaddr
->ipx
);
657 case sizeof(SOCKADDR_IRDA
):
658 return sizeof(uaddr
->irda
);
661 case sizeof(struct WS_sockaddr_in6
):
662 return sizeof(uaddr
->in6
);
666 FIXME( "unknown address family %u\n", wsaddr
->sa_family
);
671 static BOOL
addrinfo_in_list( const struct WS_addrinfo
*list
, const struct WS_addrinfo
*ai
)
673 const struct WS_addrinfo
*cursor
= list
;
676 if (ai
->ai_flags
== cursor
->ai_flags
&&
677 ai
->ai_family
== cursor
->ai_family
&&
678 ai
->ai_socktype
== cursor
->ai_socktype
&&
679 ai
->ai_protocol
== cursor
->ai_protocol
&&
680 ai
->ai_addrlen
== cursor
->ai_addrlen
&&
681 !memcmp( ai
->ai_addr
, cursor
->ai_addr
, ai
->ai_addrlen
) &&
682 ((ai
->ai_canonname
&& cursor
->ai_canonname
&& !strcmp( ai
->ai_canonname
, cursor
->ai_canonname
))
683 || (!ai
->ai_canonname
&& !cursor
->ai_canonname
)))
687 cursor
= cursor
->ai_next
;
692 static NTSTATUS
unix_getaddrinfo( void *args
)
694 #ifdef HAVE_GETADDRINFO
695 struct getaddrinfo_params
*params
= args
;
696 const char *service
= params
->service
;
697 const struct WS_addrinfo
*hints
= params
->hints
;
698 struct addrinfo unix_hints
= {0};
699 struct addrinfo
*unix_info
, *src
;
700 struct WS_addrinfo
*dst
, *prev
= NULL
;
701 unsigned int needed_size
= 0;
704 /* servname tweak required by OSX and BSD kernels */
705 if (service
&& !service
[0]) service
= "0";
709 unix_hints
.ai_flags
= addrinfo_flags_to_unix( hints
->ai_flags
);
711 if (hints
->ai_family
)
712 unix_hints
.ai_family
= family_to_unix( hints
->ai_family
);
714 if (hints
->ai_socktype
)
716 if ((unix_hints
.ai_socktype
= socktype_to_unix( hints
->ai_socktype
)) < 0)
717 return WSAESOCKTNOSUPPORT
;
720 if (hints
->ai_protocol
)
721 unix_hints
.ai_protocol
= max( protocol_to_unix( hints
->ai_protocol
), 0 );
723 /* Windows allows some invalid combinations */
724 if (unix_hints
.ai_protocol
== IPPROTO_TCP
725 && unix_hints
.ai_socktype
!= SOCK_STREAM
726 && unix_hints
.ai_socktype
!= SOCK_SEQPACKET
)
728 WARN( "ignoring invalid type %u for TCP\n", unix_hints
.ai_socktype
);
729 unix_hints
.ai_socktype
= 0;
731 else if (unix_hints
.ai_protocol
== IPPROTO_UDP
&& unix_hints
.ai_socktype
!= SOCK_DGRAM
)
733 WARN( "ignoring invalid type %u for UDP\n", unix_hints
.ai_socktype
);
734 unix_hints
.ai_socktype
= 0;
736 else if (unix_hints
.ai_protocol
>= WS_NSPROTO_IPX
&& unix_hints
.ai_protocol
<= WS_NSPROTO_IPX
+ 255
737 && unix_hints
.ai_socktype
!= SOCK_DGRAM
)
739 WARN( "ignoring invalid type %u for IPX\n", unix_hints
.ai_socktype
);
740 unix_hints
.ai_socktype
= 0;
742 else if (unix_hints
.ai_protocol
== IPPROTO_IPV6
)
744 WARN( "ignoring protocol IPv6\n" );
745 unix_hints
.ai_protocol
= 0;
749 ret
= getaddrinfo( params
->node
, service
, hints
? &unix_hints
: NULL
, &unix_info
);
751 return addrinfo_err_from_unix( ret
);
753 for (src
= unix_info
; src
!= NULL
; src
= src
->ai_next
)
755 needed_size
+= sizeof(struct WS_addrinfo
);
756 if (src
->ai_canonname
)
757 needed_size
+= strlen( src
->ai_canonname
) + 1;
758 needed_size
+= sockaddr_from_unix( (const union unix_sockaddr
*)src
->ai_addr
, NULL
, 0 );
761 if (*params
->size
< needed_size
)
763 *params
->size
= needed_size
;
764 freeaddrinfo( unix_info
);
765 return ERROR_INSUFFICIENT_BUFFER
;
770 memset( params
->info
, 0, needed_size
);
772 for (src
= unix_info
; src
!= NULL
; src
= src
->ai_next
)
774 void *next
= dst
+ 1;
776 dst
->ai_flags
= addrinfo_flags_from_unix( src
->ai_flags
);
777 dst
->ai_family
= family_from_unix( src
->ai_family
);
780 dst
->ai_socktype
= hints
->ai_socktype
;
781 dst
->ai_protocol
= hints
->ai_protocol
;
785 dst
->ai_socktype
= socktype_from_unix( src
->ai_socktype
);
786 dst
->ai_protocol
= protocol_from_unix( src
->ai_protocol
);
788 if (src
->ai_canonname
)
790 size_t len
= strlen( src
->ai_canonname
) + 1;
792 dst
->ai_canonname
= next
;
793 memcpy( dst
->ai_canonname
, src
->ai_canonname
, len
);
794 next
= dst
->ai_canonname
+ len
;
797 dst
->ai_addrlen
= sockaddr_from_unix( (const union unix_sockaddr
*)src
->ai_addr
, NULL
, 0 );
799 sockaddr_from_unix( (const union unix_sockaddr
*)src
->ai_addr
, dst
->ai_addr
, dst
->ai_addrlen
);
801 next
= (char *)dst
->ai_addr
+ dst
->ai_addrlen
;
803 if (dst
== params
->info
|| !addrinfo_in_list( params
->info
, dst
))
812 freeaddrinfo( unix_info
);
815 FIXME( "getaddrinfo() not found during build time\n" );
821 static int hostent_from_unix( const struct hostent
*unix_host
, struct WS_hostent
*host
, unsigned int *const size
)
823 unsigned int needed_size
= sizeof( struct WS_hostent
), alias_count
= 0, addr_count
= 0, i
;
826 needed_size
+= strlen( unix_host
->h_name
) + 1;
828 for (alias_count
= 0; unix_host
->h_aliases
[alias_count
] != NULL
; ++alias_count
)
829 needed_size
+= sizeof(char *) + strlen( unix_host
->h_aliases
[alias_count
] ) + 1;
830 needed_size
+= sizeof(char *); /* null terminator */
832 for (addr_count
= 0; unix_host
->h_addr_list
[addr_count
] != NULL
; ++addr_count
)
833 needed_size
+= sizeof(char *) + unix_host
->h_length
;
834 needed_size
+= sizeof(char *); /* null terminator */
836 if (*size
< needed_size
)
839 return ERROR_INSUFFICIENT_BUFFER
;
842 memset( host
, 0, needed_size
);
844 /* arrange the memory in the same order as windows >= XP */
846 host
->h_addrtype
= family_from_unix( unix_host
->h_addrtype
);
847 host
->h_length
= unix_host
->h_length
;
849 p
= (char *)(host
+ 1);
850 host
->h_aliases
= (char **)p
;
851 p
+= (alias_count
+ 1) * sizeof(char *);
852 host
->h_addr_list
= (char **)p
;
853 p
+= (addr_count
+ 1) * sizeof(char *);
855 for (i
= 0; i
< addr_count
; ++i
)
857 host
->h_addr_list
[i
] = p
;
858 memcpy( host
->h_addr_list
[i
], unix_host
->h_addr_list
[i
], unix_host
->h_length
);
859 p
+= unix_host
->h_length
;
862 for (i
= 0; i
< alias_count
; ++i
)
864 size_t len
= strlen( unix_host
->h_aliases
[i
] ) + 1;
866 host
->h_aliases
[i
] = p
;
867 memcpy( host
->h_aliases
[i
], unix_host
->h_aliases
[i
], len
);
872 strcpy( host
->h_name
, unix_host
->h_name
);
878 static NTSTATUS
unix_gethostbyaddr( void *args
)
880 struct gethostbyaddr_params
*params
= args
;
881 const void *addr
= params
->addr
;
882 const struct in_addr loopback
= { htonl( INADDR_LOOPBACK
) };
883 int unix_family
= family_to_unix( params
->family
);
884 struct hostent
*unix_host
;
887 if (params
->family
== WS_AF_INET
&& params
->len
== 4 && !memcmp( addr
, magic_loopback_addr
, 4 ))
890 #ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
892 char *unix_buffer
, *new_buffer
;
893 struct hostent stack_host
;
894 int unix_size
= 1024;
897 if (!(unix_buffer
= malloc( unix_size
)))
900 while (gethostbyaddr_r( addr
, params
->len
, unix_family
, &stack_host
, unix_buffer
,
901 unix_size
, &unix_host
, &locerr
) == ERANGE
)
904 if (!(new_buffer
= realloc( unix_buffer
, unix_size
)))
909 unix_buffer
= new_buffer
;
913 ret
= (locerr
< 0 ? errno_from_unix( errno
) : host_errno_from_unix( locerr
));
915 ret
= hostent_from_unix( unix_host
, params
->host
, params
->size
);
921 pthread_mutex_lock( &host_mutex
);
923 if (!(unix_host
= gethostbyaddr( addr
, params
->len
, unix_family
)))
925 ret
= (h_errno
< 0 ? errno_from_unix( errno
) : host_errno_from_unix( h_errno
));
926 pthread_mutex_unlock( &host_mutex
);
930 ret
= hostent_from_unix( unix_host
, params
->host
, params
->size
);
932 pthread_mutex_unlock( &host_mutex
);
937 static int compare_addrs_hashed( const void *a1
, const void *a2
, int addr_len
)
939 char a1_hashed
[16], a2_hashed
[16];
941 assert( addr_len
<= sizeof(a1_hashed
) );
942 hash_random( (BYTE
*)a1_hashed
, a1
, addr_len
);
943 hash_random( (BYTE
*)a2_hashed
, a2
, addr_len
);
944 return memcmp( a1_hashed
, a2_hashed
, addr_len
);
947 static void sort_addrs_hashed( struct hostent
*host
)
949 /* On Unix gethostbyname() may return IP addresses in random order on each call. On Windows the order of
950 * IP addresses is not determined as well but it is the same on consequent calls (changes after network
951 * resets and probably DNS timeout expiration).
952 * Life is Strange Remastered depends on gethostbyname() returning IP addresses in the same order to reuse
953 * the established TLS connection and avoid timeouts that happen in game when establishing multiple extra TLS
955 * Just sorting the addresses would break server load balancing provided by gethostbyname(), so randomize the
956 * sort once per process. */
960 pthread_once( &hash_init_once
, init_hash
);
962 for (i
= 0; host
->h_addr_list
[i
]; ++i
)
964 for (j
= i
+ 1; host
->h_addr_list
[j
]; ++j
)
966 if (compare_addrs_hashed( host
->h_addr_list
[j
], host
->h_addr_list
[i
], host
->h_length
) < 0)
968 tmp
= host
->h_addr_list
[j
];
969 host
->h_addr_list
[j
] = host
->h_addr_list
[i
];
970 host
->h_addr_list
[i
] = tmp
;
976 #ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
977 static NTSTATUS
unix_gethostbyname( void *args
)
979 struct gethostbyname_params
*params
= args
;
980 struct hostent stack_host
, *unix_host
;
981 char *unix_buffer
, *new_buffer
;
982 int unix_size
= 1024;
986 if (!(unix_buffer
= malloc( unix_size
)))
989 while (gethostbyname_r( params
->name
, &stack_host
, unix_buffer
, unix_size
, &unix_host
, &locerr
) == ERANGE
)
992 if (!(new_buffer
= realloc( unix_buffer
, unix_size
)))
997 unix_buffer
= new_buffer
;
1002 ret
= (locerr
< 0 ? errno_from_unix( errno
) : host_errno_from_unix( locerr
));
1006 sort_addrs_hashed( unix_host
);
1007 ret
= hostent_from_unix( unix_host
, params
->host
, params
->size
);
1010 free( unix_buffer
);
1014 static NTSTATUS
unix_gethostbyname( void *args
)
1016 struct gethostbyname_params
*params
= args
;
1017 struct hostent
*unix_host
;
1020 pthread_mutex_lock( &host_mutex
);
1022 if (!(unix_host
= gethostbyname( params
->name
)))
1024 ret
= (h_errno
< 0 ? errno_from_unix( errno
) : host_errno_from_unix( h_errno
));
1025 pthread_mutex_unlock( &host_mutex
);
1029 sort_addrs_hashed( unix_host
);
1030 ret
= hostent_from_unix( unix_host
, params
->host
, params
->size
);
1032 pthread_mutex_unlock( &host_mutex
);
1038 static NTSTATUS
unix_gethostname( void *args
)
1040 struct gethostname_params
*params
= args
;
1042 if (!gethostname( params
->name
, params
->size
))
1044 return errno_from_unix( errno
);
1048 static NTSTATUS
unix_getnameinfo( void *args
)
1050 struct getnameinfo_params
*params
= args
;
1051 union unix_sockaddr unix_addr
;
1052 socklen_t unix_addr_len
;
1054 unix_addr_len
= sockaddr_to_unix( params
->addr
, params
->addr_len
, &unix_addr
);
1056 return addrinfo_err_from_unix( getnameinfo( &unix_addr
.addr
, unix_addr_len
, params
->host
, params
->host_len
,
1057 params
->serv
, params
->serv_len
,
1058 nameinfo_flags_to_unix( params
->flags
) ) );
1062 const unixlib_entry_t __wine_unix_call_funcs
[] =
1073 typedef ULONG PTR32
;
1075 struct WS_addrinfo32
1096 static NTSTATUS
put_addrinfo32( const struct WS_addrinfo
*info
, struct WS_addrinfo32
*info32
,
1097 unsigned int *size
)
1099 struct WS_addrinfo32
*dst
= info32
, *prev
= NULL
;
1100 const struct WS_addrinfo
*src
;
1101 unsigned int needed_size
= 0;
1103 for (src
= info
; src
!= NULL
; src
= src
->ai_next
)
1105 needed_size
+= sizeof(struct WS_addrinfo32
);
1106 if (src
->ai_canonname
) needed_size
+= strlen( src
->ai_canonname
) + 1;
1107 needed_size
+= src
->ai_addrlen
;
1110 if (*size
< needed_size
)
1112 *size
= needed_size
;
1113 return ERROR_INSUFFICIENT_BUFFER
;
1116 memset( info32
, 0, needed_size
);
1118 for (src
= info
; src
!= NULL
; src
= src
->ai_next
)
1120 char *next
= (char *)(dst
+ 1);
1122 dst
->ai_flags
= src
->ai_flags
;
1123 dst
->ai_family
= src
->ai_family
;
1124 dst
->ai_socktype
= src
->ai_socktype
;
1125 dst
->ai_protocol
= src
->ai_protocol
;
1126 if (src
->ai_canonname
)
1128 dst
->ai_canonname
= PtrToUlong( next
);
1129 strcpy( next
, src
->ai_canonname
);
1130 next
+= strlen(next
) + 1;
1132 dst
->ai_addrlen
= src
->ai_addrlen
;
1133 dst
->ai_addr
= PtrToUlong(next
);
1134 memcpy( next
, src
->ai_addr
, dst
->ai_addrlen
);
1135 next
+= dst
->ai_addrlen
;
1136 if (prev
) prev
->ai_next
= PtrToUlong(dst
);
1138 dst
= (struct WS_addrinfo32
*)next
;
1140 return STATUS_SUCCESS
;
1143 static NTSTATUS
put_hostent32( const struct WS_hostent
*host
, struct WS_hostent32
*host32
,
1144 unsigned int *size
)
1146 unsigned int needed_size
= sizeof( struct WS_hostent32
), alias_count
= 0, addr_count
= 0, i
;
1148 ULONG
*aliases
, *addr_list
;
1150 needed_size
+= strlen( host
->h_name
) + 1;
1152 for (alias_count
= 0; host
->h_aliases
[alias_count
] != NULL
; ++alias_count
)
1153 needed_size
+= sizeof(ULONG
) + strlen( host
->h_aliases
[alias_count
] ) + 1;
1154 needed_size
+= sizeof(ULONG
); /* null terminator */
1156 for (addr_count
= 0; host
->h_addr_list
[addr_count
] != NULL
; ++addr_count
)
1157 needed_size
+= sizeof(ULONG
) + host
->h_length
;
1158 needed_size
+= sizeof(ULONG
); /* null terminator */
1160 if (*size
< needed_size
)
1162 *size
= needed_size
;
1163 return ERROR_INSUFFICIENT_BUFFER
;
1166 memset( host32
, 0, needed_size
);
1168 /* arrange the memory in the same order as windows >= XP */
1170 host32
->h_addrtype
= host
->h_addrtype
;
1171 host32
->h_length
= host
->h_length
;
1173 aliases
= (ULONG
*)(host32
+ 1);
1174 addr_list
= aliases
+ alias_count
+ 1;
1175 p
= (char *)(addr_list
+ addr_count
+ 1);
1177 host32
->h_aliases
= PtrToUlong( aliases
);
1178 host32
->h_addr_list
= PtrToUlong( addr_list
);
1180 for (i
= 0; i
< addr_count
; ++i
)
1182 addr_list
[i
] = PtrToUlong( p
);
1183 memcpy( p
, host
->h_addr_list
[i
], host
->h_length
);
1184 p
+= host
->h_length
;
1187 for (i
= 0; i
< alias_count
; ++i
)
1189 size_t len
= strlen( host
->h_aliases
[i
] ) + 1;
1191 aliases
[i
] = PtrToUlong( p
);
1192 memcpy( p
, host
->h_aliases
[i
], len
);
1196 host32
->h_name
= PtrToUlong( p
);
1197 strcpy( p
, host
->h_name
);
1198 return STATUS_SUCCESS
;
1202 static NTSTATUS
wow64_unix_getaddrinfo( void *args
)
1211 } const *params32
= args
;
1214 struct WS_addrinfo hints
;
1215 struct getaddrinfo_params params
=
1217 ULongToPtr( params32
->node
),
1218 ULongToPtr( params32
->service
),
1221 ULongToPtr(params32
->size
)
1224 if (params32
->hints
)
1226 const struct WS_addrinfo32
*hints32
= ULongToPtr(params32
->hints
);
1227 hints
.ai_flags
= hints32
->ai_flags
;
1228 hints
.ai_family
= hints32
->ai_family
;
1229 hints
.ai_socktype
= hints32
->ai_socktype
;
1230 hints
.ai_protocol
= hints32
->ai_protocol
;
1231 params
.hints
= &hints
;
1234 if (!(params
.info
= malloc( *params
.size
))) return WSAENOBUFS
;
1235 status
= unix_getaddrinfo( ¶ms
);
1236 if (!status
) put_addrinfo32( params
.info
, ULongToPtr(params32
->info
), ULongToPtr(params32
->size
) );
1237 free( params
.info
);
1242 static NTSTATUS
wow64_unix_gethostbyaddr( void *args
)
1251 } const *params32
= args
;
1254 struct gethostbyaddr_params params
=
1256 ULongToPtr( params32
->addr
),
1260 ULongToPtr(params32
->size
)
1263 if (!(params
.host
= malloc( *params
.size
))) return WSAENOBUFS
;
1264 status
= unix_gethostbyaddr( ¶ms
);
1266 status
= put_hostent32( params
.host
, ULongToPtr(params32
->host
), ULongToPtr(params32
->size
) );
1267 free( params
.host
);
1272 static NTSTATUS
wow64_unix_gethostbyname( void *args
)
1279 } const *params32
= args
;
1282 struct gethostbyname_params params
=
1284 ULongToPtr( params32
->name
),
1286 ULongToPtr(params32
->size
)
1289 if (!(params
.host
= malloc( *params
.size
))) return WSAENOBUFS
;
1290 status
= unix_gethostbyname( ¶ms
);
1292 status
= put_hostent32( params
.host
, ULongToPtr(params32
->host
), ULongToPtr(params32
->size
) );
1293 free( params
.host
);
1298 static NTSTATUS
wow64_unix_gethostname( void *args
)
1304 } const *params32
= args
;
1306 struct gethostname_params params
= { ULongToPtr(params32
->name
), params32
->size
};
1308 if (!unix_gethostname( ¶ms
)) return 0;
1309 return errno_from_unix( errno
);
1313 static NTSTATUS
wow64_unix_getnameinfo( void *args
)
1324 } const *params32
= args
;
1326 struct getnameinfo_params params
=
1328 ULongToPtr( params32
->addr
),
1330 ULongToPtr( params32
->host
),
1332 ULongToPtr( params32
->serv
),
1337 return unix_getnameinfo( ¶ms
);
1340 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
1342 wow64_unix_getaddrinfo
,
1343 wow64_unix_gethostbyaddr
,
1344 wow64_unix_gethostbyname
,
1345 wow64_unix_gethostname
,
1346 wow64_unix_getnameinfo
,