Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ws2_32/Makefile.in | 2 +- dlls/ws2_32/protocol.c | 267 ++++++++++++++++++++++++++++++---------- 2 files changed, 203 insertions(+), 66 deletions(-)
diff --git a/dlls/ws2_32/Makefile.in b/dlls/ws2_32/Makefile.in index 77983bba66f..691c8fe1d65 100644 --- a/dlls/ws2_32/Makefile.in +++ b/dlls/ws2_32/Makefile.in @@ -1,7 +1,7 @@ EXTRADEFS = -DUSE_WS_PREFIX MODULE = ws2_32.dll IMPORTLIB = ws2_32 -DELAYIMPORTS = iphlpapi user32 +DELAYIMPORTS = advapi32 iphlpapi user32 EXTRALIBS = $(POLL_LIBS)
C_SRCS = \ diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c index 8b39d5c3274..6c3ab8ea4ce 100644 --- a/dlls/ws2_32/protocol.c +++ b/dlls/ws2_32/protocol.c @@ -981,33 +981,71 @@ static int list_dup( char **src, char **dst, int item_size ) return p - (char *)dst; }
-static const struct -{ - int prot; - const char *names[3]; -} -protocols[] = -{ - { 0, {"ip", "IP"}}, - { 1, {"icmp", "ICMP"}}, - { 3, {"ggp", "GGP"}}, - { 6, {"tcp", "TCP"}}, - { 8, {"egp", "EGP"}}, - {12, {"pup", "PUP"}}, - {17, {"udp", "UDP"}}, - {20, {"hmp", "HMP"}}, - {22, {"xns-idp", "XNS-IDP"}}, - {27, {"rdp", "RDP"}}, - {41, {"ipv6", "IPv6"}}, - {43, {"ipv6-route", "IPv6-Route"}}, - {44, {"ipv6-frag", "IPv6-Frag"}}, - {50, {"esp", "ESP"}}, - {51, {"ah", "AH"}}, - {58, {"ipv6-icmp", "IPv6-ICMP"}}, - {59, {"ipv6-nonxt", "IPv6-NoNxt"}}, - {60, {"ipv6-opts", "IPv6-Opts"}}, - {66, {"rvd", "RVD"}}, -}; + +static const char *map_etc_file( const WCHAR *filename, DWORD *ret_size ) +{ + static const WCHAR key_pathW[] = {'S','y','s','t','e','m', + '\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t', + '\','S','e','r','v','i','c','e','s', + '\','t','c','p','i','p', + '\','P','a','r','a','m','e','t','e','r','s',0}; + static const WCHAR databasepathW[] = {'D','a','t','a','b','a','s','e','P','a','t','h',0}; + static const WCHAR backslashW[] = {'\',0}; + WCHAR path[MAX_PATH]; + DWORD size = sizeof(path); + HANDLE file, mapping; + const char *view; + LONG ret; + + if ((ret = RegGetValueW( HKEY_LOCAL_MACHINE, key_pathW, databasepathW, RRF_RT_REG_SZ, NULL, path, &size ))) + { + ERR( "failed to get database path, error %u\n", ret ); + return NULL; + } + lstrcatW( path, backslashW ); + lstrcatW( path, filename ); + + file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); + if (file == INVALID_HANDLE_VALUE) + { + ERR( "failed to open %s, error %u\n", debugstr_w( path ), GetLastError() ); + return NULL; + } + + size = GetFileSize( file, NULL ); + + mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, size, NULL ); + CloseHandle( file ); + if (!mapping) + { + ERR( "failed to create mapping, error %u\n", GetLastError() ); + return NULL; + } + + view = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, size ); + CloseHandle( mapping ); + if (!view) + ERR( "failed to map file, error %u\n", GetLastError() ); + + *ret_size = size; + return view; +} + +/* returns "end" if there was no space */ +static char *next_space( const char *p, const char *end ) +{ + while (p < end && !isspace( *p )) + ++p; + return (char *)p; +} + +/* returns "end" if there was no non-space */ +static char *next_non_space( const char *p, const char *end ) +{ + while (p < end && isspace( *p )) + ++p; + return (char *)p; +}
static struct WS_protoent *get_protoent_buffer( unsigned int size ) { @@ -1024,18 +1062,111 @@ static struct WS_protoent *get_protoent_buffer( unsigned int size ) return data->pe_buffer; }
-static struct WS_protoent *create_protoent( const char *name, char **aliases, int prot ) +/* Parse the first valid line into a protoent structure, returning NULL if + * there is no valid line. Updates cursor to point to the start of the next + * line or the end of the file. */ +static struct WS_protoent *get_next_protocol( const char **cursor, const char *end ) { - struct WS_protoent *ret; - unsigned int size = sizeof(*ret) + strlen( name ) + sizeof(char *) + list_size( aliases, 0 ); + const char *p = *cursor;
- if (!(ret = get_protoent_buffer( size ))) return NULL; - ret->p_proto = prot; - ret->p_name = (char *)(ret + 1); - strcpy( ret->p_name, name ); - ret->p_aliases = (char **)ret->p_name + strlen( name ) / sizeof(char *) + 1; - list_dup( aliases, ret->p_aliases, 0 ); - return ret; + while (p < end) + { + const char *line_end, *next_line; + size_t needed_size, line_len; + unsigned int alias_count = 0; + struct WS_protoent *proto; + const char *name; + int number; + char *q; + + for (line_end = p; line_end < end && *line_end != '\n' && *line_end != '#'; ++line_end) + ; + TRACE( "parsing line %s\n", debugstr_an(p, line_end - p) ); + + for (next_line = line_end; next_line < end && *next_line != '\n'; ++next_line) + ; + if (next_line < end) + ++next_line; /* skip over the newline */ + + p = next_non_space( p, line_end ); + if (p == line_end) + { + p = next_line; + continue; + } + + /* parse the name */ + + name = p; + line_len = line_end - name; + + p = next_space( p, line_end ); + if (p == line_end) + { + p = next_line; + continue; + } + + p = next_non_space( p, line_end ); + + /* parse the number */ + + number = atoi( p ); + + p = next_space( p, line_end ); + p = next_non_space( p, line_end ); + + /* we will copy the entire line after the protoent structure, then + * replace spaces with null bytes as necessary */ + + while (p < line_end) + { + ++alias_count; + + p = next_space( p, line_end ); + p = next_non_space( p, line_end ); + } + needed_size = sizeof(*proto) + line_len + 1 + (alias_count + 1) * sizeof(char *); + + if (!(proto = get_protoent_buffer( needed_size ))) + { + SetLastError( WSAENOBUFS ); + return NULL; + } + + proto->p_proto = number; + proto->p_aliases = (char **)(proto + 1); + proto->p_name = (char *)(proto->p_aliases + alias_count + 1); + + memcpy( proto->p_name, name, line_len ); + proto->p_name[line_len] = 0; + + line_end = proto->p_name + line_len; + + q = proto->p_name; + q = next_space( q, line_end ); + *q++ = 0; + q = next_non_space( q, line_end ); + /* skip over the number */ + q = next_space( q, line_end ); + q = next_non_space( q, line_end ); + + alias_count = 0; + while (q < line_end) + { + proto->p_aliases[alias_count++] = q; + q = next_space( q, line_end ); + if (q < line_end) *q++ = 0; + q = next_non_space( q, line_end ); + } + proto->p_aliases[alias_count] = NULL; + + *cursor = next_line; + return proto; + } + + SetLastError( WSANO_DATA ); + return NULL; }
@@ -1044,25 +1175,28 @@ static struct WS_protoent *create_protoent( const char *name, char **aliases, in */ struct WS_protoent * WINAPI WS_getprotobyname( const char *name ) { - struct WS_protoent *retval = NULL; - unsigned int i; + static const WCHAR protocolW[] = {'p','r','o','t','o','c','o','l',0}; + struct WS_protoent *proto; + const char *file, *cursor; + DWORD size; + + TRACE( "%s\n", debugstr_a(name) );
- for (i = 0; i < ARRAY_SIZE(protocols); i++) + if (!(file = map_etc_file( protocolW, &size ))) { - if (!_strnicmp( protocols[i].names[0], name, -1 )) - { - retval = create_protoent( protocols[i].names[0], (char **)protocols[i].names + 1, - protocols[i].prot ); - break; - } + SetLastError( WSANO_DATA ); + return NULL; } - if (!retval) + + cursor = file; + while ((proto = get_next_protocol( &cursor, file + size ))) { - WARN( "protocol %s not found\n", debugstr_a(name) ); - SetLastError( WSANO_DATA ); + if (!strcasecmp( proto->p_name, name )) + break; } - TRACE( "%s ret %p\n", debugstr_a(name), retval ); - return retval; + + UnmapViewOfFile( file ); + return proto; }
@@ -1071,25 +1205,28 @@ struct WS_protoent * WINAPI WS_getprotobyname( const char *name ) */ struct WS_protoent * WINAPI WS_getprotobynumber( int number ) { - struct WS_protoent *retval = NULL; - unsigned int i; + static const WCHAR protocolW[] = {'p','r','o','t','o','c','o','l',0}; + struct WS_protoent *proto; + const char *file, *cursor; + DWORD size;
- for (i = 0; i < ARRAY_SIZE(protocols); i++) + TRACE( "%d\n", number ); + + if (!(file = map_etc_file( protocolW, &size ))) { - if (protocols[i].prot == number) - { - retval = create_protoent( protocols[i].names[0], (char **)protocols[i].names + 1, - protocols[i].prot ); - break; - } + SetLastError( WSANO_DATA ); + return NULL; } - if (!retval) + + cursor = file; + while ((proto = get_next_protocol( &cursor, file + size ))) { - WARN( "protocol %d not found\n", number ); - SetLastError( WSANO_DATA ); + if (proto->p_proto == number) + break; } - TRACE( "%d ret %p\n", number, retval ); - return retval; + + UnmapViewOfFile( file ); + return proto; }