Skip to content

Commit a3a9596

Browse files
authored
wasi-sockets: Add services database and implement getservbyname/getservbyport functions (#532)
This is a follow-up PR for #524 by implementing the following features: - Embeds a minimal network services database with 17 common protocols, suggested by @badeend. The database array is a weak symbol allowing applications to override the default database at link time. - Updates `getaddrinfo` to resolve named services in the address info. For example `getaddrinfo("google.com", "https", NULL, &res);` - Implements the `getservbyname` and `getservbyport` functions. These functions are implemented using a static variable (`global_serv`), which holds the returned service entry. This approach is acceptable because these functions [are defined as not being thread-safe](https://man.archlinux.org/man/getservbyname.3.en). ~~Additionally, this PR introduces an optional, more comprehensive services database (`sockets_full_services_db.c`), based on Debian Bookworm's `/etc/services` file (320 entries). To use this database, link with the `-lc-full-services-db` flag.~~
1 parent 48eb92c commit a3a9596

File tree

4 files changed

+127
-15
lines changed

4 files changed

+127
-15
lines changed

expected/wasm32-wasip2/defined-symbols.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,13 @@ __wasi_sock_accept
333333
__wasi_sock_recv
334334
__wasi_sock_send
335335
__wasi_sock_shutdown
336+
__wasi_sockets_services_db
336337
__wasi_sockets_utils__any_addr
337338
__wasi_sockets_utils__borrow_network
338339
__wasi_sockets_utils__create_streams
339340
__wasi_sockets_utils__drop_streams
341+
__wasi_sockets_utils__get_service_entry_by_name
342+
__wasi_sockets_utils__get_service_entry_by_port
340343
__wasi_sockets_utils__map_error
341344
__wasi_sockets_utils__output_addr_validate
342345
__wasi_sockets_utils__output_addr_write

libc-bottom-half/headers/private/wasi/sockets_utils.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ typedef struct {
2626
};
2727
} output_sockaddr_t;
2828

