Files
KirkOS/user/include/mlibc/options/posix/generic/services.cpp
T
kaguya 9a9b91c940 user: implement mlibc as the libc, finally.
It's finally done..

Signed-off-by: kaguya <vpshinomiya@protonmail.com>
2026-05-02 03:31:49 -04:00

223 lines
4.6 KiB
C++

#include <mlibc/services.hpp>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <mlibc/debug.hpp>
namespace mlibc {
static int parse_rest(service_buf &buf, char *end, int proto) {
if (!strncmp(end, "/udp", 4)) {
if (proto == IPPROTO_TCP && proto != -1)
return 0;
buf.protocol = IPPROTO_UDP;
buf.socktype = SOCK_DGRAM;
} else if (!strncmp(end, "/tcp", 4)) {
if (proto == IPPROTO_UDP && proto != -1)
return 0;
buf.protocol = IPPROTO_TCP;
buf.socktype = SOCK_STREAM;
} else {
return 0;
}
//TODO(geert): also parse aliases.
return 1;
}
static int lookup_serv_file_port(service_result &buf, int proto, int port) {
auto file = fopen(_PATH_SERVICES, "r");
if (!file) {
switch (errno) {
case ENOENT:
case ENOTDIR:
case EACCES:
return -EAI_SERVICE;
default:
return -EAI_SYSTEM;
}
}
char line_buf[129] = {0};
char *line = line_buf + 1;
while(fgets(line, 128, file)) {
int name_length = 0;
char *pos;
// easy way to handle comments, just move the end of the line
// to the beginning of the comment
if ((pos = strchr(line, '#'))) {
*pos++ = '\n';
*pos = '\0';
}
char *end = nullptr;
for (pos = line; *pos; pos++) {
for (; isalpha(*pos); pos++);
int rport = strtoul(pos, &end, 10);
if (rport != port || rport > 65535) {
pos = end;
continue;
}
// We have found the port, time to rewind to the start
// of the line.
for (; pos[-1]; pos--)
if(!isspace(pos[-1]))
name_length++;
break;
}
if (!pos)
continue;
if (!name_length)
continue;
auto name = frg::string<MemoryAllocator>(pos, name_length,
getAllocator());
struct service_buf sbuf = {};
sbuf.port = port;
sbuf.name = std::move(name);
if (!parse_rest(sbuf, end, proto))
continue;
buf.push_back(std::move(sbuf));
}
fclose(file);
return buf.size();
}
static int lookup_serv_file_name(service_result &buf, const char *name,
int proto) {
auto file = fopen(_PATH_SERVICES, "r");
if (!file) {
switch (errno) {
case ENOENT:
case ENOTDIR:
case EACCES:
return -EAI_SERVICE;
default:
return -EAI_SYSTEM;
}
}
char line[128];
int name_length = strlen(name);
while(fgets(line, 128, file)) {
char *pos;
// easy way to handle comments, just move the end of the line
// to the beginning of the comment
if ((pos = strchr(line, '#'))) {
*pos++ = '\n';
*pos = '\0';
}
for (pos = line; (pos = strstr(pos, name)); pos++) {
// the name must start and end with a space
if (pos > line && !isspace(pos[-1]))
continue;
if (pos[name_length] && !isspace(pos[name_length]))
continue;
break;
}
if (!pos)
continue;
// Skip the name at the beginning of the line.
for(pos = line; *pos && !isspace(*pos); pos++)
;
char *end = nullptr;
int port = strtoul(pos, &end, 10);
if (port > 65535 || end == pos)
continue;
struct service_buf sbuf;
sbuf.port = port;
sbuf.name = frg::string<MemoryAllocator>(name, getAllocator());
if (!parse_rest(sbuf, end, proto))
continue;
buf.push_back(sbuf);
}
fclose(file);
return buf.size();
}
// This function returns a negative error code, since a positive
// return code means success.
int lookup_serv_by_name(service_result &buf, const char *name, int proto,
int socktype, int flags) {
switch(socktype) {
case SOCK_STREAM:
if (!proto)
proto = IPPROTO_TCP;
else if (proto != IPPROTO_TCP)
return -EAI_SERVICE;
break;
case SOCK_DGRAM:
if (!proto)
proto = IPPROTO_UDP;
else if (proto != IPPROTO_UDP)
return -EAI_SERVICE;
break;
case 0:
break;
default:
if (name)
return -EAI_SERVICE;
buf[0].port = 0;
buf[0].socktype = socktype;
buf[0].protocol = proto;
return 1;
}
char *end = nullptr;
unsigned int port = 0;
int count = 0;
if (name) {
if (!*name)
return -EAI_SERVICE;
port = strtoul(name, &end, 10);
}
// The end pointer is a null pointer so the name was a port
// or the name was not specified.
if (!end || !*end) {
if (proto != IPPROTO_UDP) {
buf[count].port = port;
buf[count].protocol = IPPROTO_TCP;
buf[count].socktype = SOCK_STREAM;
count++;
}
if (proto != IPPROTO_TCP) {
buf[count].port = port;
buf[count].protocol = IPPROTO_UDP;
buf[count].socktype = SOCK_DGRAM;
count++;
}
return count;
}
if (flags & AI_NUMERICSERV)
return -EAI_NONAME;
return lookup_serv_file_name(buf, name, proto);
}
int lookup_serv_by_port(service_result &buf, int proto, int port) {
return lookup_serv_file_port(buf, proto, port);
}
} // namespace mlibc