[PATCH 4/6] ws2_32: Read services from the etc/services file.
Zebediah Figura
zfigura at codeweavers.com
Wed Aug 4 21:20:46 CDT 2021
Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
dlls/ws2_32/protocol.c | 247 +++++++++++++++++++++++------------------
1 file changed, 141 insertions(+), 106 deletions(-)
diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c
index 6c3ab8ea4ce..e280da84205 100644
--- a/dlls/ws2_32/protocol.c
+++ b/dlls/ws2_32/protocol.c
@@ -29,8 +29,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
-DECLARE_CRITICAL_SECTION(csWSgetXXXbyYYY);
-
static char *get_fqdn(void)
{
char *ret;
@@ -949,39 +947,6 @@ int WINAPI GetHostNameW( WCHAR *name, int namelen )
}
-static int list_size( char **list, int item_size )
-{
- int i, size = 0;
- if (list)
- {
- for (i = 0; list[i]; i++)
- size += (item_size ? item_size : strlen(list[i]) + 1);
- size += (i + 1) * sizeof(char *);
- }
- return size;
-}
-
-static int list_dup( char **src, char **dst, int item_size )
-{
- char *p;
- int i;
-
- for (i = 0; src[i]; i++)
- ;
- p = (char *)(dst + i + 1);
-
- for (i = 0; src[i]; i++)
- {
- int count = item_size ? item_size : strlen(src[i]) + 1;
- memcpy( p, src[i], count );
- dst[i] = p;
- p += count;
- }
- dst[i] = NULL;
- return p - (char *)dst;
-}
-
-
static const char *map_etc_file( const WCHAR *filename, DWORD *ret_size )
{
static const WCHAR key_pathW[] = {'S','y','s','t','e','m',
@@ -1230,20 +1195,6 @@ struct WS_protoent * WINAPI WS_getprotobynumber( int number )
}
-static char *strdup_lower( const char *str )
-{
- char *ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
- int i;
-
- if (ret)
- {
- for (i = 0; str[i]; i++) ret[i] = tolower( str[i] );
- ret[i] = 0;
- }
- else SetLastError( WSAENOBUFS );
- return ret;
-}
-
static struct WS_servent *get_servent_buffer( int size )
{
struct per_thread_data *data = get_per_thread_data();
@@ -1258,31 +1209,120 @@ static struct WS_servent *get_servent_buffer( int size )
return data->se_buffer;
}
-static struct WS_servent *servent_from_unix( const struct servent *p_se )
+/* Parse the first valid line into a servent 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_servent *get_next_service( const char **cursor, const char *end )
{
- char *p;
- struct WS_servent *p_to;
+ const char *p = *cursor;
+
+ while (p < end)
+ {
+ const char *line_end, *next_line;
+ size_t needed_size, line_len;
+ unsigned int alias_count = 0;
+ struct WS_servent *serv;
+ const char *name;
+ int port;
+ char *q;
- int size = (sizeof(*p_se) +
- strlen(p_se->s_proto) + 1 +
- strlen(p_se->s_name) + 1 +
- list_size(p_se->s_aliases, 0));
+ 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) );
- if (!(p_to = get_servent_buffer( size ))) return NULL;
- p_to->s_port = p_se->s_port;
+ for (next_line = line_end; next_line < end && *next_line != '\n'; ++next_line)
+ ;
+ if (next_line < end)
+ ++next_line; /* skip over the newline */
- p = (char *)(p_to + 1);
- p_to->s_name = p;
- strcpy( p, p_se->s_name );
- p += strlen(p) + 1;
+ p = next_non_space( p, line_end );
+ if (p == line_end)
+ {
+ p = next_line;
+ continue;
+ }
- p_to->s_proto = p;
- strcpy( p, p_se->s_proto );
- p += strlen(p) + 1;
+ /* parse the name */
- p_to->s_aliases = (char **)p;
- list_dup( p_se->s_aliases, p_to->s_aliases, 0 );
- return p_to;
+ 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 port */
+
+ port = atoi( p );
+ p = memchr( p, '/', line_end - p );
+ if (!p)
+ {
+ p = next_line;
+ continue;
+ }
+
+ p = next_space( p, line_end );
+ p = next_non_space( p, line_end );
+
+ /* we will copy the entire line after the servent 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(*serv) + line_len + 1 + (alias_count + 1) * sizeof(char *);
+
+ if (!(serv = get_servent_buffer( needed_size )))
+ {
+ SetLastError( WSAENOBUFS );
+ return NULL;
+ }
+
+ serv->s_port = htons( port );
+ serv->s_aliases = (char **)(serv + 1);
+ serv->s_name = (char *)(serv->s_aliases + alias_count + 1);
+
+ memcpy( serv->s_name, name, line_len );
+ serv->s_name[line_len] = 0;
+
+ line_end = serv->s_name + line_len;
+
+ q = serv->s_name;
+ q = next_space( q, line_end );
+ *q++ = 0;
+ q = next_non_space( q, line_end );
+ /* skip over the number */
+ q = memchr( q, '/', line_end - q );
+ serv->s_proto = ++q;
+ q = next_space( q, line_end );
+ if (q < line_end) *q++ = 0;
+ q = next_non_space( q, line_end );
+
+ alias_count = 0;
+ while (q < line_end)
+ {
+ serv->s_aliases[alias_count++] = q;
+ q = next_space( q, line_end );
+ if (q < line_end) *q++ = 0;
+ q = next_non_space( q, line_end );
+ }
+ serv->s_aliases[alias_count] = NULL;
+
+ *cursor = next_line;
+ return serv;
+ }
+
+ SetLastError( WSANO_DATA );
+ return NULL;
}
@@ -1291,34 +1331,28 @@ static struct WS_servent *servent_from_unix( const struct servent *p_se )
*/
struct WS_servent * WINAPI WS_getservbyname( const char *name, const char *proto )
{
- struct WS_servent *retval = NULL;
- struct servent *serv;
- char *name_str;
- char *proto_str = NULL;
+ static const WCHAR servicesW[] = {'s','e','r','v','i','c','e','s',0};
+ struct WS_servent *serv;
+ const char *file, *cursor;
+ DWORD size;
- if (!(name_str = strdup_lower( name ))) return NULL;
+ TRACE( "name %s, proto %s\n", debugstr_a(name), debugstr_a(proto) );
- if (proto && *proto)
+ if (!(file = map_etc_file( servicesW, &size )))
{
- if (!(proto_str = strdup_lower( proto )))
- {
- HeapFree( GetProcessHeap(), 0, name_str );
- return NULL;
- }
+ SetLastError( WSANO_DATA );
+ return NULL;
}
- EnterCriticalSection( &csWSgetXXXbyYYY );
- serv = getservbyname( name_str, proto_str );
- if (serv)
- retval = servent_from_unix( serv );
- else
- SetLastError( WSANO_DATA );
- LeaveCriticalSection( &csWSgetXXXbyYYY );
+ cursor = file;
+ while ((serv = get_next_service( &cursor, file + size )))
+ {
+ if (!strcasecmp( serv->s_name, name ) && (!proto || !strcasecmp( serv->s_proto, proto )))
+ break;
+ }
- HeapFree( GetProcessHeap(), 0, proto_str );
- HeapFree( GetProcessHeap(), 0, name_str );
- TRACE( "%s, %s ret %p\n", debugstr_a(name), debugstr_a(proto), retval );
- return retval;
+ UnmapViewOfFile( file );
+ return serv;
}
@@ -1327,27 +1361,28 @@ struct WS_servent * WINAPI WS_getservbyname( const char *name, const char *proto
*/
struct WS_servent * WINAPI WS_getservbyport( int port, const char *proto )
{
- struct WS_servent *retval = NULL;
-#ifdef HAVE_GETSERVBYPORT
- struct servent *serv;
- char *proto_str = NULL;
+ static const WCHAR servicesW[] = {'s','e','r','v','i','c','e','s',0};
+ struct WS_servent *serv;
+ const char *file, *cursor;
+ DWORD size;
- if (proto && *proto)
+ TRACE( "port %d, proto %s\n", port, debugstr_a(proto) );
+
+ if (!(file = map_etc_file( servicesW, &size )))
{
- if (!(proto_str = strdup_lower( proto ))) return NULL;
+ SetLastError( WSANO_DATA );
+ return NULL;
}
- EnterCriticalSection( &csWSgetXXXbyYYY );
- if ((serv = getservbyport( port, proto_str )))
- retval = servent_from_unix( serv );
- else
- SetLastError( WSANO_DATA );
- LeaveCriticalSection( &csWSgetXXXbyYYY );
+ cursor = file;
+ while ((serv = get_next_service( &cursor, file + size )))
+ {
+ if (serv->s_port == port && (!proto || !strcasecmp( serv->s_proto, proto )))
+ break;
+ }
- HeapFree( GetProcessHeap(), 0, proto_str );
-#endif
- TRACE( "%d (i.e. port %d), %s ret %p\n", port, (int)ntohl(port), debugstr_a(proto), retval );
- return retval;
+ UnmapViewOfFile( file );
+ return serv;
}
--
2.32.0
More information about the wine-devel
mailing list