summaryrefslogtreecommitdiff
path: root/src/libc/net
diff options
context:
space:
mode:
authordzwdz2023-12-25 20:12:44 +0100
committerdzwdz2023-12-25 20:12:44 +0100
commit4be1fd62131f7e186e6f92f1bb5a356dc1ac1951 (patch)
tree54de3a2d99fe9d6e93ad45c5107aff5420f9900d /src/libc/net
parentb9f5f92bff69059471a76e73539780eedb356455 (diff)
user/libc: reorganize net stuff, basic hosts-only gethostbyname()
/usr/share/hosts because i don't have /etc/ yet and i don't feel like creating it.
Diffstat (limited to 'src/libc/net')
-rw-r--r--src/libc/net/arpainet.c38
-rw-r--r--src/libc/net/gethostbyname.c51
-rw-r--r--src/libc/net/socket.c91
3 files changed, 180 insertions, 0 deletions
diff --git a/src/libc/net/arpainet.c b/src/libc/net/arpainet.c
new file mode 100644
index 0000000..62efb62
--- /dev/null
+++ b/src/libc/net/arpainet.c
@@ -0,0 +1,38 @@
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+uint32_t htonl(uint32_t n) {
+ return ((n & 0xFF000000) >> 24)
+ | ((n & 0x00FF0000) >> 8)
+ | ((n & 0x0000FF00) << 8)
+ | ((n & 0x000000FF) << 24);
+}
+
+uint16_t htons(uint16_t n) {
+ return (n >> 8) | (n << 8);
+}
+
+uint32_t ntohl(uint32_t n) {
+ return htonl(n);
+}
+
+uint16_t ntohs(uint16_t n) {
+ return htons(n);
+}
+
+int inet_aton(const char *s, struct in_addr *dest) {
+ if (!s) return -1;
+
+ uint32_t ip = strtol(s, (char**)&s, 0);
+ int parts = 1;
+ for (; parts < 4; parts++) {
+ if (!*s) break;
+ if (*s++ != '.') return 0;
+ ip <<= 8;
+ ip += strtol(s, (char**)&s, 0);
+ }
+ if (parts > 1)
+ ip = ((ip & 0xFFFFFF00) << 8 * (4 - parts)) | (ip & 0xFF);
+ dest->s_addr = htonl(ip);
+ return 1;
+}
diff --git a/src/libc/net/gethostbyname.c b/src/libc/net/gethostbyname.c
new file mode 100644
index 0000000..f2b59c1
--- /dev/null
+++ b/src/libc/net/gethostbyname.c
@@ -0,0 +1,51 @@
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct hostent *gethostbyname(const char *name) {
+ // TODO ipv4 addresses should just get copied
+ static struct hostent he;
+ static struct in_addr addr;
+ static void *addrs[2] = {NULL, NULL};
+ bool found = false;
+ char buf[256];
+ FILE *fp;
+
+ if (he.h_name) {
+ free(he.h_name);
+ he.h_name = NULL;
+ }
+
+ if ((fp = fopen("/usr/share/hosts", "r")) == NULL) {
+ return NULL;
+ }
+ while (!found && fgets(buf, sizeof buf, fp)) {
+ char *s;
+ if (!isdigit(buf[0])) continue;
+ s = strtok(buf, " \t\n");
+ if (!inet_aton(s, &addr)) continue;
+ while ((s = strtok(NULL, " \t\n"))) {
+ if (strcmp(s, name) == 0) {
+ found = true;
+ break;
+ }
+ }
+ }
+ fclose(fp);
+ if (!found) {
+ return NULL;
+ }
+
+ he.h_name = strdup(name);
+ he.h_aliases = NULL;
+ he.h_addrtype = AF_INET;
+ he.h_length = 4;
+ he.h_addr_list = (void*)&addrs;
+ addrs[0] = &addr.s_addr;
+ return &he;
+}
diff --git a/src/libc/net/socket.c b/src/libc/net/socket.c
new file mode 100644
index 0000000..9eacbe5
--- /dev/null
+++ b/src/libc/net/socket.c
@@ -0,0 +1,91 @@
+#include <arpa/inet.h>
+#include <camellia.h>
+#include <camellia/syscalls.h>
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <sys/socket.h>
+
+int socket(int domain, int type, int protocol) {
+ if (domain != AF_INET || type != SOCK_STREAM || protocol != IPPROTO_TCP) {
+ return errno = ENOSYS, -1;
+ }
+ int h = _sys_getnull(0);
+ if (h < 0) {
+ return errno = -h, -1;
+ } else {
+ return h;
+ }
+}
+
+int bind(int, const struct sockaddr *, socklen_t) {
+ return errno = ENOSYS, -1;
+}
+
+int accept(int, struct sockaddr *, socklen_t *) {
+ return errno = ENOSYS, -1;
+}
+
+int listen(int, int) {
+ return errno = ENOSYS, -1;
+}
+
+int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+ char buf[256];
+ struct sockaddr_in *addr4 = (void*)addr;
+ uint32_t ip;
+ uint16_t port;
+ int newfd;
+
+ if (addr->sa_family != AF_INET) {
+ return errno = ENOSYS, -1;
+ }
+
+ if (addrlen < (ssize_t)sizeof(*addr4)) {
+ return errno = EINVAL, -1;
+ }
+
+ ip = ntohl(addr4->sin_addr.s_addr);
+ port = ntohs(addr4->sin_port);
+ if (snprintf(buf, 256, "/net/connect/0/%ld/tcp/%d", ip, port) >= 256) {
+ return errno = EGENERIC, -1;
+ }
+ newfd = camellia_open(buf, OPEN_READ | OPEN_WRITE);
+ if (newfd < 0) {
+ return -1;
+ }
+ dup2(newfd, sockfd);
+ close(newfd);
+ return 0;
+}
+
+ssize_t send(int sockfd, const void *buf, size_t len, int flags) {
+ if (flags != 0) {
+ return errno = ENOSYS, -1;
+ }
+ return write(sockfd, buf, len);
+}
+
+ssize_t recv(int sockfd, void *buf, size_t len, int flags) {
+ if (flags != 0) {
+ return errno = ENOSYS, -1;
+ }
+ return read(sockfd, buf, len);
+}
+
+int getsockopt(int, int, int, void *, socklen_t *) {
+ return errno = ENOSYS, -1;
+}
+
+int setsockopt(int, int, int, const void *, socklen_t) {
+ return 0;
+}
+
+int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+ // TODO /net/ should expose local address somehow
+ /* dummy output, just to satisfy curl */
+ (void)sockfd; (void)addrlen;
+ addr->sa_family = AF_UNSPEC;
+ return 0;
+}