29+
typedef struct {
30+
char *s_name;
31+
uint16_t port;
32+
uint16_t protocol;
33+
} service_entry_t;
34+
35+
typedef enum {
36+
SERVICE_PROTOCOL_TCP = 1,
37+
SERVICE_PROTOCOL_UDP = 2
38+
} service_protocol_e;
39+
2940
network_borrow_network_t __wasi_sockets_utils__borrow_network();
3041
int __wasi_sockets_utils__map_error(network_error_code_t wasi_error);
3142
bool __wasi_sockets_utils__parse_address(
@@ -50,5 +61,7 @@ bool __wasi_sockets_utils__stream(udp_socket_t *socket,
5061
network_error_code_t *error);
5162
void __wasi_sockets_utils__drop_streams(udp_socket_streams_t streams);
5263
int __wasi_sockets_utils__parse_port(const char *port);
64+
const service_entry_t *__wasi_sockets_utils__get_service_entry_by_name(const char *name);
65+
const service_entry_t *__wasi_sockets_utils__get_service_entry_by_port(const uint16_t port);
5366

5467
#endif

libc-bottom-half/sources/netdb.c

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
_Thread_local int h_errno = 0;
99

10+
static struct servent global_serv = { 0 };
11+
1012
static int map_error(ip_name_lookup_error_code_t error)
1113
{
1214
switch (error) {
@@ -27,6 +29,7 @@ static int map_error(ip_name_lookup_error_code_t error)
2729

2830
static int add_addr(ip_name_lookup_option_ip_address_t address,
2931
in_port_t port,
32+
int socktype,
3033
const struct addrinfo *restrict hint,
3134
struct addrinfo **restrict current,
3235
struct addrinfo **restrict res)
@@ -117,7 +120,7 @@ static int add_addr(ip_name_lookup_option_ip_address_t address,
117120
*result = (struct addrinfo){
118121
.ai_family = family,
119122
.ai_flags = 0,
120-
.ai_socktype = SOCK_STREAM,
123+
.ai_socktype = socktype,
121124
.ai_protocol = 0,
122125
.ai_addrlen = addrlen,
123126
.ai_addr = addr,
@@ -136,6 +139,29 @@ static int add_addr(ip_name_lookup_option_ip_address_t address,
136139
return 0;
137140
}
138141

142+
static bool set_global_serv_entry(const service_entry_t *entry, const char *proto) {
143+
if (!entry) {
144+
return false; // Service not found
145+
}
146+
147+
global_serv.s_name = entry->s_name;
148+
global_serv.s_port = htons(entry->port);
149+
global_serv.s_aliases = NULL;
150+
151+
// If proto is NULL then any protocol is matched
152+
if ((!proto || strcmp(proto, "tcp") == 0) && entry->protocol & SERVICE_PROTOCOL_TCP) {
153+
global_serv.s_proto = "tcp";
154+
}
155+
else if ((!proto || strcmp(proto, "udp") == 0) && entry->protocol & SERVICE_PROTOCOL_UDP) {
156+
global_serv.s_proto = "udp";
157+
}
158+
else {
159+
return false; // Protocol not supported
160+
}
161+
162+
return true;
163+
}
164+
139165
int getaddrinfo(const char *restrict host, const char *restrict serv,
140166
const struct addrinfo *restrict hint,
141167
struct addrinfo **restrict res)
@@ -155,27 +181,39 @@ int getaddrinfo(const char *restrict host, const char *restrict serv,
155181
ip_name_lookup_borrow_resolve_address_stream_t stream_borrow =
156182
ip_name_lookup_borrow_resolve_address_stream(stream);
157183
// The 'serv' parameter can be either a port number or a service name.
158-
//
159-
// TODO wasi-sockets: If the conversion of 'serv' to a valid port
160-
// number fails, use getservbyname() to resolve the service name to
161-
// its corresponding port number. This can be done after the
162-
// getservbyname function is implemented.)
163184
int port = 0;
185+
uint16_t protocol = SERVICE_PROTOCOL_TCP;
164186
if (serv != NULL) {
165187
port = __wasi_sockets_utils__parse_port(serv);
166188
if (port < 0) {
167-
return EAI_NONAME;
189+
const service_entry_t *service = __wasi_sockets_utils__get_service_entry_by_name(serv);
190+
if (service) {
191+
port = service->port;
192+
protocol = service->protocol;
193+
}
194+
else {
195+
return EAI_NONAME;
196+
}
168197
}
169198
}
170199
while (true) {
171200
ip_name_lookup_option_ip_address_t address;
172201
if (ip_name_lookup_method_resolve_address_stream_resolve_next_address(
173202
stream_borrow, &address, &error)) {
174203
if (address.is_some) {
175-
int error = add_addr(address, htons(port), hint,
176-
&current, res);
177-
if (error) {
178-
return error;
204+
if (protocol & SERVICE_PROTOCOL_TCP) {
205+
int error = add_addr(address, htons(port), SOCK_STREAM,
206+
hint, &current, res);
207+
if (error) {
208+
return error;
209+
}
210+
}
211+
if (protocol & SERVICE_PROTOCOL_UDP) {
212+
int error = add_addr(address, htons(port), SOCK_DGRAM,
213+
hint, &current, res);
214+
if (error) {
215+
return error;
216+
}
179217
}
180218
} else {
181219
return 0;
@@ -236,14 +274,20 @@ const char *hstrerror(int err)
236274

237275
struct servent *getservbyname(const char *name, const char *proto)
238276
{
239-
// TODO wasi-sockets
240-
return NULL;
277+
const service_entry_t *entry = __wasi_sockets_utils__get_service_entry_by_name(name);
278+
if (!set_global_serv_entry(entry, proto)) {
279+
return NULL;
280+
}
281+
return &global_serv;
241282
}
242283

243284
struct servent *getservbyport(int port, const char *proto)
244285
{
245-
// TODO wasi-sockets
246-
return NULL;
286+
const service_entry_t *entry = __wasi_sockets_utils__get_service_entry_by_port(htons(port));
287+
if (!set_global_serv_entry(entry, proto)) {
288+
return NULL;
289+
}
290+
return &global_serv;
247291
}
248292

249293
struct protoent *getprotobyname(const char *name)

libc-bottom-half/sources/sockets_utils.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,33 @@
11
#include <errno.h>
22
#include <stdlib.h>
33
#include <ctype.h>
4+
#include <string.h>
45

56
#include <wasi/sockets_utils.h>
67

78
static network_own_network_t global_network;
89
static bool global_network_initialized = false;
10+
static const service_entry_t global_services[] = {
11+
{ "domain", 53, SERVICE_PROTOCOL_TCP | SERVICE_PROTOCOL_UDP },
12+
{ "ftp", 21, SERVICE_PROTOCOL_TCP },
13+
{ "ftp-data", 20, SERVICE_PROTOCOL_TCP },
14+
{ "ftps", 990, SERVICE_PROTOCOL_TCP },
15+
{ "ftps-data", 989, SERVICE_PROTOCOL_TCP },
16+
{ "http", 80, SERVICE_PROTOCOL_TCP | SERVICE_PROTOCOL_UDP },
17+
{ "https", 443, SERVICE_PROTOCOL_TCP | SERVICE_PROTOCOL_UDP },
18+
{ "imap", 143, SERVICE_PROTOCOL_TCP },
19+
{ "imaps", 993, SERVICE_PROTOCOL_TCP },
20+
{ "ntp", 123, SERVICE_PROTOCOL_TCP },
21+
{ "pop3", 110, SERVICE_PROTOCOL_TCP },
22+
{ "pop3s", 995, SERVICE_PROTOCOL_TCP },
23+
{ "smtp", 25, SERVICE_PROTOCOL_TCP },
24+
{ "ssh", 22, SERVICE_PROTOCOL_TCP },
25+
{ "submission", 587, SERVICE_PROTOCOL_TCP },
26+
{ "submissions", 465, SERVICE_PROTOCOL_TCP },
27+
{ "telnet", 23, SERVICE_PROTOCOL_TCP },
28+
{ 0 },
29+
};
30+
weak_alias(global_services, __wasi_sockets_services_db);
931

1032
network_borrow_network_t __wasi_sockets_utils__borrow_network()
1133
{
@@ -482,3 +504,33 @@ int __wasi_sockets_utils__parse_port(const char *restrict port_str)
482504

483505
return (int)port;
484506
}
507+
508+
const service_entry_t *__wasi_sockets_utils__get_service_entry_by_name(const char *name)
509+
{
510+
if (!name) {
511+
return NULL;
512+
}
513+
514+
const service_entry_t *entry = __wasi_sockets_services_db;
515+
while(entry->s_name) {
516+
if (strcmp(name, entry->s_name) == 0) {
517+
return entry;
518+
}
519+
++entry;
520+
}
521+
522+
return NULL;
523+
}
524+
525+
const service_entry_t *__wasi_sockets_utils__get_service_entry_by_port(const uint16_t port)
526+
{
527+
const service_entry_t *entry = __wasi_sockets_services_db;
528+
while(entry->s_name) {
529+
if (entry->port == port) {
530+
return entry;
531+
}
532+
++entry;
533+
}
534+
535+
return NULL;
536+
}

0 commit comments

Comments
 (0)