Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/protocol.c | 492 +++++++++++++++++++++++++++++++++ dlls/ws2_32/socket.c | 516 +---------------------------------- dlls/ws2_32/ws2_32_private.h | 29 +- 3 files changed, 521 insertions(+), 516 deletions(-)
diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c index 7bf994b501f..5bbcdee3e0c 100644 --- a/dlls/ws2_32/protocol.c +++ b/dlls/ws2_32/protocol.c @@ -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,453 @@ 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; +} + diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 9e48fe256fd..7313741e4b1 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -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; diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h index 8af23b11ded..121ce25ad1d 100644 --- a/dlls/ws2_32/ws2_32_private.h +++ b/dlls/ws2_32/ws2_32_private.h @@ -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