Zebediah Figura : ws2_32: Read protocols from the etc/protocol file.

Alexandre Julliard julliard at winehq.org
Fri Aug 6 16:10:39 CDT 2021


Module: wine
Branch: master
Commit: 8504e40d5b5e7076b998b36e6291515b863482cb
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=8504e40d5b5e7076b998b36e6291515b863482cb

Author: Zebediah Figura <zfigura at codeweavers.com>
Date:   Wed Aug  4 21:20:45 2021 -0500

ws2_32: Read protocols from the etc/protocol file.

Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ws2_32/Makefile.in |   2 +-
 dlls/ws2_32/protocol.c  | 262 ++++++++++++++++++++++++++++++++++++------------
 2 files changed, 198 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..c1789fb4c77 100644
--- a/dlls/ws2_32/protocol.c
+++ b/dlls/ws2_32/protocol.c
@@ -981,33 +981,64 @@ 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 char *read_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;
+    char *data;
+    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 );
+    if (!(data = HeapAlloc( GetProcessHeap(), 0, size )) ||
+        !ReadFile( file, data, size, ret_size, NULL ))
+    {
+        WARN( "failed to read file, error %u\n", GetLastError() );
+        HeapFree( GetProcessHeap(), 0, data );
+        data = NULL;
+    }
+    CloseHandle( file );
+    return data;
+}
+
+/* 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 +1055,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 +1168,29 @@ 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 *cursor;
+    char *file;
+    DWORD size;
 
-    for (i = 0; i < ARRAY_SIZE(protocols); i++)
+    TRACE( "%s\n", debugstr_a(name) );
+
+    if (!(file = read_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;
+
+    HeapFree( GetProcessHeap(), 0, file );
+    return proto;
 }
 
 
@@ -1071,25 +1199,29 @@ 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 *cursor;
+    char *file;
+    DWORD size;
+
+    TRACE( "%d\n", number );
 
-    for (i = 0; i < ARRAY_SIZE(protocols); i++)
+    if (!(file = read_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;
+
+    HeapFree( GetProcessHeap(), 0, file );
+    return proto;
 }
 
 




More information about the wine-cvs mailing list