ws2_32: Move host lookup functions to protocol.c.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-04-30 19:09:59 -05:00 committed by Alexandre Julliard
parent e30b16d738
commit ec9f311930
3 changed files with 520 additions and 516 deletions

View File

@ -29,6 +29,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
DECLARE_CRITICAL_SECTION(csWSgetXXXbyYYY);
#define MAP_OPTION(opt) { WS_##opt, opt }
static const int ws_aiflag_map[][2] =
@ -66,6 +68,20 @@ static const int ws_eai_map[][2] =
{ 0, 0 }
};
static const int ws_af_map[][2] =
{
MAP_OPTION( AF_UNSPEC ),
MAP_OPTION( AF_INET ),
MAP_OPTION( AF_INET6 ),
#ifdef HAS_IPX
MAP_OPTION( AF_IPX ),
#endif
#ifdef AF_IRDA
MAP_OPTION( AF_IRDA ),
#endif
{FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
};
static const int ws_proto_map[][2] =
{
MAP_OPTION( IPPROTO_IP ),
@ -81,6 +97,32 @@ static const int ws_proto_map[][2] =
#define IS_IPX_PROTO(X) ((X) >= WS_NSPROTO_IPX && (X) <= WS_NSPROTO_IPX + 255)
static int convert_af_w2u( int family )
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(ws_af_map); i++)
{
if (ws_af_map[i][0] == family)
return ws_af_map[i][1];
}
FIXME( "unhandled Windows address family %d\n", family );
return -1;
}
static int convert_af_u2w( int family )
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(ws_af_map); i++)
{
if (ws_af_map[i][1] == family)
return ws_af_map[i][0];
}
FIXME( "unhandled UNIX address family %d\n", family );
return -1;
}
static int convert_proto_w2u( int protocol )
{
unsigned int i;
@ -810,3 +852,452 @@ void WINAPI FreeAddrInfoExW( ADDRINFOEXW *ai )
ai = next;
}
}
static UINT host_errno_from_unix( int err )
{
WARN( "%d\n", err );
switch (err)
{
case HOST_NOT_FOUND: return WSAHOST_NOT_FOUND;
case TRY_AGAIN: return WSATRY_AGAIN;
case NO_RECOVERY: return WSANO_RECOVERY;
case NO_DATA: return WSANO_DATA;
case ENOBUFS: return WSAENOBUFS;
case 0: return 0;
default:
WARN( "Unknown h_errno %d!\n", err );
return WSAEOPNOTSUPP;
}
}
static struct WS_hostent *get_hostent_buffer( unsigned int size )
{
struct per_thread_data *data = get_per_thread_data();
if (data->he_buffer)
{
if (data->he_len >= size) return data->he_buffer;
HeapFree( GetProcessHeap(), 0, data->he_buffer );
}
data->he_buffer = HeapAlloc( GetProcessHeap(), 0, (data->he_len = size) );
if (!data->he_buffer) SetLastError(WSAENOBUFS);
return data->he_buffer;
}
/* create a hostent entry
*
* Creates the entry with enough memory for the name, aliases
* addresses, and the address pointers. Also copies the name
* and sets up all the pointers.
*
* NOTE: The alias and address lists must be allocated with room
* for the NULL item terminating the list. This is true even if
* the list has no items ("aliases" and "addresses" must be
* at least "1", a truly empty list is invalid).
*/
static struct WS_hostent *create_hostent( char *name, int alias_count, int aliases_size,
int address_count, int address_length )
{
struct WS_hostent *p_to;
char *p;
unsigned int size = sizeof(struct WS_hostent), i;
size += strlen(name) + 1;
size += alias_count * sizeof(char *);
size += aliases_size;
size += address_count * sizeof(char *);
size += (address_count - 1) * address_length;
if (!(p_to = get_hostent_buffer( size ))) return NULL;
memset( p_to, 0, size );
/* Use the memory in the same way winsock does.
* First set the pointer for aliases, second set the pointers for addresses.
* Third fill the addresses indexes, fourth jump aliases names size.
* Fifth fill the hostname.
* NOTE: This method is valid for OS versions >= XP.
*/
p = (char *)(p_to + 1);
p_to->h_aliases = (char **)p;
p += alias_count * sizeof(char *);
p_to->h_addr_list = (char **)p;
p += address_count * sizeof(char *);
for (i = 0, address_count--; i < address_count; i++, p += address_length)
p_to->h_addr_list[i] = p;
/* h_aliases must be filled in manually because we don't know each string
* size. Leave these pointers NULL (already set to NULL by memset earlier).
*/
p += aliases_size;
p_to->h_name = p;
strcpy( p, name );
return p_to;
}
static struct WS_hostent *hostent_from_unix( const struct hostent *p_he )
{
int i, addresses = 0, alias_size = 0;
struct WS_hostent *p_to;
char *p;
for (i = 0; p_he->h_aliases[i]; i++)
alias_size += strlen( p_he->h_aliases[i] ) + 1;
while (p_he->h_addr_list[addresses])
addresses++;
p_to = create_hostent( p_he->h_name, i + 1, alias_size, addresses + 1, p_he->h_length );
if (!p_to) return NULL;
p_to->h_addrtype = convert_af_u2w( p_he->h_addrtype );
p_to->h_length = p_he->h_length;
for (i = 0, p = p_to->h_addr_list[0]; p_he->h_addr_list[i]; i++, p += p_to->h_length)
memcpy( p, p_he->h_addr_list[i], p_to->h_length );
/* Fill the aliases after the IP data */
for (i = 0; p_he->h_aliases[i]; i++)
{
p_to->h_aliases[i] = p;
strcpy( p, p_he->h_aliases[i] );
p += strlen(p) + 1;
}
return p_to;
}
/***********************************************************************
* gethostbyaddr (ws2_32.51)
*/
struct WS_hostent * WINAPI WS_gethostbyaddr( const char *addr, int len, int type )
{
struct WS_hostent *retval = NULL;
struct hostent *host;
int unixtype = convert_af_w2u(type);
const char *paddr = addr;
unsigned long loopback;
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
char *extrabuf;
int ebufsize = 1024;
struct hostent hostentry;
int locerr = ENOBUFS;
#endif
/* convert back the magic loopback address if necessary */
if (unixtype == AF_INET && len == 4 && !memcmp( addr, magic_loopback_addr, 4 ))
{
loopback = htonl( INADDR_LOOPBACK );
paddr = (char *)&loopback;
}
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
host = NULL;
extrabuf = HeapAlloc( GetProcessHeap(), 0, ebufsize );
while (extrabuf)
{
int res = gethostbyaddr_r( paddr, len, unixtype, &hostentry, extrabuf, ebufsize, &host, &locerr );
if (res != ERANGE) break;
ebufsize *= 2;
extrabuf = HeapReAlloc( GetProcessHeap(), 0, extrabuf, ebufsize );
}
if (host)
retval = hostent_from_unix( host );
else
SetLastError( (locerr < 0) ? sock_get_error( errno ) : host_errno_from_unix( locerr ) );
HeapFree( GetProcessHeap(), 0, extrabuf );
#else
EnterCriticalSection( &csWSgetXXXbyYYY );
host = gethostbyaddr( paddr, len, unixtype );
if (host)
retval = hostent_from_unix( host );
else
SetLastError( (h_errno < 0) ? sock_get_error( errno ) : host_errno_from_unix( h_errno ) );
LeaveCriticalSection( &csWSgetXXXbyYYY );
#endif
TRACE( "ptr %p, len %d, type %d ret %p\n", addr, len, type, retval );
return retval;
}
struct route
{
struct in_addr addr;
IF_INDEX interface;
DWORD metric, default_route;
};
static int compare_routes_by_metric_asc( const void *left, const void *right )
{
const struct route *a = left, *b = right;
if (a->default_route && b->default_route)
return a->default_route - b->default_route;
if (a->default_route && !b->default_route)
return -1;
if (b->default_route && !a->default_route)
return 1;
return a->metric - b->metric;
}
/* Returns the list of local IP addresses by going through the network
* adapters and using the local routing table to sort the addresses
* from highest routing priority to lowest routing priority. This
* functionality is inferred from the description for obtaining local
* IP addresses given in the Knowledge Base Article Q160215.
*
* Please note that the returned hostent is only freed when the thread
* closes and is replaced if another hostent is requested.
*/
static struct WS_hostent *get_local_ips( char *hostname )
{
int numroutes = 0, i, j, default_routes = 0;
IP_ADAPTER_INFO *adapters = NULL, *k;
struct WS_hostent *hostlist = NULL;
MIB_IPFORWARDTABLE *routes = NULL;
struct route *route_addrs = NULL;
DWORD adap_size, route_size, n;
/* Obtain the size of the adapter list and routing table, also allocate memory */
if (GetAdaptersInfo( NULL, &adap_size ) != ERROR_BUFFER_OVERFLOW)
return NULL;
if (GetIpForwardTable( NULL, &route_size, FALSE ) != ERROR_INSUFFICIENT_BUFFER)
return NULL;
adapters = HeapAlloc( GetProcessHeap(), 0, adap_size );
routes = HeapAlloc( GetProcessHeap(), 0, route_size );
if (!adapters || !routes)
goto cleanup;
/* Obtain the adapter list and the full routing table */
if (GetAdaptersInfo( adapters, &adap_size ) != NO_ERROR)
goto cleanup;
if (GetIpForwardTable( routes, &route_size, FALSE ) != NO_ERROR)
goto cleanup;
/* Store the interface associated with each route */
for (n = 0; n < routes->dwNumEntries; n++)
{
IF_INDEX ifindex;
DWORD ifmetric, ifdefault = 0;
BOOL exists = FALSE;
/* Check if this is a default route (there may be more than one) */
if (!routes->table[n].dwForwardDest)
ifdefault = ++default_routes;
else if (routes->table[n].u1.ForwardType != MIB_IPROUTE_TYPE_DIRECT)
continue;
ifindex = routes->table[n].dwForwardIfIndex;
ifmetric = routes->table[n].dwForwardMetric1;
/* Only store the lowest valued metric for an interface */
for (j = 0; j < numroutes; j++)
{
if (route_addrs[j].interface == ifindex)
{
if (route_addrs[j].metric > ifmetric)
route_addrs[j].metric = ifmetric;
exists = TRUE;
}
}
if (exists)
continue;
route_addrs = heap_realloc( route_addrs, (numroutes + 1) * sizeof(struct route) );
if (!route_addrs)
goto cleanup;
route_addrs[numroutes].interface = ifindex;
route_addrs[numroutes].metric = ifmetric;
route_addrs[numroutes].default_route = ifdefault;
/* If no IP is found in the next step (for whatever reason)
* then fall back to the magic loopback address.
*/
memcpy( &route_addrs[numroutes].addr.s_addr, magic_loopback_addr, 4 );
numroutes++;
}
if (numroutes == 0)
goto cleanup; /* No routes, fall back to the Magic IP */
/* Find the IP address associated with each found interface */
for (i = 0; i < numroutes; i++)
{
for (k = adapters; k != NULL; k = k->Next)
{
char *ip = k->IpAddressList.IpAddress.String;
if (route_addrs[i].interface == k->Index)
route_addrs[i].addr.s_addr = inet_addr(ip);
}
}
/* Allocate a hostent and enough memory for all the IPs,
* including the NULL at the end of the list.
*/
hostlist = create_hostent( hostname, 1, 0, numroutes+1, sizeof(struct in_addr) );
if (hostlist == NULL)
goto cleanup;
hostlist->h_addr_list[numroutes] = NULL;
hostlist->h_aliases[0] = NULL;
hostlist->h_addrtype = AF_INET;
hostlist->h_length = sizeof(struct in_addr);
/* Reorder the entries before placing them in the host list. Windows expects
* the IP list in order from highest priority to lowest (the critical thing
* is that most applications expect the first IP to be the default route).
*/
if (numroutes > 1)
qsort( route_addrs, numroutes, sizeof(struct route), compare_routes_by_metric_asc );
for (i = 0; i < numroutes; i++)
*(struct in_addr *)hostlist->h_addr_list[i] = route_addrs[i].addr;
cleanup:
HeapFree( GetProcessHeap(), 0, route_addrs );
HeapFree( GetProcessHeap(), 0, adapters );
HeapFree( GetProcessHeap(), 0, routes );
return hostlist;
}
/***********************************************************************
* gethostbyname (ws2_32.52)
*/
struct WS_hostent * WINAPI WS_gethostbyname( const char *name )
{
struct WS_hostent *retval = NULL;
struct hostent *host;
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
char *extrabuf;
int ebufsize = 1024;
struct hostent hostentry;
int locerr = ENOBUFS;
#endif
char hostname[100];
if (!num_startup)
{
SetLastError( WSANOTINITIALISED );
return NULL;
}
if (gethostname( hostname, 100 ) == -1)
{
SetLastError( WSAENOBUFS );
return retval;
}
if (!name || !name[0])
name = hostname;
/* If the hostname of the local machine is requested then return the
* complete list of local IP addresses */
if (!strcmp( name, hostname ))
retval = get_local_ips( hostname );
/* If any other hostname was requested (or the routing table lookup failed)
* then return the IP found by the host OS */
if (!retval)
{
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
host = NULL;
extrabuf = HeapAlloc( GetProcessHeap(), 0, ebufsize );
while (extrabuf)
{
int res = gethostbyname_r( name, &hostentry, extrabuf, ebufsize, &host, &locerr );
if (res != ERANGE) break;
ebufsize *= 2;
extrabuf = HeapReAlloc( GetProcessHeap(), 0, extrabuf, ebufsize );
}
if (!host) SetLastError( (locerr < 0) ? sock_get_error( errno ) : host_errno_from_unix( locerr ) );
#else
EnterCriticalSection( &csWSgetXXXbyYYY );
host = gethostbyname( name );
if (!host) SetLastError( (h_errno < 0) ? sock_get_error( errno ) : host_errno_from_unix( h_errno ) );
#endif
if (host) retval = hostent_from_unix( host );
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
HeapFree( GetProcessHeap(), 0, extrabuf );
#else
LeaveCriticalSection( &csWSgetXXXbyYYY );
#endif
}
if (retval && retval->h_addr_list[0][0] == 127 && strcmp( name, "localhost" ))
{
/* hostname != "localhost" but has loopback address. replace by our
* special address.*/
memcpy( retval->h_addr_list[0], magic_loopback_addr, 4 );
}
TRACE( "%s ret %p\n", debugstr_a(name), retval );
return retval;
}
/***********************************************************************
* gethostname (ws2_32.57)
*/
int WINAPI WS_gethostname( char *name, int namelen )
{
char buf[256];
int len;
TRACE( "name %p, len %d\n", name, namelen );
if (!name)
{
SetLastError( WSAEFAULT );
return -1;
}
if (gethostname( buf, sizeof(buf) ) != 0)
{
SetLastError( sock_get_error( errno ) );
return -1;
}
TRACE( "<- %s\n", debugstr_a(buf) );
len = strlen( buf );
if (len > 15)
WARN( "Windows supports NetBIOS name length up to 15 bytes!\n" );
if (namelen <= len)
{
SetLastError( WSAEFAULT );
return -1;
}
strcpy( name, buf );
return 0;
}
/***********************************************************************
* GetHostNameW (ws2_32.@)
*/
int WINAPI GetHostNameW( WCHAR *name, int namelen )
{
char buf[256];
TRACE( "name %p, len %d\n", name, namelen );
if (!name)
{
SetLastError( WSAEFAULT );
return -1;
}
if (gethostname( buf, sizeof(buf) ))
{
SetLastError( sock_get_error( errno ) );
return -1;
}
if (MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 ) > namelen)
{
SetLastError( WSAEFAULT );
return -1;
}
MultiByteToWideChar( CP_ACP, 0, buf, -1, name, namelen );
return 0;
}

