ws2_32: Read services from the etc/services file.

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2021-08-04 21:20:46 -05:00 committed by Alexandre Julliard
parent 8504e40d5b
commit d3138d711b
1 changed files with 143 additions and 106 deletions

View File

@ -29,8 +29,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(winsock); WINE_DEFAULT_DEBUG_CHANNEL(winsock);
WINE_DECLARE_DEBUG_CHANNEL(winediag); WINE_DECLARE_DEBUG_CHANNEL(winediag);
DECLARE_CRITICAL_SECTION(csWSgetXXXbyYYY);
static char *get_fqdn(void) static char *get_fqdn(void)
{ {
char *ret; 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 char *read_etc_file( const WCHAR *filename, DWORD *ret_size ) static char *read_etc_file( const WCHAR *filename, DWORD *ret_size )
{ {
static const WCHAR key_pathW[] = {'S','y','s','t','e','m', static const WCHAR key_pathW[] = {'S','y','s','t','e','m',
@ -1225,20 +1190,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 ) static struct WS_servent *get_servent_buffer( int size )
{ {
struct per_thread_data *data = get_per_thread_data(); struct per_thread_data *data = get_per_thread_data();
@ -1253,31 +1204,120 @@ static struct WS_servent *get_servent_buffer( int size )
return data->se_buffer; 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; const char *p = *cursor;
struct WS_servent *p_to;
int size = (sizeof(*p_se) + while (p < end)
strlen(p_se->s_proto) + 1 + {
strlen(p_se->s_name) + 1 + const char *line_end, *next_line;
list_size(p_se->s_aliases, 0)); size_t needed_size, line_len;
unsigned int alias_count = 0;
struct WS_servent *serv;
const char *name;
int port;
char *q;
if (!(p_to = get_servent_buffer( size ))) return NULL; for (line_end = p; line_end < end && *line_end != '\n' && *line_end != '#'; ++line_end)
p_to->s_port = p_se->s_port; ;
TRACE( "parsing line %s\n", debugstr_an(p, line_end - p) );
p = (char *)(p_to + 1); for (next_line = line_end; next_line < end && *next_line != '\n'; ++next_line)
p_to->s_name = p; ;
strcpy( p, p_se->s_name ); if (next_line < end)
p += strlen(p) + 1; ++next_line; /* skip over the newline */
p_to->s_proto = p; p = next_non_space( p, line_end );
strcpy( p, p_se->s_proto ); if (p == line_end)
p += strlen(p) + 1; {
p = next_line;
continue;
}
p_to->s_aliases = (char **)p; /* parse the name */
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;
} }
@ -1286,34 +1326,29 @@ 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 * WINAPI WS_getservbyname( const char *name, const char *proto )
{ {
struct WS_servent *retval = NULL; static const WCHAR servicesW[] = {'s','e','r','v','i','c','e','s',0};
struct servent *serv; struct WS_servent *serv;
char *name_str; const char *cursor;
char *proto_str = NULL; char *file;
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 = read_etc_file( servicesW, &size )))
{ {
if (!(proto_str = strdup_lower( proto ))) SetLastError( WSANO_DATA );
{ return NULL;
HeapFree( GetProcessHeap(), 0, name_str );
return NULL;
}
} }
EnterCriticalSection( &csWSgetXXXbyYYY ); cursor = file;
serv = getservbyname( name_str, proto_str ); while ((serv = get_next_service( &cursor, file + size )))
if (serv) {
retval = servent_from_unix( serv ); if (!strcasecmp( serv->s_name, name ) && (!proto || !strcasecmp( serv->s_proto, proto )))
else break;
SetLastError( WSANO_DATA ); }
LeaveCriticalSection( &csWSgetXXXbyYYY );
HeapFree( GetProcessHeap(), 0, proto_str ); HeapFree( GetProcessHeap(), 0, file );
HeapFree( GetProcessHeap(), 0, name_str ); return serv;
TRACE( "%s, %s ret %p\n", debugstr_a(name), debugstr_a(proto), retval );
return retval;
} }
@ -1322,27 +1357,29 @@ 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 * WINAPI WS_getservbyport( int port, const char *proto )
{ {
struct WS_servent *retval = NULL; static const WCHAR servicesW[] = {'s','e','r','v','i','c','e','s',0};
#ifdef HAVE_GETSERVBYPORT struct WS_servent *serv;
struct servent *serv; const char *cursor;
char *proto_str = NULL; char *file;
DWORD size;
if (proto && *proto) TRACE( "port %d, proto %s\n", port, debugstr_a(proto) );
if (!(file = read_etc_file( servicesW, &size )))
{ {
if (!(proto_str = strdup_lower( proto ))) return NULL; SetLastError( WSANO_DATA );
return NULL;
} }
EnterCriticalSection( &csWSgetXXXbyYYY ); cursor = file;
if ((serv = getservbyport( port, proto_str ))) while ((serv = get_next_service( &cursor, file + size )))
retval = servent_from_unix( serv ); {
else if (serv->s_port == port && (!proto || !strcasecmp( serv->s_proto, proto )))
SetLastError( WSANO_DATA ); break;
LeaveCriticalSection( &csWSgetXXXbyYYY ); }
HeapFree( GetProcessHeap(), 0, proto_str ); HeapFree( GetProcessHeap(), 0, file );
#endif return serv;
TRACE( "%d (i.e. port %d), %s ret %p\n", port, (int)ntohl(port), debugstr_a(proto), retval );
return retval;
} }