ws2_32: Move getaddrinfo() support to a new Unix library.
Signed-off-by: Zebediah Figura <zfigura@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
c07da78a2e
commit
e58405000c
|
@ -7,6 +7,7 @@ EXTRALIBS = $(POLL_LIBS)
|
|||
C_SRCS = \
|
||||
async.c \
|
||||
protocol.c \
|
||||
socket.c
|
||||
socket.c \
|
||||
unixlib.c
|
||||
|
||||
RC_SRCS = version.rc
|
||||
|
|
|
@ -33,21 +33,6 @@ DECLARE_CRITICAL_SECTION(csWSgetXXXbyYYY);
|
|||
|
||||
#define MAP_OPTION(opt) { WS_##opt, opt }
|
||||
|
||||
static const int ws_aiflag_map[][2] =
|
||||
{
|
||||
MAP_OPTION( AI_PASSIVE ),
|
||||
MAP_OPTION( AI_CANONNAME ),
|
||||
MAP_OPTION( AI_NUMERICHOST ),
|
||||
#ifdef AI_NUMERICSERV
|
||||
MAP_OPTION( AI_NUMERICSERV ),
|
||||
#endif
|
||||
#ifdef AI_V4MAPPED
|
||||
MAP_OPTION( AI_V4MAPPED ),
|
||||
#endif
|
||||
MAP_OPTION( AI_ALL ),
|
||||
MAP_OPTION( AI_ADDRCONFIG ),
|
||||
};
|
||||
|
||||
static const int ws_eai_map[][2] =
|
||||
{
|
||||
MAP_OPTION( EAI_AGAIN ),
|
||||
|
@ -82,21 +67,6 @@ static const int ws_af_map[][2] =
|
|||
{FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
|
||||
};
|
||||
|
||||
static const int ws_proto_map[][2] =
|
||||
{
|
||||
MAP_OPTION( IPPROTO_IP ),
|
||||
MAP_OPTION( IPPROTO_TCP ),
|
||||
MAP_OPTION( IPPROTO_UDP ),
|
||||
MAP_OPTION( IPPROTO_IPV6 ),
|
||||
MAP_OPTION( IPPROTO_ICMP ),
|
||||
MAP_OPTION( IPPROTO_IGMP ),
|
||||
MAP_OPTION( IPPROTO_RAW ),
|
||||
{WS_IPPROTO_IPV4, IPPROTO_IPIP},
|
||||
{FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
|
||||
};
|
||||
|
||||
#define IS_IPX_PROTO(X) ((X) >= WS_NSPROTO_IPX && (X) <= WS_NSPROTO_IPX + 255)
|
||||
|
||||
static int convert_af_w2u( int family )
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -123,78 +93,6 @@ static int convert_af_u2w( int family )
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int convert_proto_w2u( int protocol )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ws_proto_map); i++)
|
||||
{
|
||||
if (ws_proto_map[i][0] == protocol)
|
||||
return ws_proto_map[i][1];
|
||||
}
|
||||
|
||||
if (IS_IPX_PROTO(protocol))
|
||||
return protocol;
|
||||
|
||||
FIXME( "unhandled Windows socket protocol %d\n", protocol );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int convert_proto_u2w( int protocol )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ws_proto_map); i++)
|
||||
{
|
||||
if (ws_proto_map[i][1] == protocol)
|
||||
return ws_proto_map[i][0];
|
||||
}
|
||||
|
||||
/* if value is inside IPX range just return it - the kernel simply
|
||||
* echoes the value used in the socket() function */
|
||||
if (IS_IPX_PROTO(protocol))
|
||||
return protocol;
|
||||
|
||||
FIXME("unhandled UNIX socket protocol %d\n", protocol);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int convert_aiflag_w2u( int winflags )
|
||||
{
|
||||
unsigned int i;
|
||||
int unixflags = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ws_aiflag_map); i++)
|
||||
{
|
||||
if (ws_aiflag_map[i][0] & winflags)
|
||||
{
|
||||
unixflags |= ws_aiflag_map[i][1];
|
||||
winflags &= ~ws_aiflag_map[i][0];
|
||||
}
|
||||
}
|
||||
if (winflags)
|
||||
FIXME( "Unhandled windows AI_xxx flags 0x%x\n", winflags );
|
||||
return unixflags;
|
||||
}
|
||||
|
||||
static int convert_aiflag_u2w( int unixflags )
|
||||
{
|
||||
unsigned int i;
|
||||
int winflags = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ws_aiflag_map); i++)
|
||||
{
|
||||
if (ws_aiflag_map[i][1] & unixflags)
|
||||
{
|
||||
winflags |= ws_aiflag_map[i][0];
|
||||
unixflags &= ~ws_aiflag_map[i][1];
|
||||
}
|
||||
}
|
||||
if (unixflags)
|
||||
WARN( "Unhandled UNIX AI_xxx flags 0x%x\n", unixflags );
|
||||
return winflags;
|
||||
}
|
||||
|
||||
int convert_eai_u2w( int unixret )
|
||||
{
|
||||
int i;
|
||||
|
@ -232,62 +130,37 @@ static char *get_fqdn(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static BOOL addrinfo_in_list( const struct WS_addrinfo *list, const struct WS_addrinfo *ai )
|
||||
{
|
||||
const struct WS_addrinfo *cursor = list;
|
||||
while (cursor)
|
||||
{
|
||||
if (ai->ai_flags == cursor->ai_flags &&
|
||||
ai->ai_family == cursor->ai_family &&
|
||||
ai->ai_socktype == cursor->ai_socktype &&
|
||||
ai->ai_protocol == cursor->ai_protocol &&
|
||||
ai->ai_addrlen == cursor->ai_addrlen &&
|
||||
!memcmp(ai->ai_addr, cursor->ai_addr, ai->ai_addrlen) &&
|
||||
((ai->ai_canonname && cursor->ai_canonname && !strcmp(ai->ai_canonname, cursor->ai_canonname))
|
||||
|| (!ai->ai_canonname && !cursor->ai_canonname)))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
cursor = cursor->ai_next;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* getaddrinfo (ws2_32.@)
|
||||
*/
|
||||
int WINAPI WS_getaddrinfo( const char *nodename, const char *servname,
|
||||
const struct WS_addrinfo *hints, struct WS_addrinfo **res )
|
||||
int WINAPI WS_getaddrinfo( const char *node, const char *service,
|
||||
const struct WS_addrinfo *hints, struct WS_addrinfo **info )
|
||||
{
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
struct addrinfo *unixaires = NULL;
|
||||
int result;
|
||||
struct addrinfo unixhints, *punixhints = NULL;
|
||||
char *nodev6 = NULL, *fqdn = NULL;
|
||||
const char *node;
|
||||
int ret;
|
||||
|
||||
*res = NULL;
|
||||
if (!nodename && !servname)
|
||||
TRACE( "node %s, service %s, hints %p\n", debugstr_a(node), debugstr_a(service), hints );
|
||||
|
||||
*info = NULL;
|
||||
|
||||
if (!node && !service)
|
||||
{
|
||||
SetLastError(WSAHOST_NOT_FOUND);
|
||||
SetLastError( WSAHOST_NOT_FOUND );
|
||||
return WSAHOST_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!nodename)
|
||||
node = NULL;
|
||||
else if (!nodename[0])
|
||||
if (node)
|
||||
{
|
||||
if (!(fqdn = get_fqdn())) return WSA_NOT_ENOUGH_MEMORY;
|
||||
node = fqdn;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = nodename;
|
||||
|
||||
/* Check for [ipv6] or [ipv6]:portnumber, which are supported by Windows */
|
||||
if (!hints || hints->ai_family == WS_AF_UNSPEC || hints->ai_family == WS_AF_INET6)
|
||||
if (!node[0])
|
||||
{
|
||||
if (!(fqdn = get_fqdn())) return WSA_NOT_ENOUGH_MEMORY;
|
||||
node = fqdn;
|
||||
}
|
||||
else if (!hints || hints->ai_family == WS_AF_UNSPEC || hints->ai_family == WS_AF_INET6)
|
||||
{
|
||||
/* [ipv6] or [ipv6]:portnumber are supported by Windows */
|
||||
char *close_bracket;
|
||||
|
||||
if (node[0] == '[' && (close_bracket = strchr(node + 1, ']')))
|
||||
|
@ -300,50 +173,9 @@ int WINAPI WS_getaddrinfo( const char *nodename, const char *servname,
|
|||
}
|
||||
}
|
||||
|
||||
/* servname tweak required by OSX and BSD kernels */
|
||||
if (servname && !servname[0]) servname = "0";
|
||||
ret = unix_funcs->getaddrinfo( node, service, hints, info );
|
||||
|
||||
if (hints)
|
||||
{
|
||||
punixhints = &unixhints;
|
||||
|
||||
memset( &unixhints, 0, sizeof(unixhints) );
|
||||
punixhints->ai_flags = convert_aiflag_w2u( hints->ai_flags );
|
||||
|
||||
/* zero is a wildcard, no need to convert */
|
||||
if (hints->ai_family)
|
||||
punixhints->ai_family = convert_af_w2u( hints->ai_family );
|
||||
if (hints->ai_socktype)
|
||||
punixhints->ai_socktype = convert_socktype_w2u( hints->ai_socktype );
|
||||
if (hints->ai_protocol)
|
||||
punixhints->ai_protocol = max( convert_proto_w2u( hints->ai_protocol ), 0 );
|
||||
|
||||
if (punixhints->ai_socktype < 0)
|
||||
{
|
||||
SetLastError( WSAESOCKTNOSUPPORT );
|
||||
HeapFree( GetProcessHeap(), 0, fqdn );
|
||||
HeapFree( GetProcessHeap(), 0, nodev6 );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* windows allows invalid combinations of socket type and protocol, unix does not.
|
||||
* fix the parameters here to make getaddrinfo call always work */
|
||||
if (punixhints->ai_protocol == IPPROTO_TCP
|
||||
&& punixhints->ai_socktype != SOCK_STREAM
|
||||
&& punixhints->ai_socktype != SOCK_SEQPACKET)
|
||||
punixhints->ai_socktype = 0;
|
||||
else if (punixhints->ai_protocol == IPPROTO_UDP && punixhints->ai_socktype != SOCK_DGRAM)
|
||||
punixhints->ai_socktype = 0;
|
||||
else if (IS_IPX_PROTO(punixhints->ai_protocol) && punixhints->ai_socktype != SOCK_DGRAM)
|
||||
punixhints->ai_socktype = 0;
|
||||
else if (punixhints->ai_protocol == IPPROTO_IPV6)
|
||||
punixhints->ai_protocol = 0;
|
||||
}
|
||||
|
||||
/* getaddrinfo(3) is thread safe, no need to wrap in CS */
|
||||
result = getaddrinfo( node, servname, punixhints, &unixaires );
|
||||
|
||||
if (result && (!hints || !(hints->ai_flags & WS_AI_NUMERICHOST)) && node)
|
||||
if (ret && (!hints || !(hints->ai_flags & WS_AI_NUMERICHOST)) && node)
|
||||
{
|
||||
if (!fqdn && !(fqdn = get_fqdn()))
|
||||
{
|
||||
|
@ -356,115 +188,33 @@ int WINAPI WS_getaddrinfo( const char *nodename, const char *servname,
|
|||
* by sending a NULL host and avoid sending a NULL servname too because that
|
||||
* is invalid */
|
||||
ERR_(winediag)( "Failed to resolve your host name IP\n" );
|
||||
result = getaddrinfo( NULL, servname ? servname : "0", punixhints, &unixaires );
|
||||
if (!result && punixhints && (punixhints->ai_flags & AI_CANONNAME) && unixaires && !unixaires->ai_canonname)
|
||||
ret = unix_funcs->getaddrinfo( NULL, service, hints, info );
|
||||
if (!ret && hints && (hints->ai_flags & WS_AI_CANONNAME) && *info && !(*info)->ai_canonname)
|
||||
{
|
||||
freeaddrinfo( unixaires );
|
||||
result = EAI_NONAME;
|
||||
WS_freeaddrinfo( *info );
|
||||
*info = NULL;
|
||||
return EAI_NONAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
TRACE( "%s, %s %p -> %p %d\n", debugstr_a(nodename), debugstr_a(servname), hints, res, result );
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, fqdn );
|
||||
HeapFree( GetProcessHeap(), 0, nodev6 );
|
||||
|
||||
if (!result)
|
||||
if (!ret && TRACE_ON(winsock))
|
||||
{
|
||||
struct addrinfo *xuai = unixaires;
|
||||
struct WS_addrinfo **xai = res;
|
||||
struct WS_addrinfo *ai;
|
||||
|
||||
*xai = NULL;
|
||||
while (xuai)
|
||||
for (ai = *info; ai != NULL; ai = ai->ai_next)
|
||||
{
|
||||
struct WS_addrinfo *ai = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct WS_addrinfo) );
|
||||
SIZE_T len;
|
||||
|
||||
if (!ai)
|
||||
goto outofmem;
|
||||
|
||||
ai->ai_flags = convert_aiflag_u2w( xuai->ai_flags );
|
||||
ai->ai_family = convert_af_u2w( xuai->ai_family );
|
||||
/* copy whatever was sent in the hints */
|
||||
if (hints)
|
||||
{
|
||||
ai->ai_socktype = hints->ai_socktype;
|
||||
ai->ai_protocol = hints->ai_protocol;
|
||||
}
|
||||
else
|
||||
{
|
||||
ai->ai_socktype = convert_socktype_u2w( xuai->ai_socktype );
|
||||
ai->ai_protocol = convert_proto_u2w( xuai->ai_protocol );
|
||||
}
|
||||
if (xuai->ai_canonname)
|
||||
{
|
||||
TRACE( "canon name - %s\n", debugstr_a(xuai->ai_canonname) );
|
||||
ai->ai_canonname = HeapAlloc( GetProcessHeap(), 0, strlen( xuai->ai_canonname ) + 1 );
|
||||
if (!ai->ai_canonname)
|
||||
goto outofmem;
|
||||
strcpy( ai->ai_canonname, xuai->ai_canonname );
|
||||
}
|
||||
len = xuai->ai_addrlen;
|
||||
ai->ai_addr = HeapAlloc( GetProcessHeap(), 0, len );
|
||||
if (!ai->ai_addr)
|
||||
goto outofmem;
|
||||
ai->ai_addrlen = len;
|
||||
do
|
||||
{
|
||||
int winlen = ai->ai_addrlen;
|
||||
|
||||
if (!ws_sockaddr_u2ws( xuai->ai_addr, ai->ai_addr, &winlen ))
|
||||
{
|
||||
ai->ai_addrlen = winlen;
|
||||
break;
|
||||
}
|
||||
len *= 2;
|
||||
ai->ai_addr = HeapReAlloc( GetProcessHeap(), 0, ai->ai_addr, len );
|
||||
if (!ai->ai_addr)
|
||||
goto outofmem;
|
||||
ai->ai_addrlen = len;
|
||||
} while (1);
|
||||
|
||||
if (addrinfo_in_list( *res, ai ))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, ai->ai_canonname );
|
||||
HeapFree( GetProcessHeap(), 0, ai->ai_addr );
|
||||
HeapFree( GetProcessHeap(), 0, ai );
|
||||
}
|
||||
else
|
||||
{
|
||||
*xai = ai;
|
||||
xai = &ai->ai_next;
|
||||
}
|
||||
xuai = xuai->ai_next;
|
||||
}
|
||||
freeaddrinfo( unixaires );
|
||||
|
||||
if (TRACE_ON(winsock))
|
||||
{
|
||||
struct WS_addrinfo *ai = *res;
|
||||
while (ai)
|
||||
{
|
||||
TRACE( "=> %p, flags %#x, family %d, type %d, protocol %d, len %ld, name %s, addr %s\n",
|
||||
ai, ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol, ai->ai_addrlen,
|
||||
ai->ai_canonname, debugstr_sockaddr(ai->ai_addr) );
|
||||
ai = ai->ai_next;
|
||||
}
|
||||
TRACE( "=> %p, flags %#x, family %d, type %d, protocol %d, len %ld, name %s, addr %s\n",
|
||||
ai, ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol, ai->ai_addrlen,
|
||||
ai->ai_canonname, debugstr_sockaddr(ai->ai_addr) );
|
||||
}
|
||||
}
|
||||
else
|
||||
result = convert_eai_u2w( result );
|
||||
|
||||
SetLastError( result );
|
||||
return result;
|
||||
|
||||
outofmem:
|
||||
if (*res) WS_freeaddrinfo( *res );
|
||||
if (unixaires) freeaddrinfo( unixaires );
|
||||
return WSA_NOT_ENOUGH_MEMORY;
|
||||
#else
|
||||
FIXME( "getaddrinfo() failed, not found during build time.\n" );
|
||||
return EAI_FAIL;
|
||||
#endif
|
||||
SetLastError( ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(winediag);
|
||||
|
||||
const struct unix_funcs *unix_funcs = NULL;
|
||||
|
||||
static const WSAPROTOCOL_INFOW supported_protocols[] =
|
||||
{
|
||||
{
|
||||
|
@ -426,14 +428,6 @@ static int ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, in
|
|||
|
||||
#define MAP_OPTION(opt) { WS_##opt, opt }
|
||||
|
||||
static const int ws_socktype_map[][2] =
|
||||
{
|
||||
MAP_OPTION( SOCK_DGRAM ),
|
||||
MAP_OPTION( SOCK_STREAM ),
|
||||
MAP_OPTION( SOCK_RAW ),
|
||||
{FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
|
||||
};
|
||||
|
||||
UINT sock_get_error( int err )
|
||||
{
|
||||
switch(err)
|
||||
|
@ -626,38 +620,20 @@ static HANDLE get_sync_event(void)
|
|||
return data->sync_event;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DllMain (WS2_32.init)
|
||||
*/
|
||||
|
||||
BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
|
||||
{
|
||||
if (reason == DLL_THREAD_DETACH)
|
||||
switch (reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
return !__wine_init_unix_lib( instance, reason, NULL, &unix_funcs );
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
free_per_thread_data();
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
convert_socktype_w2u(int windowssocktype) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ws_socktype_map); i++)
|
||||
if (ws_socktype_map[i][0] == windowssocktype)
|
||||
return ws_socktype_map[i][1];
|
||||
FIXME("unhandled Windows socket type %d\n", windowssocktype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
convert_socktype_u2w(int unixsocktype) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ws_socktype_map); i++)
|
||||
if (ws_socktype_map[i][1] == unixsocktype)
|
||||
return ws_socktype_map[i][0];
|
||||
FIXME("unhandled UNIX socket type %d\n", unixsocktype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* WSAStartup (WS2_32.115)
|
||||
|
@ -858,112 +834,6 @@ unsigned int ws_sockaddr_ws2u( const struct WS_sockaddr *wsaddr, int wsaddrlen,
|
|||
return uaddrlen;
|
||||
}
|
||||
|
||||
/* Returns 0 if successful, -1 if the buffer is too small */
|
||||
int ws_sockaddr_u2ws(const struct sockaddr *uaddr, struct WS_sockaddr *wsaddr, int *wsaddrlen)
|
||||
{
|
||||
int res;
|
||||
|
||||
switch(uaddr->sa_family)
|
||||
{
|
||||
#ifdef HAS_IPX
|
||||
case AF_IPX:
|
||||
{
|
||||
const struct sockaddr_ipx* uipx=(const struct sockaddr_ipx*)uaddr;
|
||||
struct WS_sockaddr_ipx* wsipx=(struct WS_sockaddr_ipx*)wsaddr;
|
||||
|
||||
res=-1;
|
||||
switch (*wsaddrlen) /* how much can we copy? */
|
||||
{
|
||||
default:
|
||||
res=0; /* enough */
|
||||
*wsaddrlen = sizeof(*wsipx);
|
||||
wsipx->sa_socket=uipx->sipx_port;
|
||||
/* fall through */
|
||||
case 13:
|
||||
case 12:
|
||||
memcpy(wsipx->sa_nodenum,uipx->sipx_node,sizeof(wsipx->sa_nodenum));
|
||||
/* fall through */
|
||||
case 11:
|
||||
case 10:
|
||||
case 9:
|
||||
case 8:
|
||||
case 7:
|
||||
case 6:
|
||||
memcpy(wsipx->sa_netnum,&uipx->sipx_network,sizeof(wsipx->sa_netnum));
|
||||
/* fall through */
|
||||
case 5:
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
wsipx->sa_family=WS_AF_IPX;
|
||||
/* fall through */
|
||||
case 1:
|
||||
case 0:
|
||||
/* way too small */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAS_IRDA
|
||||
case AF_IRDA: {
|
||||
const struct sockaddr_irda *uin = (const struct sockaddr_irda *)uaddr;
|
||||
SOCKADDR_IRDA *win = (SOCKADDR_IRDA *)wsaddr;
|
||||
|
||||
if (*wsaddrlen < sizeof(SOCKADDR_IRDA))
|
||||
return -1;
|
||||
win->irdaAddressFamily = WS_AF_IRDA;
|
||||
memcpy( win->irdaDeviceID, &uin->sir_addr, sizeof(win->irdaDeviceID) );
|
||||
if (uin->sir_lsap_sel != LSAP_ANY)
|
||||
sprintf( win->irdaServiceName, "LSAP-SEL%u", uin->sir_lsap_sel );
|
||||
else
|
||||
memcpy( win->irdaServiceName, uin->sir_name,
|
||||
sizeof(win->irdaServiceName) );
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
case AF_INET6: {
|
||||
const struct sockaddr_in6* uin6 = (const struct sockaddr_in6*)uaddr;
|
||||
struct WS_sockaddr_in6 *win6 = (struct WS_sockaddr_in6 *)wsaddr;
|
||||
|
||||
if (*wsaddrlen < sizeof(struct WS_sockaddr_in6))
|
||||
return -1;
|
||||
win6->sin6_family = WS_AF_INET6;
|
||||
win6->sin6_port = uin6->sin6_port;
|
||||
win6->sin6_flowinfo = uin6->sin6_flowinfo;
|
||||
memcpy(&win6->sin6_addr, &uin6->sin6_addr, 16); /* 16 bytes = 128 address bits */
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
win6->sin6_scope_id = uin6->sin6_scope_id;
|
||||
#else
|
||||
win6->sin6_scope_id = 0;
|
||||
#endif
|
||||
*wsaddrlen = sizeof(struct WS_sockaddr_in6);
|
||||
return 0;
|
||||
}
|
||||
case AF_INET: {
|
||||
const struct sockaddr_in* uin = (const struct sockaddr_in*)uaddr;
|
||||
struct WS_sockaddr_in* win = (struct WS_sockaddr_in*)wsaddr;
|
||||
|
||||
if (*wsaddrlen < sizeof(struct WS_sockaddr_in))
|
||||
return -1;
|
||||
win->sin_family = WS_AF_INET;
|
||||
win->sin_port = uin->sin_port;
|
||||
memcpy(&win->sin_addr,&uin->sin_addr,4); /* 4 bytes = 32 address bits */
|
||||
memset(win->sin_zero, 0, 8); /* Make sure the null padding is null */
|
||||
*wsaddrlen = sizeof(struct WS_sockaddr_in);
|
||||
return 0;
|
||||
}
|
||||
case AF_UNSPEC: {
|
||||
memset(wsaddr,0,*wsaddrlen);
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
FIXME("Unknown address family %d\n", uaddr->sa_family);
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static INT WS_DuplicateSocket(BOOL unicode, SOCKET s, DWORD dwProcessId, LPWSAPROTOCOL_INFOW lpProtocolInfo)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
|
|
|
@ -1740,7 +1740,7 @@ static void test_GetAddrInfoW(void)
|
|||
result = NULL;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = GetAddrInfoW(localhost, NULL, &hint, &result);
|
||||
todo_wine_if (hinttests[i].error) ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
|
||||
ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
|
||||
if (!ret)
|
||||
{
|
||||
for (p = result; p; p = p->ai_next)
|
||||
|
@ -2293,7 +2293,7 @@ static void test_getaddrinfo(void)
|
|||
result = NULL;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = getaddrinfo("localhost", NULL, &hint, &result);
|
||||
todo_wine_if (hinttests[i].error) ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
|
||||
ok(ret == hinttests[i].error, "test %d: wrong ret %d\n", i, ret);
|
||||
if (!ret)
|
||||
{
|
||||
for (p = result; p; p = p->ai_next)
|
||||
|
|
|
@ -0,0 +1,618 @@
|
|||
/*
|
||||
* Unix library functions
|
||||
*
|
||||
* Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
|
||||
* Copyright (C) 2001 Stefan Leichter
|
||||
* Copyright (C) 2004 Hans Leidekker
|
||||
* Copyright (C) 2005 Marcus Meissner
|
||||
* Copyright (C) 2006-2008 Kai Blin
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#pragma makedep unix
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETDB_H
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETIPX_IPX_H
|
||||
# include <netipx/ipx.h>
|
||||
#elif defined(HAVE_LINUX_IPX_H)
|
||||
# ifdef HAVE_ASM_TYPES_H
|
||||
# include <asm/types.h>
|
||||
# endif
|
||||
# ifdef HAVE_LINUX_TYPES_H
|
||||
# include <linux/types.h>
|
||||
# endif
|
||||
# include <linux/ipx.h>
|
||||
#endif
|
||||
#if defined(SOL_IPX) || defined(SO_DEFAULT_HEADERS)
|
||||
# define HAS_IPX
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_IRDA_H
|
||||
# ifdef HAVE_LINUX_TYPES_H
|
||||
# include <linux/types.h>
|
||||
# endif
|
||||
# include <linux/irda.h>
|
||||
# define HAS_IRDA
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winerror.h"
|
||||
#include "winternl.h"
|
||||
#include "winsock2.h"
|
||||
#include "ws2tcpip.h"
|
||||
#include "wsipx.h"
|
||||
#include "af_irda.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
#include "ws2_32_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
|
||||
|
||||
#define MAP(x) {WS_ ## x, x}
|
||||
|
||||
static const int addrinfo_flag_map[][2] =
|
||||
{
|
||||
MAP( AI_PASSIVE ),
|
||||
MAP( AI_CANONNAME ),
|
||||
MAP( AI_NUMERICHOST ),
|
||||
#ifdef AI_NUMERICSERV
|
||||
MAP( AI_NUMERICSERV ),
|
||||
#endif
|
||||
#ifdef AI_V4MAPPED
|
||||
MAP( AI_V4MAPPED ),
|
||||
#endif
|
||||
MAP( AI_ALL ),
|
||||
MAP( AI_ADDRCONFIG ),
|
||||
};
|
||||
|
||||
static const int family_map[][2] =
|
||||
{
|
||||
MAP( AF_UNSPEC ),
|
||||
MAP( AF_INET ),
|
||||
MAP( AF_INET6 ),
|
||||
#ifdef AF_IPX
|
||||
MAP( AF_IPX ),
|
||||
#endif
|
||||
#ifdef AF_IRDA
|
||||
MAP( AF_IRDA ),
|
||||
#endif
|
||||
};
|
||||
|
||||
static const int socktype_map[][2] =
|
||||
{
|
||||
MAP( SOCK_STREAM ),
|
||||
MAP( SOCK_DGRAM ),
|
||||
MAP( SOCK_RAW ),
|
||||
};
|
||||
|
||||
static const int ip_protocol_map[][2] =
|
||||
{
|
||||
MAP( IPPROTO_IP ),
|
||||
MAP( IPPROTO_TCP ),
|
||||
MAP( IPPROTO_UDP ),
|
||||
MAP( IPPROTO_IPV6 ),
|
||||
MAP( IPPROTO_ICMP ),
|
||||
MAP( IPPROTO_IGMP ),
|
||||
MAP( IPPROTO_RAW ),
|
||||
{WS_IPPROTO_IPV4, IPPROTO_IPIP},
|
||||
};
|
||||
|
||||
#undef MAP
|
||||
|
||||
static int addrinfo_flags_from_unix( int flags )
|
||||
{
|
||||
int ws_flags = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(addrinfo_flag_map); ++i)
|
||||
{
|
||||
if (flags & addrinfo_flag_map[i][1])
|
||||
{
|
||||
ws_flags |= addrinfo_flag_map[i][0];
|
||||
flags &= ~addrinfo_flag_map[i][1];
|
||||
}
|
||||
}
|
||||
|
||||
if (flags)
|
||||
FIXME( "unhandled flags %#x\n", flags );
|
||||
return ws_flags;
|
||||
}
|
||||
|
||||
static int addrinfo_flags_to_unix( int flags )
|
||||
{
|
||||
int unix_flags = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(addrinfo_flag_map); ++i)
|
||||
{
|
||||
if (flags & addrinfo_flag_map[i][0])
|
||||
{
|
||||
unix_flags |= addrinfo_flag_map[i][1];
|
||||
flags &= ~addrinfo_flag_map[i][0];
|
||||
}
|
||||
}
|
||||
|
||||
if (flags)
|
||||
FIXME( "unhandled flags %#x\n", flags );
|
||||
return unix_flags;
|
||||
}
|
||||
|
||||
static int family_from_unix( int family )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(family_map); ++i)
|
||||
{
|
||||
if (family == family_map[i][1])
|
||||
return family_map[i][0];
|
||||
}
|
||||
|
||||
FIXME( "unhandled family %u\n", family );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int family_to_unix( int family )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(family_map); ++i)
|
||||
{
|
||||
if (family == family_map[i][0])
|
||||
return family_map[i][1];
|
||||
}
|
||||
|
||||
FIXME( "unhandled family %u\n", family );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int socktype_from_unix( int type )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(socktype_map); ++i)
|
||||
{
|
||||
if (type == socktype_map[i][1])
|
||||
return socktype_map[i][0];
|
||||
}
|
||||
|
||||
FIXME( "unhandled type %u\n", type );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int socktype_to_unix( int type )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(socktype_map); ++i)
|
||||
{
|
||||
if (type == socktype_map[i][0])
|
||||
return socktype_map[i][1];
|
||||
}
|
||||
|
||||
FIXME( "unhandled type %u\n", type );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int protocol_from_unix( int protocol )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ip_protocol_map); ++i)
|
||||
{
|
||||
if (protocol == ip_protocol_map[i][1])
|
||||
return ip_protocol_map[i][0];
|
||||
}
|
||||
|
||||
if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255)
|
||||
return protocol;
|
||||
|
||||
FIXME( "unhandled protocol %u\n", protocol );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int protocol_to_unix( int protocol )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ip_protocol_map); ++i)
|
||||
{
|
||||
if (protocol == ip_protocol_map[i][0])
|
||||
return ip_protocol_map[i][1];
|
||||
}
|
||||
|
||||
if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255)
|
||||
return protocol;
|
||||
|
||||
FIXME( "unhandled protocol %u\n", protocol );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned int errno_from_unix( int err )
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case EINTR: return WSAEINTR;
|
||||
case EBADF: return WSAEBADF;
|
||||
case EPERM:
|
||||
case EACCES: return WSAEACCES;
|
||||
case EFAULT: return WSAEFAULT;
|
||||
case EINVAL: return WSAEINVAL;
|
||||
case EMFILE: return WSAEMFILE;
|
||||
case EINPROGRESS:
|
||||
case EWOULDBLOCK: return WSAEWOULDBLOCK;
|
||||
case EALREADY: return WSAEALREADY;
|
||||
case ENOTSOCK: return WSAENOTSOCK;
|
||||
case EDESTADDRREQ: return WSAEDESTADDRREQ;
|
||||
case EMSGSIZE: return WSAEMSGSIZE;
|
||||
case EPROTOTYPE: return WSAEPROTOTYPE;
|
||||
case ENOPROTOOPT: return WSAENOPROTOOPT;
|
||||
case EPROTONOSUPPORT: return WSAEPROTONOSUPPORT;
|
||||
case ESOCKTNOSUPPORT: return WSAESOCKTNOSUPPORT;
|
||||
case EOPNOTSUPP: return WSAEOPNOTSUPP;
|
||||
case EPFNOSUPPORT: return WSAEPFNOSUPPORT;
|
||||
case EAFNOSUPPORT: return WSAEAFNOSUPPORT;
|
||||
case EADDRINUSE: return WSAEADDRINUSE;
|
||||
case EADDRNOTAVAIL: return WSAEADDRNOTAVAIL;
|
||||
case ENETDOWN: return WSAENETDOWN;
|
||||
case ENETUNREACH: return WSAENETUNREACH;
|
||||
case ENETRESET: return WSAENETRESET;
|
||||
case ECONNABORTED: return WSAECONNABORTED;
|
||||
case EPIPE:
|
||||
case ECONNRESET: return WSAECONNRESET;
|
||||
case ENOBUFS: return WSAENOBUFS;
|
||||
case EISCONN: return WSAEISCONN;
|
||||
case ENOTCONN: return WSAENOTCONN;
|
||||
case ESHUTDOWN: return WSAESHUTDOWN;
|
||||
case ETOOMANYREFS: return WSAETOOMANYREFS;
|
||||
case ETIMEDOUT: return WSAETIMEDOUT;
|
||||
case ECONNREFUSED: return WSAECONNREFUSED;
|
||||
case ELOOP: return WSAELOOP;
|
||||
case ENAMETOOLONG: return WSAENAMETOOLONG;
|
||||
case EHOSTDOWN: return WSAEHOSTDOWN;
|
||||
case EHOSTUNREACH: return WSAEHOSTUNREACH;
|
||||
case ENOTEMPTY: return WSAENOTEMPTY;
|
||||
#ifdef EPROCLIM
|
||||
case EPROCLIM: return WSAEPROCLIM;
|
||||
#endif
|
||||
#ifdef EUSERS
|
||||
case EUSERS: return WSAEUSERS;
|
||||
#endif
|
||||
#ifdef EDQUOT
|
||||
case EDQUOT: return WSAEDQUOT;
|
||||
#endif
|
||||
#ifdef ESTALE
|
||||
case ESTALE: return WSAESTALE;
|
||||
#endif
|
||||
#ifdef EREMOTE
|
||||
case EREMOTE: return WSAEREMOTE;
|
||||
#endif
|
||||
default:
|
||||
FIXME( "unknown error: %s", strerror( err ) );
|
||||
return WSAEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
static int addrinfo_err_from_unix( int err )
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case EAI_AGAIN: return WS_EAI_AGAIN;
|
||||
case EAI_BADFLAGS: return WS_EAI_BADFLAGS;
|
||||
case EAI_FAIL: return WS_EAI_FAIL;
|
||||
case EAI_FAMILY: return WS_EAI_FAMILY;
|
||||
case EAI_MEMORY: return WS_EAI_MEMORY;
|
||||
/* EAI_NODATA is deprecated, but still used by Windows and Linux. We map
|
||||
* the newer EAI_NONAME to EAI_NODATA for now until Windows changes too. */
|
||||
#ifdef EAI_NODATA
|
||||
case EAI_NODATA: return WS_EAI_NODATA;
|
||||
#endif
|
||||
#ifdef EAI_NONAME
|
||||
case EAI_NONAME: return WS_EAI_NODATA;
|
||||
#endif
|
||||
case EAI_SERVICE: return WS_EAI_SERVICE;
|
||||
case EAI_SOCKTYPE: return WS_EAI_SOCKTYPE;
|
||||
case EAI_SYSTEM:
|
||||
/* some broken versions of glibc return EAI_SYSTEM and set errno to
|
||||
* 0 instead of returning EAI_NONAME */
|
||||
return errno ? errno_from_unix( errno ) : WS_EAI_NONAME;
|
||||
|
||||
default:
|
||||
FIXME( "unhandled error %d\n", err );
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
union unix_sockaddr
|
||||
{
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
#ifdef HAS_IPX
|
||||
struct sockaddr_ipx ipx;
|
||||
#endif
|
||||
#ifdef HAS_IRDA
|
||||
struct sockaddr_irda irda;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* different from the version in ntdll and server; it does not return failure if
|
||||
* given a short buffer */
|
||||
static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_sockaddr *wsaddr, socklen_t wsaddrlen )
|
||||
{
|
||||
memset( wsaddr, 0, wsaddrlen );
|
||||
|
||||
switch (uaddr->addr.sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
struct WS_sockaddr_in win = {0};
|
||||
|
||||
if (wsaddrlen >= sizeof(win))
|
||||
{
|
||||
win.sin_family = WS_AF_INET;
|
||||
win.sin_port = uaddr->in.sin_port;
|
||||
memcpy( &win.sin_addr, &uaddr->in.sin_addr, sizeof(win.sin_addr) );
|
||||
memcpy( wsaddr, &win, sizeof(win) );
|
||||
}
|
||||
return sizeof(win);
|
||||
}
|
||||
|
||||
case AF_INET6:
|
||||
{
|
||||
struct WS_sockaddr_in6 win = {0};
|
||||
|
||||
if (wsaddrlen >= sizeof(win))
|
||||
{
|
||||
win.sin6_family = WS_AF_INET6;
|
||||
win.sin6_port = uaddr->in6.sin6_port;
|
||||
win.sin6_flowinfo = uaddr->in6.sin6_flowinfo;
|
||||
memcpy( &win.sin6_addr, &uaddr->in6.sin6_addr, sizeof(win.sin6_addr) );
|
||||
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
|
||||
win.sin6_scope_id = uaddr->in6.sin6_scope_id;
|
||||
#endif
|
||||
memcpy( wsaddr, &win, sizeof(win) );
|
||||
}
|
||||
return sizeof(win);
|
||||
}
|
||||
|
||||
#ifdef HAS_IPX
|
||||
case AF_IPX:
|
||||
{
|
||||
struct WS_sockaddr_ipx win = {0};
|
||||
|
||||
if (wsaddrlen >= sizeof(win))
|
||||
{
|
||||
win.sa_family = WS_AF_IPX;
|
||||
memcpy( win.sa_netnum, &uaddr->ipx.sipx_network, sizeof(win.sa_netnum) );
|
||||
memcpy( win.sa_nodenum, &uaddr->ipx.sipx_node, sizeof(win.sa_nodenum) );
|
||||
win.sa_socket = uaddr->ipx.sipx_port;
|
||||
memcpy( wsaddr, &win, sizeof(win) );
|
||||
}
|
||||
return sizeof(win);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAS_IRDA
|
||||
case AF_IRDA:
|
||||
{
|
||||
SOCKADDR_IRDA win;
|
||||
|
||||
if (wsaddrlen >= sizeof(win))
|
||||
{
|
||||
win.irdaAddressFamily = WS_AF_IRDA;
|
||||
memcpy( win.irdaDeviceID, &uaddr->irda.sir_addr, sizeof(win.irdaDeviceID) );
|
||||
if (uaddr->irda.sir_lsap_sel != LSAP_ANY)
|
||||
snprintf( win.irdaServiceName, sizeof(win.irdaServiceName), "LSAP-SEL%u", uaddr->irda.sir_lsap_sel );
|
||||
else
|
||||
memcpy( win.irdaServiceName, uaddr->irda.sir_name, sizeof(win.irdaServiceName) );
|
||||
memcpy( wsaddr, &win, sizeof(win) );
|
||||
}
|
||||
return sizeof(win);
|
||||
}
|
||||
#endif
|
||||
|
||||
case AF_UNSPEC:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
FIXME( "unknown address family %d\n", uaddr->addr.sa_family );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL addrinfo_in_list( const struct WS_addrinfo *list, const struct WS_addrinfo *ai )
|
||||
{
|
||||
const struct WS_addrinfo *cursor = list;
|
||||
while (cursor)
|
||||
{
|
||||
if (ai->ai_flags == cursor->ai_flags &&
|
||||
ai->ai_family == cursor->ai_family &&
|
||||
ai->ai_socktype == cursor->ai_socktype &&
|
||||
ai->ai_protocol == cursor->ai_protocol &&
|
||||
ai->ai_addrlen == cursor->ai_addrlen &&
|
||||
!memcmp( ai->ai_addr, cursor->ai_addr, ai->ai_addrlen ) &&
|
||||
((ai->ai_canonname && cursor->ai_canonname && !strcmp( ai->ai_canonname, cursor->ai_canonname ))
|
||||
|| (!ai->ai_canonname && !cursor->ai_canonname)))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
cursor = cursor->ai_next;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int CDECL unix_getaddrinfo( const char *node, const char *service,
|
||||
const struct WS_addrinfo *hints, struct WS_addrinfo **info )
|
||||
{
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
struct addrinfo unix_hints = {0};
|
||||
struct addrinfo *unix_info, *src;
|
||||
struct WS_addrinfo *dst, *prev = NULL;
|
||||
int ret;
|
||||
|
||||
*info = NULL;
|
||||
|
||||
/* servname tweak required by OSX and BSD kernels */
|
||||
if (service && !service[0]) service = "0";
|
||||
|
||||
if (hints)
|
||||
{
|
||||
unix_hints.ai_flags = addrinfo_flags_to_unix( hints->ai_flags );
|
||||
|
||||
if (hints->ai_family)
|
||||
unix_hints.ai_family = family_to_unix( hints->ai_family );
|
||||
|
||||
if (hints->ai_socktype)
|
||||
{
|
||||
if ((unix_hints.ai_socktype = socktype_to_unix( hints->ai_socktype )) < 0)
|
||||
return WSAESOCKTNOSUPPORT;
|
||||
}
|
||||
|
||||
if (hints->ai_protocol)
|
||||
unix_hints.ai_protocol = max( protocol_to_unix( hints->ai_protocol ), 0 );
|
||||
|
||||
/* Windows allows some invalid combinations */
|
||||
if (unix_hints.ai_protocol == IPPROTO_TCP
|
||||
&& unix_hints.ai_socktype != SOCK_STREAM
|
||||
&& unix_hints.ai_socktype != SOCK_SEQPACKET)
|
||||
{
|
||||
WARN( "ignoring invalid type %u for TCP\n", unix_hints.ai_socktype );
|
||||
unix_hints.ai_socktype = 0;
|
||||
}
|
||||
else if (unix_hints.ai_protocol == IPPROTO_UDP && unix_hints.ai_socktype != SOCK_DGRAM)
|
||||
{
|
||||
WARN( "ignoring invalid type %u for UDP\n", unix_hints.ai_socktype );
|
||||
unix_hints.ai_socktype = 0;
|
||||
}
|
||||
else if (unix_hints.ai_protocol >= WS_NSPROTO_IPX && unix_hints.ai_protocol <= WS_NSPROTO_IPX + 255
|
||||
&& unix_hints.ai_socktype != SOCK_DGRAM)
|
||||
{
|
||||
WARN( "ignoring invalid type %u for IPX\n", unix_hints.ai_socktype );
|
||||
unix_hints.ai_socktype = 0;
|
||||
}
|
||||
else if (unix_hints.ai_protocol == IPPROTO_IPV6)
|
||||
{
|
||||
WARN( "ignoring protocol IPv6\n" );
|
||||
unix_hints.ai_protocol = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret = getaddrinfo( node, service, hints ? &unix_hints : NULL, &unix_info );
|
||||
if (ret)
|
||||
return addrinfo_err_from_unix( ret );
|
||||
|
||||
*info = NULL;
|
||||
|
||||
for (src = unix_info; src != NULL; src = src->ai_next)
|
||||
{
|
||||
if (!(dst = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dst) )))
|
||||
goto fail;
|
||||
|
||||
dst->ai_flags = addrinfo_flags_from_unix( src->ai_flags );
|
||||
dst->ai_family = family_from_unix( src->ai_family );
|
||||
if (hints)
|
||||
{
|
||||
dst->ai_socktype = hints->ai_socktype;
|
||||
dst->ai_protocol = hints->ai_protocol;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst->ai_socktype = socktype_from_unix( src->ai_socktype );
|
||||
dst->ai_protocol = protocol_from_unix( src->ai_protocol );
|
||||
}
|
||||
if (src->ai_canonname)
|
||||
{
|
||||
if (!(dst->ai_canonname = RtlAllocateHeap( GetProcessHeap(), 0, strlen( src->ai_canonname ) + 1 )))
|
||||
{
|
||||
RtlFreeHeap( GetProcessHeap(), 0, dst );
|
||||
goto fail;
|
||||
}
|
||||
strcpy( dst->ai_canonname, src->ai_canonname );
|
||||
}
|
||||
|
||||
dst->ai_addrlen = sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, NULL, 0 );
|
||||
if (!(dst->ai_addr = RtlAllocateHeap( GetProcessHeap(), 0, dst->ai_addrlen )))
|
||||
{
|
||||
RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
|
||||
RtlFreeHeap( GetProcessHeap(), 0, dst );
|
||||
goto fail;
|
||||
}
|
||||
sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, dst->ai_addr, dst->ai_addrlen );
|
||||
|
||||
if (addrinfo_in_list( *info, dst ))
|
||||
{
|
||||
RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
|
||||
RtlFreeHeap( GetProcessHeap(), 0, dst->ai_addr );
|
||||
RtlFreeHeap( GetProcessHeap(), 0, dst );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prev)
|
||||
prev->ai_next = dst;
|
||||
else
|
||||
*info = dst;
|
||||
prev = dst;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo( unix_info );
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dst = *info;
|
||||
while (dst)
|
||||
{
|
||||
struct WS_addrinfo *next;
|
||||
|
||||
RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
|
||||
RtlFreeHeap( GetProcessHeap(), 0, dst->ai_addr );
|
||||
next = dst->ai_next;
|
||||
RtlFreeHeap( GetProcessHeap(), 0, dst );
|
||||
dst = next;
|
||||
}
|
||||
return WS_EAI_MEMORY;
|
||||
#else
|
||||
FIXME( "getaddrinfo() not found during build time\n" );
|
||||
return WS_EAI_FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct unix_funcs funcs =
|
||||
{
|
||||
unix_getaddrinfo,
|
||||
};
|
||||
|
||||
NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
|
||||
{
|
||||
if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
|
||||
|
||||
*(const struct unix_funcs **)ptr_out = &funcs;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
|
@ -172,10 +172,6 @@ union generic_unix_sockaddr
|
|||
};
|
||||
|
||||
int convert_eai_u2w( int ret ) DECLSPEC_HIDDEN;
|
||||
int convert_socktype_u2w( int type ) DECLSPEC_HIDDEN;
|
||||
int convert_socktype_w2u( int type ) DECLSPEC_HIDDEN;
|
||||
int ws_sockaddr_u2ws( const struct sockaddr *unix_addr, struct WS_sockaddr *win_addr,
|
||||
int *win_addr_len ) DECLSPEC_HIDDEN;
|
||||
unsigned int ws_sockaddr_ws2u( const struct WS_sockaddr *win_addr, int win_addr_len,
|
||||
union generic_unix_sockaddr *unix_addr ) DECLSPEC_HIDDEN;
|
||||
|
||||
|
@ -200,4 +196,12 @@ extern int num_startup;
|
|||
|
||||
struct per_thread_data *get_per_thread_data(void) DECLSPEC_HIDDEN;
|
||||
|
||||
struct unix_funcs
|
||||
{
|
||||
int (CDECL *getaddrinfo)( const char *node, const char *service,
|
||||
const struct WS(addrinfo) *hints, struct WS(addrinfo) **info );
|
||||
};
|
||||
|
||||
extern const struct unix_funcs *unix_funcs;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue