user: implement mlibc as the libc, finally.
It's finally done.. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user