View File

@ -225,13 +225,6 @@ static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSABUF lpControlBuffer );
#define DECLARE_CRITICAL_SECTION(cs) \
static CRITICAL_SECTION cs; \
static CRITICAL_SECTION_DEBUG cs##_debug = \
{ 0, 0, &cs, { &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \
0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \
static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 }
DECLARE_CRITICAL_SECTION(csWSgetXXXbyYYY);
DECLARE_CRITICAL_SECTION(cs_if_addr_cache);
DECLARE_CRITICAL_SECTION(cs_socket_list);
@ -618,35 +611,10 @@ typedef struct /* WSAAsyncSelect() control struct */
#define WS_MAX_UDP_DATAGRAM 1024
static INT WINAPI WSA_DefaultBlockingHook( FARPROC x );
/* hostent's, servent's and protent's are stored in one buffer per thread,
* as documented on MSDN for the functions that return any of the buffers */
struct per_thread_data
{
int opentype;
struct WS_hostent *he_buffer;
struct WS_servent *se_buffer;
struct WS_protoent *pe_buffer;
struct pollfd *fd_cache;
unsigned int fd_count;
int he_len;
int se_len;
int pe_len;
char ntoa_buffer[16]; /* 4*3 digits + 3 '.' + 1 '\0' */
};
/* internal: routing description information */
struct route {
struct in_addr addr;
IF_INDEX interface;
DWORD metric, default_route;
};
static INT num_startup; /* reference counter */
int num_startup;
static FARPROC blocking_hook = (FARPROC)WSA_DefaultBlockingHook;
/* function prototypes */
static struct WS_hostent *WS_create_he(char *name, int aliases, int aliases_size, int addresses, int address_length);
static struct WS_hostent *WS_dup_he(const struct hostent* p_he);
static struct WS_protoent *WS_create_pe( const char *name, char **aliases, int prot );
static struct WS_servent *WS_dup_se(const struct servent* p_se);
static int ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, int *size);
@ -741,20 +709,6 @@ static const int ws_ipv6_map[][2] =
#endif
};
static const int ws_af_map[][2] =
{
MAP_OPTION( AF_UNSPEC ),
MAP_OPTION( AF_INET ),
MAP_OPTION( AF_INET6 ),
#ifdef HAS_IPX
MAP_OPTION( AF_IPX ),
#endif
#ifdef AF_IRDA
MAP_OPTION( AF_IRDA ),
#endif
{FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
};
static const int ws_socktype_map[][2] =
{
MAP_OPTION( SOCK_DGRAM ),
@ -783,8 +737,6 @@ static const int ws_poll_map[][2] =
{ WS_POLLRDBAND, POLLPRI }
};
static const char magic_loopback_addr[] = {127, 12, 34, 56};
#ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR)
static inline WSACMSGHDR *fill_control_message(int level, int type, WSACMSGHDR *current, ULONG *maxsize, void *data, int len)
@ -1003,25 +955,6 @@ static NTSTATUS wsaErrStatus(void)
return sock_get_ntstatus(loc_errno);
}
static UINT wsaHerrno(int loc_errno)
{
WARN("h_errno %d.\n", loc_errno);
switch(loc_errno)
{
case HOST_NOT_FOUND: return WSAHOST_NOT_FOUND;
case TRY_AGAIN: return WSATRY_AGAIN;
case NO_RECOVERY: return WSANO_RECOVERY;
case NO_DATA: return WSANO_DATA;
case ENOBUFS: return WSAENOBUFS;
case 0: return 0;
default:
WARN("Unknown h_errno %d!\n", loc_errno);
return WSAEOPNOTSUPP;
}
}
static NTSTATUS sock_error_to_ntstatus( DWORD err )
{
switch (err)
@ -1298,7 +1231,7 @@ static BOOL get_dont_fragment(SOCKET s, int level, BOOL *out)
return value;
}
static struct per_thread_data *get_per_thread_data(void)
struct per_thread_data *get_per_thread_data(void)
{
struct per_thread_data * ptb = NtCurrentTeb()->WinSockData;
/* lazy initialization */
@ -1486,28 +1419,6 @@ static inline int do_block( int fd, int events, int timeout )
return pfd.revents;
}
int
convert_af_w2u(int windowsaf) {
unsigned int i;
for (i = 0; i < ARRAY_SIZE(ws_af_map); i++)
if (ws_af_map[i][0] == windowsaf)
return ws_af_map[i][1];
FIXME("unhandled Windows address family %d\n", windowsaf);
return -1;
}
int
convert_af_u2w(int unixaf) {
unsigned int i;
for (i = 0; i < ARRAY_SIZE(ws_af_map); i++)
if (ws_af_map[i][1] == unixaf)
return ws_af_map[i][0];
FIXME("unhandled UNIX address family %d\n", unixaf);
return -1;
}
int
convert_socktype_w2u(int windowssocktype) {
unsigned int i;
@ -1669,19 +1580,6 @@ void WINAPI WSASetLastError(INT iError) {
SetLastError(iError);
}
static struct WS_hostent *check_buffer_he(int size)
{
struct per_thread_data * ptb = get_per_thread_data();
if (ptb->he_buffer)
{
if (ptb->he_len >= size ) return ptb->he_buffer;
HeapFree( GetProcessHeap(), 0, ptb->he_buffer );
}
ptb->he_buffer = HeapAlloc( GetProcessHeap(), 0, (ptb->he_len = size) );
if (!ptb->he_buffer) SetLastError(WSAENOBUFS);
return ptb->he_buffer;
}
static struct WS_servent *check_buffer_se(int size)
{
struct per_thread_data * ptb = get_per_thread_data();
@ -5854,256 +5752,6 @@ SOCKET WINAPI WS_socket(int af, int type, int protocol)
}
/***********************************************************************
* gethostbyaddr (WS2_32.51)
*/
struct WS_hostent* WINAPI WS_gethostbyaddr(const char *addr, int len, int type)
{
struct WS_hostent *retval = NULL;
struct hostent* host;
int unixtype = convert_af_w2u(type);
const char *paddr = addr;
unsigned long loopback;
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
char *extrabuf;
int ebufsize = 1024;
struct hostent hostentry;
int locerr = ENOBUFS;
#endif
/* convert back the magic loopback address if necessary */
if (unixtype == AF_INET && len == 4 && !memcmp(addr, magic_loopback_addr, 4))
{
loopback = htonl(INADDR_LOOPBACK);
paddr = (char*) &loopback;
}
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
host = NULL;
extrabuf=HeapAlloc(GetProcessHeap(),0,ebufsize) ;
while(extrabuf) {
int res = gethostbyaddr_r(paddr, len, unixtype,
&hostentry, extrabuf, ebufsize, &host, &locerr);
if (res != ERANGE) break;
ebufsize *=2;
extrabuf=HeapReAlloc(GetProcessHeap(),0,extrabuf,ebufsize) ;
}
if (host) retval = WS_dup_he(host);
else SetLastError((locerr < 0) ? wsaErrno() : wsaHerrno(locerr));
HeapFree(GetProcessHeap(),0,extrabuf);
#else
EnterCriticalSection( &csWSgetXXXbyYYY );
host = gethostbyaddr(paddr, len, unixtype);
if (host) retval = WS_dup_he(host);
else SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno(h_errno));
LeaveCriticalSection( &csWSgetXXXbyYYY );
#endif
TRACE("ptr %p, len %d, type %d ret %p\n", addr, len, type, retval);
return retval;
}
/***********************************************************************
* WS_compare_routes_by_metric_asc (INTERNAL)
*
* Comparison function for qsort(), for sorting two routes (struct route)
* by metric in ascending order.
*/
static int WS_compare_routes_by_metric_asc(const void *left, const void *right)
{
const struct route *a = left, *b = right;
if (a->default_route && b->default_route)
return a->default_route - b->default_route;
if (a->default_route && !b->default_route)
return -1;
if (b->default_route && !a->default_route)
return 1;
return a->metric - b->metric;
}
/***********************************************************************
* WS_get_local_ips (INTERNAL)
*
* Returns the list of local IP addresses by going through the network
* adapters and using the local routing table to sort the addresses
* from highest routing priority to lowest routing priority. This
* functionality is inferred from the description for obtaining local
* IP addresses given in the Knowledge Base Article Q160215.
*
* Please note that the returned hostent is only freed when the thread
* closes and is replaced if another hostent is requested.
*/
static struct WS_hostent* WS_get_local_ips( char *hostname )
{
int numroutes = 0, i, j, default_routes = 0;
DWORD n;
PIP_ADAPTER_INFO adapters = NULL, k;
struct WS_hostent *hostlist = NULL;
PMIB_IPFORWARDTABLE routes = NULL;
struct route *route_addrs = NULL;
DWORD adap_size, route_size;
/* Obtain the size of the adapter list and routing table, also allocate memory */
if (GetAdaptersInfo(NULL, &adap_size) != ERROR_BUFFER_OVERFLOW)
return NULL;
if (GetIpForwardTable(NULL, &route_size, FALSE) != ERROR_INSUFFICIENT_BUFFER)
return NULL;
adapters = HeapAlloc(GetProcessHeap(), 0, adap_size);
routes = HeapAlloc(GetProcessHeap(), 0, route_size);
if (adapters == NULL || routes == NULL)
goto cleanup;
/* Obtain the adapter list and the full routing table */
if (GetAdaptersInfo(adapters, &adap_size) != NO_ERROR)
goto cleanup;
if (GetIpForwardTable(routes, &route_size, FALSE) != NO_ERROR)
goto cleanup;
/* Store the interface associated with each route */
for (n = 0; n < routes->dwNumEntries; n++)
{
IF_INDEX ifindex;
DWORD ifmetric, ifdefault = 0;
BOOL exists = FALSE;
/* Check if this is a default route (there may be more than one) */
if (!routes->table[n].dwForwardDest)
ifdefault = ++default_routes;
else if (routes->table[n].u1.ForwardType != MIB_IPROUTE_TYPE_DIRECT)
continue;
ifindex = routes->table[n].dwForwardIfIndex;
ifmetric = routes->table[n].dwForwardMetric1;
/* Only store the lowest valued metric for an interface */
for (j = 0; j < numroutes; j++)
{
if (route_addrs[j].interface == ifindex)
{
if (route_addrs[j].metric > ifmetric)
route_addrs[j].metric = ifmetric;
exists = TRUE;
}
}
if (exists)
continue;
route_addrs = heap_realloc(route_addrs, (numroutes+1)*sizeof(struct route));
if (route_addrs == NULL)
goto cleanup; /* Memory allocation error, fail gracefully */
route_addrs[numroutes].interface = ifindex;
route_addrs[numroutes].metric = ifmetric;
route_addrs[numroutes].default_route = ifdefault;
/* If no IP is found in the next step (for whatever reason)
* then fall back to the magic loopback address.
*/
memcpy(&(route_addrs[numroutes].addr.s_addr), magic_loopback_addr, 4);
numroutes++;
}
if (numroutes == 0)
goto cleanup; /* No routes, fall back to the Magic IP */
/* Find the IP address associated with each found interface */
for (i = 0; i < numroutes; i++)
{
for (k = adapters; k != NULL; k = k->Next)
{
char *ip = k->IpAddressList.IpAddress.String;
if (route_addrs[i].interface == k->Index)
route_addrs[i].addr.s_addr = (in_addr_t) inet_addr(ip);
}
}
/* Allocate a hostent and enough memory for all the IPs,
* including the NULL at the end of the list.
*/
hostlist = WS_create_he(hostname, 1, 0, numroutes+1, sizeof(struct in_addr));
if (hostlist == NULL)
goto cleanup; /* Failed to allocate a hostent for the list of IPs */
hostlist->h_addr_list[numroutes] = NULL; /* NULL-terminate the address list */
hostlist->h_aliases[0] = NULL; /* NULL-terminate the alias list */
hostlist->h_addrtype = AF_INET;
hostlist->h_length = sizeof(struct in_addr); /* = 4 */
/* Reorder the entries before placing them in the host list. Windows expects
* the IP list in order from highest priority to lowest (the critical thing
* is that most applications expect the first IP to be the default route).
*/
if (numroutes > 1)
qsort(route_addrs, numroutes, sizeof(struct route), WS_compare_routes_by_metric_asc);
for (i = 0; i < numroutes; i++)
(*(struct in_addr *) hostlist->h_addr_list[i]) = route_addrs[i].addr;
/* Cleanup all allocated memory except the address list,
* the address list is used by the calling app.
*/
cleanup:
HeapFree(GetProcessHeap(), 0, route_addrs);
HeapFree(GetProcessHeap(), 0, adapters);
HeapFree(GetProcessHeap(), 0, routes);
return hostlist;
}
/***********************************************************************
* gethostbyname (WS2_32.52)
*/
struct WS_hostent* WINAPI WS_gethostbyname(const char* name)
{
struct WS_hostent *retval = NULL;
struct hostent* host;
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
char *extrabuf;
int ebufsize=1024;
struct hostent hostentry;
int locerr = ENOBUFS;
#endif
char hostname[100];
if(!num_startup) {
SetLastError(WSANOTINITIALISED);
return NULL;
}
if( gethostname( hostname, 100) == -1) {
SetLastError(WSAENOBUFS); /* appropriate ? */
return retval;
}
if( !name || !name[0]) {
name = hostname;
}
/* If the hostname of the local machine is requested then return the
* complete list of local IP addresses */
if(strcmp(name, hostname) == 0)
retval = WS_get_local_ips(hostname);
/* If any other hostname was requested (or the routing table lookup failed)
* then return the IP found by the host OS */
if(retval == NULL)
{
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
host = NULL;
extrabuf=HeapAlloc(GetProcessHeap(),0,ebufsize) ;
while(extrabuf) {
int res = gethostbyname_r(name, &hostentry, extrabuf, ebufsize, &host, &locerr);
if( res != ERANGE) break;
ebufsize *=2;
extrabuf=HeapReAlloc(GetProcessHeap(),0,extrabuf,ebufsize) ;
}
if (!host) SetLastError((locerr < 0) ? wsaErrno() : wsaHerrno(locerr));
#else
EnterCriticalSection( &csWSgetXXXbyYYY );
host = gethostbyname(name);
if (!host) SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno(h_errno));
#endif
if (host) retval = WS_dup_he(host);
#ifdef HAVE_LINUX_GETHOSTBYNAME_R_6
HeapFree(GetProcessHeap(),0,extrabuf);
#else
LeaveCriticalSection( &csWSgetXXXbyYYY );
#endif
}
if (retval && retval->h_addr_list[0][0] == 127 &&
strcmp(name, "localhost") != 0)
{
/* hostname != "localhost" but has loopback address. replace by our
* special address.*/
memcpy(retval->h_addr_list[0], magic_loopback_addr, 4);
}
TRACE( "%s ret %p\n", debugstr_a(name), retval );
return retval;
}
static const struct { int prot; const char *names[3]; } protocols[] =
{
{ 0, { "ip", "IP" }},
@ -6303,77 +5951,6 @@ struct WS_servent* WINAPI WS_getservbyport(int port, const char *proto)
}
/***********************************************************************
* gethostname (WS2_32.57)
*/
int WINAPI WS_gethostname(char *name, int namelen)
{
char buf[256];
int len;
TRACE("name %p, len %d\n", name, namelen);
if (!name)
{
SetLastError(WSAEFAULT);
return SOCKET_ERROR;
}
if (gethostname(buf, sizeof(buf)) != 0)
{
SetLastError(wsaErrno());
return SOCKET_ERROR;
}
TRACE("<- '%s'\n", buf);
len = strlen(buf);
if (len > 15)
WARN("Windows supports NetBIOS name length up to 15 bytes!\n");
if (namelen <= len)
{
SetLastError(WSAEFAULT);
WARN("<- not enough space for hostname, required %d, got %d!\n", len + 1, namelen);
return SOCKET_ERROR;
}
strcpy(name, buf);
return 0;
}
/***********************************************************************
* GetHostNameW (WS2_32.@)
*/
int WINAPI GetHostNameW(WCHAR *name, int namelen)
{
char buf[256];
int len;
TRACE("name %p, len %d\n", name, namelen);
if (!name)
{
SetLastError(WSAEFAULT);
return SOCKET_ERROR;
}
if (gethostname(buf, sizeof(buf)))
{
SetLastError(wsaErrno());
return SOCKET_ERROR;
}
if ((len = MultiByteToWideChar(CP_ACP, 0, buf, -1, NULL, 0)) > namelen)
{
SetLastError(WSAEFAULT);
return SOCKET_ERROR;
}
MultiByteToWideChar(CP_ACP, 0, buf, -1, name, namelen);
return 0;
}
/* ------------------------------------- Windows sockets extensions -- *
* *
* ------------------------------------------------------------------- */
/***********************************************************************
* WSAEnumNetworkEvents (WS2_32.36)
*/
@ -6815,95 +6392,6 @@ static int list_dup(char** l_src, char** l_to, int item_size)
return p - (char *)l_to;
}
/* ----- hostent */
/* create a hostent entry
*
* Creates the entry with enough memory for the name, aliases
* addresses, and the address pointers. Also copies the name
* and sets up all the pointers.
*
* NOTE: The alias and address lists must be allocated with room
* for the NULL item terminating the list. This is true even if
* the list has no items ("aliases" and "addresses" must be
* at least "1", a truly empty list is invalid).
*/
static struct WS_hostent *WS_create_he(char *name, int aliases, int aliases_size, int addresses, int address_length)
{
struct WS_hostent *p_to;
char *p;
int size = (sizeof(struct WS_hostent) +
strlen(name) + 1 +
sizeof(char *) * aliases +
aliases_size +
sizeof(char *) * addresses +
address_length * (addresses - 1)), i;
if (!(p_to = check_buffer_he(size))) return NULL;
memset(p_to, 0, size);
/* Use the memory in the same way winsock does.
* First set the pointer for aliases, second set the pointers for addresses.
* Third fill the addresses indexes, fourth jump aliases names size.
* Fifth fill the hostname.
* NOTE: This method is valid for OS versions >= XP.
*/
p = (char *)(p_to + 1);
p_to->h_aliases = (char **)p;
p += sizeof(char *)*aliases;
p_to->h_addr_list = (char **)p;
p += sizeof(char *)*addresses;
for (i = 0, addresses--; i < addresses; i++, p += address_length)
p_to->h_addr_list[i] = p;
/* NOTE: h_aliases must be filled in manually because we don't know each string
* size, leave these pointers NULL (already set to NULL by memset earlier).
*/
p += aliases_size;
p_to->h_name = p;
strcpy(p, name);
return p_to;
}
/* duplicate hostent entry
* and handle all Win16/Win32 dependent things (struct size, ...) *correctly*.
* Ditto for protoent and servent.
*/
static struct WS_hostent *WS_dup_he(const struct hostent* p_he)
{
int i, addresses = 0, alias_size = 0;
struct WS_hostent *p_to;
char *p;
for( i = 0; p_he->h_aliases[i]; i++) alias_size += strlen(p_he->h_aliases[i]) + 1;
while (p_he->h_addr_list[addresses]) addresses++;
p_to = WS_create_he(p_he->h_name, i + 1, alias_size, addresses + 1, p_he->h_length);
if (!p_to) return NULL;
p_to->h_addrtype = convert_af_u2w(p_he->h_addrtype);
p_to->h_length = p_he->h_length;
for(i = 0, p = p_to->h_addr_list[0]; p_he->h_addr_list[i]; i++, p += p_to->h_length)
memcpy(p, p_he->h_addr_list[i], p_to->h_length);
/* Fill the aliases after the IP data */
for(i = 0; p_he->h_aliases[i]; i++)
{
p_to->h_aliases[i] = p;
strcpy(p, p_he->h_aliases[i]);
p += strlen(p) + 1;
}
return p_to;
}
/* ----- protoent */
static struct WS_protoent *WS_create_pe( const char *name, char **aliases, int prot )
{
struct WS_protoent *ret;

View File

@ -152,8 +152,15 @@
#include "wine/unicode.h"
#include "wine/heap.h"
int convert_af_u2w( int family ) DECLSPEC_HIDDEN;
int convert_af_w2u( int family ) DECLSPEC_HIDDEN;
#define DECLARE_CRITICAL_SECTION(cs) \
static CRITICAL_SECTION cs; \
static CRITICAL_SECTION_DEBUG cs##_debug = \
{ 0, 0, &cs, { &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \
0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \
static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 }
static const char magic_loopback_addr[] = {127, 12, 34, 56};
int convert_eai_u2w( int ret ) DECLSPEC_HIDDEN;
int convert_socktype_u2w( int type ) DECLSPEC_HIDDEN;
int convert_socktype_w2u( int type ) DECLSPEC_HIDDEN;
@ -164,4 +171,22 @@ const char *debugstr_sockaddr( const struct WS_sockaddr *addr ) DECLSPEC_HIDDEN;
UINT sock_get_error( int err ) DECLSPEC_HIDDEN;
struct per_thread_data
{
int opentype;
struct WS_hostent *he_buffer;
struct WS_servent *se_buffer;
struct WS_protoent *pe_buffer;
struct pollfd *fd_cache;
unsigned int fd_count;
int he_len;
int se_len;
int pe_len;
char ntoa_buffer[16]; /* 4*3 digits + 3 '.' + 1 '\0' */
};
extern int num_startup;
struct per_thread_data *get_per_thread_data(void) DECLSPEC_HIDDEN;
#endif