ws2_32: Move getaddrinfo() and related functions to a separate file.
Signed-off-by: Zebediah Figura <z.figura12@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
cf1e6d3f3f
commit
e30b16d738
|
@ -6,6 +6,7 @@ EXTRALIBS = $(POLL_LIBS)
|
|||
|
||||
C_SRCS = \
|
||||
async.c \
|
||||
protocol.c \
|
||||
socket.c
|
||||
|
||||
RC_SRCS = version.rc
|
||||
|
|
|
@ -0,0 +1,812 @@
|
|||
/*
|
||||
* Protocol-level socket 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ws2_32_private.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(winediag);
|
||||
|
||||
#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 ),
|
||||
MAP_OPTION( EAI_BADFLAGS ),
|
||||
MAP_OPTION( EAI_FAIL ),
|
||||
MAP_OPTION( EAI_FAMILY ),
|
||||
MAP_OPTION( EAI_MEMORY ),
|
||||
/* Note: 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
|
||||
MAP_OPTION( EAI_NODATA ),
|
||||
#endif
|
||||
#ifdef EAI_NONAME
|
||||
{ WS_EAI_NODATA, EAI_NONAME },
|
||||
#endif
|
||||
MAP_OPTION( EAI_SERVICE ),
|
||||
MAP_OPTION( EAI_SOCKTYPE ),
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
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_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;
|
||||
|
||||
if (!unixret) return 0;
|
||||
|
||||
for (i = 0; ws_eai_map[i][0]; i++)
|
||||
{
|
||||
if (ws_eai_map[i][1] == unixret)
|
||||
return ws_eai_map[i][0];
|
||||
}
|
||||
|
||||
if (unixret == EAI_SYSTEM)
|
||||
/* There are broken versions of glibc which return EAI_SYSTEM
|
||||
* and set errno to 0 instead of returning EAI_NONAME. */
|
||||
return errno ? sock_get_error( errno ) : WS_EAI_NONAME;
|
||||
|
||||
FIXME("Unhandled unix EAI_xxx ret %d\n", unixret);
|
||||
return unixret;
|
||||
}
|
||||
|
||||
static char *get_fqdn(void)
|
||||
{
|
||||
char *ret;
|
||||
DWORD size = 0;
|
||||
|
||||
GetComputerNameExA( ComputerNamePhysicalDnsFullyQualified, NULL, &size );
|
||||
if (GetLastError() != ERROR_MORE_DATA) return NULL;
|
||||
if (!(ret = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
|
||||
if (!GetComputerNameExA( ComputerNamePhysicalDnsFullyQualified, ret, &size ))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, ret );
|
||||
return NULL;
|
||||
}
|
||||
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 )
|
||||
{
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
struct addrinfo *unixaires = NULL;
|
||||
int result;
|
||||
struct addrinfo unixhints, *punixhints = NULL;
|
||||
char *nodev6 = NULL, *fqdn = NULL;
|
||||
const char *node;
|
||||
|
||||
*res = NULL;
|
||||
if (!nodename && !servname)
|
||||
{
|
||||
SetLastError(WSAHOST_NOT_FOUND);
|
||||
return WSAHOST_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!nodename)
|
||||
node = NULL;
|
||||
else if (!nodename[0])
|
||||
{
|
||||
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)
|
||||
{
|
||||
char *close_bracket;
|
||||
|
||||
if (node[0] == '[' && (close_bracket = strchr(node + 1, ']')))
|
||||
{
|
||||
nodev6 = HeapAlloc( GetProcessHeap(), 0, close_bracket - node );
|
||||
if (!nodev6) return WSA_NOT_ENOUGH_MEMORY;
|
||||
lstrcpynA( nodev6, node + 1, close_bracket - node );
|
||||
node = nodev6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* servname tweak required by OSX and BSD kernels */
|
||||
if (servname && !servname[0]) servname = "0";
|
||||
|
||||
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 (!fqdn && !(fqdn = get_fqdn()))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, nodev6 );
|
||||
return WSA_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
if (!strcmp( fqdn, node ) || (!strncmp( fqdn, node, strlen( node ) ) && fqdn[strlen( node )] == '.'))
|
||||
{
|
||||
/* If it didn't work it means the host name IP is not in /etc/hosts, try again
|
||||
* 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)
|
||||
{
|
||||
freeaddrinfo( unixaires );
|
||||
result = 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)
|
||||
{
|
||||
struct addrinfo *xuai = unixaires;
|
||||
struct WS_addrinfo **xai = res;
|
||||
|
||||
*xai = NULL;
|
||||
while (xuai)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
static ADDRINFOEXW *addrinfo_AtoW( const struct WS_addrinfo *ai )
|
||||
{
|
||||
ADDRINFOEXW *ret;
|
||||
|
||||
if (!(ret = HeapAlloc( GetProcessHeap(), 0, sizeof(ADDRINFOEXW) ))) return NULL;
|
||||
ret->ai_flags = ai->ai_flags;
|
||||
ret->ai_family = ai->ai_family;
|
||||
ret->ai_socktype = ai->ai_socktype;
|
||||
ret->ai_protocol = ai->ai_protocol;
|
||||
ret->ai_addrlen = ai->ai_addrlen;
|
||||
ret->ai_canonname = NULL;
|
||||
ret->ai_addr = NULL;
|
||||
ret->ai_blob = NULL;
|
||||
ret->ai_bloblen = 0;
|
||||
ret->ai_provider = NULL;
|
||||
ret->ai_next = NULL;
|
||||
if (ai->ai_canonname)
|
||||
{
|
||||
int len = MultiByteToWideChar( CP_ACP, 0, ai->ai_canonname, -1, NULL, 0 );
|
||||
if (!(ret->ai_canonname = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, ret );
|
||||
return NULL;
|
||||
}
|
||||
MultiByteToWideChar( CP_ACP, 0, ai->ai_canonname, -1, ret->ai_canonname, len );
|
||||
}
|
||||
if (ai->ai_addr)
|
||||
{
|
||||
if (!(ret->ai_addr = HeapAlloc( GetProcessHeap(), 0, ai->ai_addrlen )))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, ret->ai_canonname );
|
||||
HeapFree( GetProcessHeap(), 0, ret );
|
||||
return NULL;
|
||||
}
|
||||
memcpy( ret->ai_addr, ai->ai_addr, ai->ai_addrlen );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ADDRINFOEXW *addrinfo_list_AtoW( const struct WS_addrinfo *info )
|
||||
{
|
||||
ADDRINFOEXW *ret, *infoW;
|
||||
|
||||
if (!(ret = infoW = addrinfo_AtoW( info ))) return NULL;
|
||||
while (info->ai_next)
|
||||
{
|
||||
if (!(infoW->ai_next = addrinfo_AtoW( info->ai_next )))
|
||||
{
|
||||
FreeAddrInfoExW( ret );
|
||||
return NULL;
|
||||
}
|
||||
infoW = infoW->ai_next;
|
||||
info = info->ai_next;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct WS_addrinfo *addrinfo_WtoA( const struct WS_addrinfoW *ai )
|
||||
{
|
||||
struct WS_addrinfo *ret;
|
||||
|
||||
if (!(ret = HeapAlloc( GetProcessHeap(), 0, sizeof(struct WS_addrinfo) ))) return NULL;
|
||||
ret->ai_flags = ai->ai_flags;
|
||||
ret->ai_family = ai->ai_family;
|
||||
ret->ai_socktype = ai->ai_socktype;
|
||||
ret->ai_protocol = ai->ai_protocol;
|
||||
ret->ai_addrlen = ai->ai_addrlen;
|
||||
ret->ai_canonname = NULL;
|
||||
ret->ai_addr = NULL;
|
||||
ret->ai_next = NULL;
|
||||
if (ai->ai_canonname)
|
||||
{
|
||||
int len = WideCharToMultiByte( CP_ACP, 0, ai->ai_canonname, -1, NULL, 0, NULL, NULL );
|
||||
if (!(ret->ai_canonname = HeapAlloc( GetProcessHeap(), 0, len )))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, ret );
|
||||
return NULL;
|
||||
}
|
||||
WideCharToMultiByte( CP_ACP, 0, ai->ai_canonname, -1, ret->ai_canonname, len, NULL, NULL );
|
||||
}
|
||||
if (ai->ai_addr)
|
||||
{
|
||||
if (!(ret->ai_addr = HeapAlloc( GetProcessHeap(), 0, sizeof(struct WS_sockaddr) )))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, ret->ai_canonname );
|
||||
HeapFree( GetProcessHeap(), 0, ret );
|
||||
return NULL;
|
||||
}
|
||||
memcpy( ret->ai_addr, ai->ai_addr, sizeof(struct WS_sockaddr) );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct getaddrinfo_args
|
||||
{
|
||||
OVERLAPPED *overlapped;
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine;
|
||||
ADDRINFOEXW **result;
|
||||
char *nodename;
|
||||
char *servname;
|
||||
};
|
||||
|
||||
static void WINAPI getaddrinfo_callback(TP_CALLBACK_INSTANCE *instance, void *context)
|
||||
{
|
||||
struct getaddrinfo_args *args = context;
|
||||
OVERLAPPED *overlapped = args->overlapped;
|
||||
HANDLE event = overlapped->hEvent;
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine = args->completion_routine;
|
||||
struct WS_addrinfo *res;
|
||||
int ret;
|
||||
|
||||
ret = WS_getaddrinfo( args->nodename, args->servname, NULL, &res );
|
||||
if (res)
|
||||
{
|
||||
*args->result = addrinfo_list_AtoW(res);
|
||||
overlapped->u.Pointer = args->result;
|
||||
WS_freeaddrinfo(res);
|
||||
}
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, args->nodename );
|
||||
HeapFree( GetProcessHeap(), 0, args->servname );
|
||||
HeapFree( GetProcessHeap(), 0, args );
|
||||
|
||||
overlapped->Internal = ret;
|
||||
if (completion_routine) completion_routine( ret, 0, overlapped );
|
||||
if (event) SetEvent( event );
|
||||
}
|
||||
|
||||
static int WS_getaddrinfoW( const WCHAR *nodename, const WCHAR *servname,
|
||||
const struct WS_addrinfo *hints, ADDRINFOEXW **res, OVERLAPPED *overlapped,
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine )
|
||||
{
|
||||
int ret = EAI_MEMORY, len, i;
|
||||
char *nodenameA = NULL, *servnameA = NULL;
|
||||
struct WS_addrinfo *resA;
|
||||
WCHAR *local_nodenameW = (WCHAR *)nodename;
|
||||
|
||||
*res = NULL;
|
||||
if (nodename)
|
||||
{
|
||||
/* Is this an IDN? Most likely if any char is above the Ascii table, this
|
||||
* is the simplest validation possible, further validation will be done by
|
||||
* the native getaddrinfo() */
|
||||
for (i = 0; nodename[i]; i++)
|
||||
{
|
||||
if (nodename[i] > 'z')
|
||||
break;
|
||||
}
|
||||
if (nodename[i])
|
||||
{
|
||||
if (hints && (hints->ai_flags & WS_AI_DISABLE_IDN_ENCODING))
|
||||
{
|
||||
/* Name requires conversion but it was disabled */
|
||||
ret = WSAHOST_NOT_FOUND;
|
||||
SetLastError( ret );
|
||||
goto end;
|
||||
}
|
||||
|
||||
len = IdnToAscii( 0, nodename, -1, NULL, 0 );
|
||||
if (!len)
|
||||
{
|
||||
ERR("Failed to convert %s to punycode\n", debugstr_w(nodename));
|
||||
ret = EAI_FAIL;
|
||||
goto end;
|
||||
}
|
||||
if (!(local_nodenameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) goto end;
|
||||
IdnToAscii( 0, nodename, -1, local_nodenameW, len );
|
||||
}
|
||||
}
|
||||
if (local_nodenameW)
|
||||
{
|
||||
len = WideCharToMultiByte( CP_ACP, 0, local_nodenameW, -1, NULL, 0, NULL, NULL );
|
||||
if (!(nodenameA = HeapAlloc( GetProcessHeap(), 0, len ))) goto end;
|
||||
WideCharToMultiByte( CP_ACP, 0, local_nodenameW, -1, nodenameA, len, NULL, NULL );
|
||||
}
|
||||
if (servname)
|
||||
{
|
||||
len = WideCharToMultiByte( CP_ACP, 0, servname, -1, NULL, 0, NULL, NULL );
|
||||
if (!(servnameA = HeapAlloc( GetProcessHeap(), 0, len ))) goto end;
|
||||
WideCharToMultiByte( CP_ACP, 0, servname, -1, servnameA, len, NULL, NULL );
|
||||
}
|
||||
|
||||
if (overlapped)
|
||||
{
|
||||
struct getaddrinfo_args *args;
|
||||
|
||||
if (overlapped->hEvent && completion_routine)
|
||||
{
|
||||
ret = WSAEINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(args = HeapAlloc( GetProcessHeap(), 0, sizeof(*args) ))) goto end;
|
||||
args->overlapped = overlapped;
|
||||
args->completion_routine = completion_routine;
|
||||
args->result = res;
|
||||
args->nodename = nodenameA;
|
||||
args->servname = servnameA;
|
||||
|
||||
overlapped->Internal = WSAEINPROGRESS;
|
||||
if (!TrySubmitThreadpoolCallback( getaddrinfo_callback, args, NULL ))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, args );
|
||||
ret = GetLastError();
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (local_nodenameW != nodename)
|
||||
HeapFree( GetProcessHeap(), 0, local_nodenameW );
|
||||
SetLastError( ERROR_IO_PENDING );
|
||||
return ERROR_IO_PENDING;
|
||||
}
|
||||
|
||||
ret = WS_getaddrinfo( nodenameA, servnameA, hints, &resA );
|
||||
if (!ret)
|
||||
{
|
||||
*res = addrinfo_list_AtoW( resA );
|
||||
WS_freeaddrinfo( resA );
|
||||
}
|
||||
|
||||
end:
|
||||
if (local_nodenameW != nodename)
|
||||
HeapFree( GetProcessHeap(), 0, local_nodenameW );
|
||||
HeapFree( GetProcessHeap(), 0, nodenameA );
|
||||
HeapFree( GetProcessHeap(), 0, servnameA );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetAddrInfoExW (ws2_32.@)
|
||||
*/
|
||||
int WINAPI GetAddrInfoExW( const WCHAR *name, const WCHAR *servname, DWORD namespace,
|
||||
GUID *namespace_id, const ADDRINFOEXW *hints, ADDRINFOEXW **result,
|
||||
struct WS_timeval *timeout, OVERLAPPED *overlapped,
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine, HANDLE *handle )
|
||||
{
|
||||
int ret;
|
||||
|
||||
TRACE( "name %s, servname %s, namespace %u, namespace_id %s)\n",
|
||||
debugstr_w(name), debugstr_w(servname), namespace, debugstr_guid(namespace_id) );
|
||||
|
||||
if (namespace != NS_DNS)
|
||||
FIXME( "Unsupported namespace %u\n", namespace );
|
||||
if (namespace_id)
|
||||
FIXME( "Unsupported namespace_id %s\n", debugstr_guid(namespace_id) );
|
||||
if (hints)
|
||||
FIXME( "Unsupported hints\n" );
|
||||
if (timeout)
|
||||
FIXME( "Unsupported timeout\n" );
|
||||
if (handle)
|
||||
FIXME( "Unsupported cancel handle\n" );
|
||||
|
||||
ret = WS_getaddrinfoW( name, servname, NULL, result, overlapped, completion_routine );
|
||||
if (ret) return ret;
|
||||
if (handle) *handle = (HANDLE)0xdeadbeef;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetAddrInfoExOverlappedResult (ws2_32.@)
|
||||
*/
|
||||
int WINAPI GetAddrInfoExOverlappedResult( OVERLAPPED *overlapped )
|
||||
{
|
||||
TRACE( "(%p)\n", overlapped );
|
||||
return overlapped->Internal;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetAddrInfoExCancel (ws2_32.@)
|
||||
*/
|
||||
int WINAPI GetAddrInfoExCancel( HANDLE *handle )
|
||||
{
|
||||
FIXME( "(%p)\n", handle );
|
||||
return WSA_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetAddrInfoW (ws2_32.@)
|
||||
*/
|
||||
int WINAPI GetAddrInfoW(const WCHAR *nodename, const WCHAR *servname, const ADDRINFOW *hints, ADDRINFOW **res)
|
||||
{
|
||||
struct WS_addrinfo *hintsA = NULL;
|
||||
ADDRINFOEXW *resex;
|
||||
int ret = EAI_MEMORY;
|
||||
|
||||
TRACE( "nodename %s, servname %s, hints %p, result %p\n",
|
||||
debugstr_w(nodename), debugstr_w(servname), hints, res );
|
||||
|
||||
*res = NULL;
|
||||
if (hints) hintsA = addrinfo_WtoA( hints );
|
||||
ret = WS_getaddrinfoW( nodename, servname, hintsA, &resex, NULL, NULL );
|
||||
WS_freeaddrinfo( hintsA );
|
||||
if (ret) return ret;
|
||||
|
||||
if (resex)
|
||||
{
|
||||
/* ADDRINFOEXW has a layout compatible with ADDRINFOW except for the
|
||||
* ai_next field, so we may convert it in place */
|
||||
*res = (ADDRINFOW *)resex;
|
||||
do
|
||||
{
|
||||
((ADDRINFOW *)resex)->ai_next = (ADDRINFOW *)resex->ai_next;
|
||||
resex = resex->ai_next;
|
||||
} while (resex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* freeaddrinfo (ws2_32.@)
|
||||
*/
|
||||
void WINAPI WS_freeaddrinfo( struct WS_addrinfo *res )
|
||||
{
|
||||
while (res)
|
||||
{
|
||||
struct WS_addrinfo *next;
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, res->ai_canonname );
|
||||
HeapFree( GetProcessHeap(), 0, res->ai_addr );
|
||||
next = res->ai_next;
|
||||
HeapFree( GetProcessHeap(), 0, res );
|
||||
res = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* FreeAddrInfoW (ws2_32.@)
|
||||
*/
|
||||
void WINAPI FreeAddrInfoW( ADDRINFOW *ai )
|
||||
{
|
||||
while (ai)
|
||||
{
|
||||
ADDRINFOW *next;
|
||||
HeapFree( GetProcessHeap(), 0, ai->ai_canonname );
|
||||
HeapFree( GetProcessHeap(), 0, ai->ai_addr );
|
||||
next = ai->ai_next;
|
||||
HeapFree( GetProcessHeap(), 0, ai );
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* FreeAddrInfoEx (ws2_32.@)
|
||||
*/
|
||||
void WINAPI FreeAddrInfoEx( ADDRINFOEXA *ai )
|
||||
{
|
||||
TRACE( "(%p)\n", ai );
|
||||
|
||||
while (ai)
|
||||
{
|
||||
ADDRINFOEXA *next;
|
||||
HeapFree( GetProcessHeap(), 0, ai->ai_canonname );
|
||||
HeapFree( GetProcessHeap(), 0, ai->ai_addr );
|
||||
next = ai->ai_next;
|
||||
HeapFree( GetProcessHeap(), 0, ai );
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* FreeAddrInfoExW (ws2_32.@)
|
||||
*/
|
||||
void WINAPI FreeAddrInfoExW( ADDRINFOEXW *ai )
|
||||
{
|
||||
TRACE( "(%p)\n", ai );
|
||||
|
||||
while (ai)
|
||||
{
|
||||
ADDRINFOEXW *next;
|
||||
HeapFree( GetProcessHeap(), 0, ai->ai_canonname );
|
||||
HeapFree( GetProcessHeap(), 0, ai->ai_addr );
|
||||
next = ai->ai_next;
|
||||
HeapFree( GetProcessHeap(), 0, ai );
|
||||
ai = next;
|
||||
}
|
||||
}
|
|
@ -29,138 +29,7 @@
|
|||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <limits.h>
|
||||
#ifdef HAVE_SYS_IPC_H
|
||||
# include <sys/ipc.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_FILIO_H
|
||||
# include <sys/filio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKIO_H
|
||||
# include <sys/sockio.h>
|
||||
#endif
|
||||
|
||||
#if defined(__EMX__)
|
||||
# include <sys/so_ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_MSG_H
|
||||
# include <sys/msg.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_TCP_H
|
||||
# include <netinet/tcp.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_ARPA_NAMESER_H
|
||||
# include <arpa/nameser.h>
|
||||
#endif
|
||||
#ifdef HAVE_RESOLV_H
|
||||
# include <resolv.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_H
|
||||
# include <net/if.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_FILTER_H
|
||||
# include <linux/filter.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
|
||||
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_POLL_H
|
||||
# include <sys/poll.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
#include "winerror.h"
|
||||
#include "winnls.h"
|
||||
#include "winsock2.h"
|
||||
#include "mswsock.h"
|
||||
#include "ws2tcpip.h"
|
||||
#include "ws2spi.h"
|
||||
#include "wsipx.h"
|
||||
#include "wsnwlink.h"
|
||||
#include "wshisotp.h"
|
||||
#include "mstcpip.h"
|
||||
#include "af_irda.h"
|
||||
#include "winnt.h"
|
||||
#define USE_WC_PREFIX /* For CMSG_DATA */
|
||||
#include "iphlpapi.h"
|
||||
#include "ip2string.h"
|
||||
#include "wine/afd.h"
|
||||
#include "wine/server.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/exception.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/heap.h"
|
||||
#include "ws2_32_private.h"
|
||||
|
||||
#if defined(linux) && !defined(IP_UNICAST_IF)
|
||||
#define IP_UNICAST_IF 50
|
||||
|
@ -300,8 +169,6 @@ static const WSAPROTOCOL_INFOW supported_protocols[] =
|
|||
},
|
||||
};
|
||||
|
||||
#define IS_IPX_PROTO(X) ((X) >= WS_NSPROTO_IPX && (X) <= WS_NSPROTO_IPX + 255)
|
||||
|
||||
#if defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER)
|
||||
# define LINUX_BOUND_IF
|
||||
struct interface_filter {
|
||||
|
@ -381,7 +248,7 @@ union generic_unix_sockaddr
|
|||
char data[128]; /* should be big enough for all families */
|
||||
};
|
||||
|
||||
static inline const char *debugstr_sockaddr( const struct WS_sockaddr *a )
|
||||
const char *debugstr_sockaddr( const struct WS_sockaddr *a )
|
||||
{
|
||||
if (!a) return "(nil)";
|
||||
switch (a->sa_family)
|
||||
|
@ -896,34 +763,6 @@ static const int ws_socktype_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},
|
||||
};
|
||||
|
||||
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_niflag_map[][2] =
|
||||
{
|
||||
MAP_OPTION( NI_NOFQDN ),
|
||||
|
@ -933,30 +772,6 @@ static const int ws_niflag_map[][2] =
|
|||
MAP_OPTION( NI_DGRAM ),
|
||||
};
|
||||
|
||||
static const int ws_eai_map[][2] =
|
||||
{
|
||||
MAP_OPTION( EAI_AGAIN ),
|
||||
MAP_OPTION( EAI_BADFLAGS ),
|
||||
MAP_OPTION( EAI_FAIL ),
|
||||
MAP_OPTION( EAI_FAMILY ),
|
||||
MAP_OPTION( EAI_MEMORY ),
|
||||
/* Note: 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
|
||||
MAP_OPTION( EAI_NODATA ),
|
||||
#endif
|
||||
#ifdef EAI_NONAME
|
||||
{ WS_EAI_NODATA, EAI_NONAME },
|
||||
#endif
|
||||
|
||||
MAP_OPTION( EAI_SERVICE ),
|
||||
MAP_OPTION( EAI_SOCKTYPE ),
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static const int ws_poll_map[][2] =
|
||||
{
|
||||
MAP_OPTION( POLLERR ),
|
||||
|
@ -1103,7 +918,7 @@ static NTSTATUS sock_get_ntstatus( int err )
|
|||
}
|
||||
}
|
||||
|
||||
static UINT sock_get_error( int err )
|
||||
UINT sock_get_error( int err )
|
||||
{
|
||||
switch(err)
|
||||
{
|
||||
|
@ -1671,7 +1486,7 @@ static inline int do_block( int fd, int events, int timeout )
|
|||
return pfd.revents;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
convert_af_w2u(int windowsaf) {
|
||||
unsigned int i;
|
||||
|
||||
|
@ -1682,7 +1497,7 @@ convert_af_w2u(int windowsaf) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
convert_af_u2w(int unixaf) {
|
||||
unsigned int i;
|
||||
|
||||
|
@ -1693,40 +1508,7 @@ convert_af_u2w(int unixaf) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
convert_proto_w2u(int windowsproto) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ws_proto_map); i++)
|
||||
if (ws_proto_map[i][0] == windowsproto)
|
||||
return ws_proto_map[i][1];
|
||||
|
||||
/* check for extended IPX */
|
||||
if (IS_IPX_PROTO(windowsproto))
|
||||
return windowsproto;
|
||||
|
||||
FIXME("unhandled Windows socket protocol %d\n", windowsproto);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
convert_proto_u2w(int unixproto) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ws_proto_map); i++)
|
||||
if (ws_proto_map[i][1] == unixproto)
|
||||
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(unixproto))
|
||||
return unixproto;
|
||||
|
||||
FIXME("unhandled UNIX socket protocol %d\n", unixproto);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
convert_socktype_w2u(int windowssocktype) {
|
||||
unsigned int i;
|
||||
|
||||
|
@ -1737,7 +1519,7 @@ convert_socktype_w2u(int windowssocktype) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
convert_socktype_u2w(int unixsocktype) {
|
||||
unsigned int i;
|
||||
|
||||
|
@ -2130,7 +1912,7 @@ static int is_fd_bound(int fd, union generic_unix_sockaddr *uaddr, socklen_t *ua
|
|||
}
|
||||
|
||||
/* Returns 0 if successful, -1 if the buffer is too small */
|
||||
static int ws_sockaddr_u2ws(const struct sockaddr* uaddr, struct WS_sockaddr* wsaddr, int* wsaddrlen)
|
||||
int ws_sockaddr_u2ws(const struct sockaddr *uaddr, struct WS_sockaddr *wsaddr, int *wsaddrlen)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
@ -6430,37 +6212,6 @@ struct WS_servent* WINAPI WS_getservbyname(const char *name, const char *proto)
|
|||
return retval;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* freeaddrinfo (WS2_32.@)
|
||||
*/
|
||||
void WINAPI WS_freeaddrinfo(struct WS_addrinfo *res)
|
||||
{
|
||||
while (res) {
|
||||
struct WS_addrinfo *next;
|
||||
|
||||
HeapFree(GetProcessHeap(),0,res->ai_canonname);
|
||||
HeapFree(GetProcessHeap(),0,res->ai_addr);
|
||||
next = res->ai_next;
|
||||
HeapFree(GetProcessHeap(),0,res);
|
||||
res = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* helper functions for getaddrinfo()/getnameinfo() */
|
||||
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_niflag_w2u(int winflags) {
|
||||
unsigned int i;
|
||||
int unixflags = 0;
|
||||
|
@ -6475,631 +6226,6 @@ static int convert_niflag_w2u(int 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;
|
||||
}
|
||||
|
||||
static int convert_eai_u2w(int unixret) {
|
||||
int i;
|
||||
|
||||
if (!unixret) return 0;
|
||||
|
||||
for (i=0;ws_eai_map[i][0];i++)
|
||||
if (ws_eai_map[i][1] == unixret)
|
||||
return ws_eai_map[i][0];
|
||||
|
||||
if (unixret == EAI_SYSTEM)
|
||||
/* There are broken versions of glibc which return EAI_SYSTEM
|
||||
* and set errno to 0 instead of returning EAI_NONAME.
|
||||
*/
|
||||
return errno ? sock_get_error( errno ) : WS_EAI_NONAME;
|
||||
|
||||
FIXME("Unhandled unix EAI_xxx ret %d\n", unixret);
|
||||
return unixret;
|
||||
}
|
||||
|
||||
static char *get_fqdn(void)
|
||||
{
|
||||
char *ret;
|
||||
DWORD size = 0;
|
||||
|
||||
GetComputerNameExA( ComputerNamePhysicalDnsFullyQualified, NULL, &size );
|
||||
if (GetLastError() != ERROR_MORE_DATA) return NULL;
|
||||
if (!(ret = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL;
|
||||
if (!GetComputerNameExA( ComputerNamePhysicalDnsFullyQualified, ret, &size ))
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, ret );
|
||||
return NULL;
|
||||
}
|
||||
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(LPCSTR nodename, LPCSTR servname, const struct WS_addrinfo *hints, struct WS_addrinfo **res)
|
||||
{
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
struct addrinfo *unixaires = NULL;
|
||||
int result;
|
||||
struct addrinfo unixhints, *punixhints = NULL;
|
||||
char *nodeV6 = NULL, *fqdn = NULL;
|
||||
const char *node;
|
||||
|
||||
*res = NULL;
|
||||
if (!nodename && !servname)
|
||||
{
|
||||
SetLastError(WSAHOST_NOT_FOUND);
|
||||
return WSAHOST_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!nodename)
|
||||
node = NULL;
|
||||
else if (!nodename[0])
|
||||
{
|
||||
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)
|
||||
{
|
||||
char *close_bracket;
|
||||
|
||||
if (node[0] == '[' && (close_bracket = strchr(node + 1, ']')))
|
||||
{
|
||||
nodeV6 = HeapAlloc(GetProcessHeap(), 0, close_bracket - node);
|
||||
if (!nodeV6) return WSA_NOT_ENOUGH_MEMORY;
|
||||
lstrcpynA(nodeV6, node + 1, close_bracket - node);
|
||||
node = nodeV6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* servname tweak required by OSX and BSD kernels */
|
||||
if (servname && !servname[0]) servname = "0";
|
||||
|
||||
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 SOCKET_ERROR;
|
||||
}
|
||||
|
||||
/* 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 (!fqdn && !(fqdn = get_fqdn()))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, nodeV6);
|
||||
return WSA_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
if (!strcmp(fqdn, node) || (!strncmp(fqdn, node, strlen(node)) && fqdn[strlen(node)] == '.'))
|
||||
{
|
||||
/* If it didn't work it means the host name IP is not in /etc/hosts, try again
|
||||
* 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)
|
||||
{
|
||||
freeaddrinfo(unixaires);
|
||||
result = 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) {
|
||||
struct addrinfo *xuai = unixaires;
|
||||
struct WS_addrinfo **xai = res;
|
||||
|
||||
*xai = NULL;
|
||||
while (xuai) {
|
||||
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*len;
|
||||
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;
|
||||
}
|
||||
}
|
||||
} 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 buildtime.\n");
|
||||
return EAI_FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static ADDRINFOEXW *addrinfo_AtoW(const struct WS_addrinfo *ai)
|
||||
{
|
||||
ADDRINFOEXW *ret;
|
||||
|
||||
if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ADDRINFOEXW)))) return NULL;
|
||||
ret->ai_flags = ai->ai_flags;
|
||||
ret->ai_family = ai->ai_family;
|
||||
ret->ai_socktype = ai->ai_socktype;
|
||||
ret->ai_protocol = ai->ai_protocol;
|
||||
ret->ai_addrlen = ai->ai_addrlen;
|
||||
ret->ai_canonname = NULL;
|
||||
ret->ai_addr = NULL;
|
||||
ret->ai_blob = NULL;
|
||||
ret->ai_bloblen = 0;
|
||||
ret->ai_provider = NULL;
|
||||
ret->ai_next = NULL;
|
||||
if (ai->ai_canonname)
|
||||
{
|
||||
int len = MultiByteToWideChar(CP_ACP, 0, ai->ai_canonname, -1, NULL, 0);
|
||||
if (!(ret->ai_canonname = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR))))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, ret);
|
||||
return NULL;
|
||||
}
|
||||
MultiByteToWideChar(CP_ACP, 0, ai->ai_canonname, -1, ret->ai_canonname, len);
|
||||
}
|
||||
if (ai->ai_addr)
|
||||
{
|
||||
if (!(ret->ai_addr = HeapAlloc(GetProcessHeap(), 0, ai->ai_addrlen)))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, ret->ai_canonname);
|
||||
HeapFree(GetProcessHeap(), 0, ret);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ret->ai_addr, ai->ai_addr, ai->ai_addrlen);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ADDRINFOEXW *addrinfo_list_AtoW(const struct WS_addrinfo *info)
|
||||
{
|
||||
ADDRINFOEXW *ret, *infoW;
|
||||
|
||||
if (!(ret = infoW = addrinfo_AtoW(info))) return NULL;
|
||||
while (info->ai_next)
|
||||
{
|
||||
if (!(infoW->ai_next = addrinfo_AtoW(info->ai_next)))
|
||||
{
|
||||
FreeAddrInfoExW(ret);
|
||||
return NULL;
|
||||
}
|
||||
infoW = infoW->ai_next;
|
||||
info = info->ai_next;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct WS_addrinfo *addrinfo_WtoA(const struct WS_addrinfoW *ai)
|
||||
{
|
||||
struct WS_addrinfo *ret;
|
||||
|
||||
if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct WS_addrinfo)))) return NULL;
|
||||
ret->ai_flags = ai->ai_flags;
|
||||
ret->ai_family = ai->ai_family;
|
||||
ret->ai_socktype = ai->ai_socktype;
|
||||
ret->ai_protocol = ai->ai_protocol;
|
||||
ret->ai_addrlen = ai->ai_addrlen;
|
||||
ret->ai_canonname = NULL;
|
||||
ret->ai_addr = NULL;
|
||||
ret->ai_next = NULL;
|
||||
if (ai->ai_canonname)
|
||||
{
|
||||
int len = WideCharToMultiByte(CP_ACP, 0, ai->ai_canonname, -1, NULL, 0, NULL, NULL);
|
||||
if (!(ret->ai_canonname = HeapAlloc(GetProcessHeap(), 0, len)))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, ret);
|
||||
return NULL;
|
||||
}
|
||||
WideCharToMultiByte(CP_ACP, 0, ai->ai_canonname, -1, ret->ai_canonname, len, NULL, NULL);
|
||||
}
|
||||
if (ai->ai_addr)
|
||||
{
|
||||
if (!(ret->ai_addr = HeapAlloc(GetProcessHeap(), 0, sizeof(struct WS_sockaddr))))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, ret->ai_canonname);
|
||||
HeapFree(GetProcessHeap(), 0, ret);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ret->ai_addr, ai->ai_addr, sizeof(struct WS_sockaddr));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct getaddrinfo_args
|
||||
{
|
||||
OVERLAPPED *overlapped;
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine;
|
||||
ADDRINFOEXW **result;
|
||||
char *nodename;
|
||||
char *servname;
|
||||
};
|
||||
|
||||
static void WINAPI getaddrinfo_callback(TP_CALLBACK_INSTANCE *instance, void *context)
|
||||
{
|
||||
struct getaddrinfo_args *args = context;
|
||||
OVERLAPPED *overlapped = args->overlapped;
|
||||
HANDLE event = overlapped->hEvent;
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine = args->completion_routine;
|
||||
struct WS_addrinfo *res;
|
||||
int ret;
|
||||
|
||||
ret = WS_getaddrinfo(args->nodename, args->servname, NULL, &res);
|
||||
if (res)
|
||||
{
|
||||
*args->result = addrinfo_list_AtoW(res);
|
||||
overlapped->u.Pointer = args->result;
|
||||
WS_freeaddrinfo(res);
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, args->nodename);
|
||||
HeapFree(GetProcessHeap(), 0, args->servname);
|
||||
HeapFree(GetProcessHeap(), 0, args);
|
||||
|
||||
overlapped->Internal = ret;
|
||||
if (completion_routine) completion_routine(ret, 0, overlapped);
|
||||
if (event) SetEvent(event);
|
||||
}
|
||||
|
||||
static int WS_getaddrinfoW(const WCHAR *nodename, const WCHAR *servname, const struct WS_addrinfo *hints, ADDRINFOEXW **res,
|
||||
OVERLAPPED *overlapped, LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine)
|
||||
{
|
||||
int ret = EAI_MEMORY, len, i;
|
||||
char *nodenameA = NULL, *servnameA = NULL;
|
||||
struct WS_addrinfo *resA;
|
||||
WCHAR *local_nodenameW = (WCHAR *)nodename;
|
||||
|
||||
*res = NULL;
|
||||
if (nodename)
|
||||
{
|
||||
/* Is this an IDN? Most likely if any char is above the Ascii table, this
|
||||
* is the simplest validation possible, further validation will be done by
|
||||
* the native getaddrinfo() */
|
||||
for (i = 0; nodename[i]; i++)
|
||||
{
|
||||
if (nodename[i] > 'z')
|
||||
break;
|
||||
}
|
||||
if (nodename[i])
|
||||
{
|
||||
if (hints && (hints->ai_flags & WS_AI_DISABLE_IDN_ENCODING))
|
||||
{
|
||||
/* Name requires conversion but it was disabled */
|
||||
ret = WSAHOST_NOT_FOUND;
|
||||
WSASetLastError(ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
len = IdnToAscii(0, nodename, -1, NULL, 0);
|
||||
if (!len)
|
||||
{
|
||||
ERR("Failed to convert %s to punycode\n", debugstr_w(nodename));
|
||||
ret = EAI_FAIL;
|
||||
goto end;
|
||||
}
|
||||
if (!(local_nodenameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) goto end;
|
||||
IdnToAscii(0, nodename, -1, local_nodenameW, len);
|
||||
}
|
||||
}
|
||||
if (local_nodenameW)
|
||||
{
|
||||
len = WideCharToMultiByte(CP_ACP, 0, local_nodenameW, -1, NULL, 0, NULL, NULL);
|
||||
if (!(nodenameA = HeapAlloc(GetProcessHeap(), 0, len))) goto end;
|
||||
WideCharToMultiByte(CP_ACP, 0, local_nodenameW, -1, nodenameA, len, NULL, NULL);
|
||||
}
|
||||
if (servname)
|
||||
{
|
||||
len = WideCharToMultiByte(CP_ACP, 0, servname, -1, NULL, 0, NULL, NULL);
|
||||
if (!(servnameA = HeapAlloc(GetProcessHeap(), 0, len))) goto end;
|
||||
WideCharToMultiByte(CP_ACP, 0, servname, -1, servnameA, len, NULL, NULL);
|
||||
}
|
||||
|
||||
if (overlapped)
|
||||
{
|
||||
struct getaddrinfo_args *args;
|
||||
|
||||
if (overlapped->hEvent && completion_routine)
|
||||
{
|
||||
ret = WSAEINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(args = HeapAlloc(GetProcessHeap(), 0, sizeof(*args)))) goto end;
|
||||
args->overlapped = overlapped;
|
||||
args->completion_routine = completion_routine;
|
||||
args->result = res;
|
||||
args->nodename = nodenameA;
|
||||
args->servname = servnameA;
|
||||
|
||||
overlapped->Internal = WSAEINPROGRESS;
|
||||
if (!TrySubmitThreadpoolCallback(getaddrinfo_callback, args, NULL))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, args);
|
||||
ret = GetLastError();
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (local_nodenameW != nodename)
|
||||
HeapFree(GetProcessHeap(), 0, local_nodenameW);
|
||||
WSASetLastError(ERROR_IO_PENDING);
|
||||
return ERROR_IO_PENDING;
|
||||
}
|
||||
|
||||
ret = WS_getaddrinfo(nodenameA, servnameA, hints, &resA);
|
||||
if (!ret)
|
||||
{
|
||||
*res = addrinfo_list_AtoW(resA);
|
||||
WS_freeaddrinfo(resA);
|
||||
}
|
||||
|
||||
end:
|
||||
if (local_nodenameW != nodename)
|
||||
HeapFree(GetProcessHeap(), 0, local_nodenameW);
|
||||
HeapFree(GetProcessHeap(), 0, nodenameA);
|
||||
HeapFree(GetProcessHeap(), 0, servnameA);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* GetAddrInfoExW (WS2_32.@)
|
||||
*/
|
||||
int WINAPI GetAddrInfoExW(const WCHAR *name, const WCHAR *servname, DWORD namespace, GUID *namespace_id,
|
||||
const ADDRINFOEXW *hints, ADDRINFOEXW **result, struct WS_timeval *timeout, OVERLAPPED *overlapped,
|
||||
LPLOOKUPSERVICE_COMPLETION_ROUTINE completion_routine, HANDLE *handle)
|
||||
{
|
||||
int ret;
|
||||
|
||||
TRACE("(%s %s %x %s %p %p %p %p %p %p)\n", debugstr_w(name), debugstr_w(servname), namespace,
|
||||
debugstr_guid(namespace_id), hints, result, timeout, overlapped, completion_routine, handle);
|
||||
|
||||
if (namespace != NS_DNS)
|
||||
FIXME("Unsupported namespace %u\n", namespace);
|
||||
if (namespace_id)
|
||||
FIXME("Unsupported naemspace_id %s\n", debugstr_guid(namespace_id));
|
||||
if (hints)
|
||||
FIXME("Unsupported hints\n");
|
||||
if (timeout)
|
||||
FIXME("Unsupported timeout\n");
|
||||
if (handle)
|
||||
FIXME("Unsupported cancel handle\n");
|
||||
|
||||
ret = WS_getaddrinfoW(name, servname, NULL, result, overlapped, completion_routine);
|
||||
if (ret) return ret;
|
||||
if (handle) *handle = (HANDLE)0xdeadbeef;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* GetAddrInfoExOverlappedResult (WS2_32.@)
|
||||
*/
|
||||
int WINAPI GetAddrInfoExOverlappedResult(OVERLAPPED *overlapped)
|
||||
{
|
||||
TRACE("(%p)\n", overlapped);
|
||||
return overlapped->Internal;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* GetAddrInfoExCancel (WS2_32.@)
|
||||
*/
|
||||
int WINAPI GetAddrInfoExCancel(HANDLE *handle)
|
||||
{
|
||||
FIXME("(%p)\n", handle);
|
||||
return WSA_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* GetAddrInfoW (WS2_32.@)
|
||||
*/
|
||||
int WINAPI GetAddrInfoW(LPCWSTR nodename, LPCWSTR servname, const ADDRINFOW *hints, PADDRINFOW *res)
|
||||
{
|
||||
struct WS_addrinfo *hintsA = NULL;
|
||||
ADDRINFOEXW *resex;
|
||||
int ret = EAI_MEMORY;
|
||||
|
||||
TRACE("nodename %s, servname %s, hints %p, result %p\n",
|
||||
debugstr_w(nodename), debugstr_w(servname), hints, res);
|
||||
|
||||
*res = NULL;
|
||||
if (hints) hintsA = addrinfo_WtoA(hints);
|
||||
ret = WS_getaddrinfoW(nodename, servname, hintsA, &resex, NULL, NULL);
|
||||
WS_freeaddrinfo(hintsA);
|
||||
if (ret) return ret;
|
||||
|
||||
if (resex)
|
||||
{
|
||||
/* ADDRINFOEXW has layout compatible with ADDRINFOW except for ai_next field,
|
||||
* so we may convert it in place */
|
||||
*res = (ADDRINFOW*)resex;
|
||||
do {
|
||||
((ADDRINFOW*)resex)->ai_next = (ADDRINFOW*)resex->ai_next;
|
||||
resex = resex->ai_next;
|
||||
} while (resex);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* FreeAddrInfoW (WS2_32.@)
|
||||
*/
|
||||
void WINAPI FreeAddrInfoW(PADDRINFOW ai)
|
||||
{
|
||||
while (ai)
|
||||
{
|
||||
ADDRINFOW *next;
|
||||
HeapFree(GetProcessHeap(), 0, ai->ai_canonname);
|
||||
HeapFree(GetProcessHeap(), 0, ai->ai_addr);
|
||||
next = ai->ai_next;
|
||||
HeapFree(GetProcessHeap(), 0, ai);
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* FreeAddrInfoEx (WS2_32.@)
|
||||
*/
|
||||
void WINAPI FreeAddrInfoEx(ADDRINFOEXA *ai)
|
||||
{
|
||||
TRACE("(%p)\n", ai);
|
||||
|
||||
while (ai)
|
||||
{
|
||||
ADDRINFOEXA *next;
|
||||
HeapFree(GetProcessHeap(), 0, ai->ai_canonname);
|
||||
HeapFree(GetProcessHeap(), 0, ai->ai_addr);
|
||||
next = ai->ai_next;
|
||||
HeapFree(GetProcessHeap(), 0, ai);
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* FreeAddrInfoExW (WS2_32.@)
|
||||
*/
|
||||
void WINAPI FreeAddrInfoExW(ADDRINFOEXW *ai)
|
||||
{
|
||||
TRACE("(%p)\n", ai);
|
||||
|
||||
while (ai)
|
||||
{
|
||||
ADDRINFOEXW *next;
|
||||
HeapFree(GetProcessHeap(), 0, ai->ai_canonname);
|
||||
HeapFree(GetProcessHeap(), 0, ai->ai_addr);
|
||||
next = ai->ai_next;
|
||||
HeapFree(GetProcessHeap(), 0, ai);
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
|
||||
int WINAPI WS_getnameinfo(const SOCKADDR *sa, WS_socklen_t salen, PCHAR host,
|
||||
DWORD hostlen, PCHAR serv, DWORD servlen, INT flags)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* Copyright (C) 2021 Zebediah Figura for CodeWeavers
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __WINE_WS2_32_PRIVATE_H
|
||||
#define __WINE_WS2_32_PRIVATE_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <limits.h>
|
||||
#ifdef HAVE_SYS_IPC_H
|
||||
# include <sys/ipc.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_FILIO_H
|
||||
# include <sys/filio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKIO_H
|
||||
# include <sys/sockio.h>
|
||||
#endif
|
||||
|
||||
#if defined(__EMX__)
|
||||
# include <sys/so_ioctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_MSG_H
|
||||
# include <sys/msg.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
# include <sys/uio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETINET_TCP_H
|
||||
# include <netinet/tcp.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_ARPA_NAMESER_H
|
||||
# include <arpa/nameser.h>
|
||||
#endif
|
||||
#ifdef HAVE_RESOLV_H
|
||||
# include <resolv.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_H
|
||||
# include <net/if.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_FILTER_H
|
||||
# include <linux/filter.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
|
||||
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_POLL_H
|
||||
# include <sys/poll.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
#include "winerror.h"
|
||||
#include "winnls.h"
|
||||
#include "winsock2.h"
|
||||
#include "mswsock.h"
|
||||
#include "ws2tcpip.h"
|
||||
#include "ws2spi.h"
|
||||
#include "wsipx.h"
|
||||
#include "wsnwlink.h"
|
||||
#include "wshisotp.h"
|
||||
#include "mstcpip.h"
|
||||
#include "af_irda.h"
|
||||
#include "winnt.h"
|
||||
#define USE_WC_PREFIX /* For CMSG_DATA */
|
||||
#include "iphlpapi.h"
|
||||
#include "ip2string.h"
|
||||
#include "wine/afd.h"
|
||||
#include "wine/server.h"
|
||||
#include "wine/debug.h"
|
||||
#include "wine/exception.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "wine/heap.h"
|
||||
|
||||
int convert_af_u2w( int family ) DECLSPEC_HIDDEN;
|
||||
int convert_af_w2u( int family ) DECLSPEC_HIDDEN;
|
||||
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;
|
||||
|
||||
const char *debugstr_sockaddr( const struct WS_sockaddr *addr ) DECLSPEC_HIDDEN;
|
||||
|
||||
UINT sock_get_error( int err ) DECLSPEC_HIDDEN;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue