From 65c2a56c6d62e3c24d52da8c63f306b70becdb45 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Wed, 23 Sep 2020 12:40:28 -0400 Subject: [PATCH] Initialize sockets --- config.sh | 6 ++++ configure | 1 + include/config.h | 2 ++ include/server.h | 31 ++++++++++++++++ src/config.c | 26 ++++++++++++++ src/main.c | 14 +++++++- src/server.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 include/server.h create mode 100644 src/server.c diff --git a/config.sh b/config.sh index e1dfa97..6e6aafa 100644 --- a/config.sh +++ b/config.sh @@ -30,6 +30,12 @@ do esac done +case "$(uname)" in + Linux) + CFLAGS="$CFLAGS -DLINUX" + ;; +esac + subdir() { eval ". $srcdir/$1/configure" } diff --git a/configure b/configure index 30c4cbb..fd6c84c 100755 --- a/configure +++ b/configure @@ -8,6 +8,7 @@ gmnisrv() { src/escape.c \ src/ini.c \ src/main.c \ + src/server.c \ src/url.c } diff --git a/include/config.h b/include/config.h index f9d875c..dec0e15 100644 --- a/include/config.h +++ b/include/config.h @@ -15,6 +15,7 @@ struct gmnisrv_host { }; struct gmnisrv_bind { + char *name; int family, port; char addr[sizeof(struct in6_addr)]; struct gmnisrv_bind *next; @@ -27,6 +28,7 @@ struct gmnisrv_config { }; int load_config(struct gmnisrv_config *conf, const char *path); +void config_finish(struct gmnisrv_config *conf); struct gmnisrv_host *gmnisrv_config_get_host( struct gmnisrv_config *conf, const char *hostname); diff --git a/include/server.h b/include/server.h new file mode 100644 index 0000000..8547799 --- /dev/null +++ b/include/server.h @@ -0,0 +1,31 @@ +#ifndef GMNISRV_SERVER +#define GMNISRV_SERVER +#include + +#define GEMINI_MAX_URL 1024 + +struct gmnisrv_client { + char buf[GEMINI_MAX_URL + 2]; + size_t bufln; + int sockfd; + int respfd; +}; + +struct gmisrv_config; + +struct gmnisrv_server { + struct gmnisrv_config *conf; + struct pollfd *fds; + nfds_t nfds, fdsz; + + size_t nlisten; + + struct gmnisrv_client *clients; + size_t nclients, clientsz; +}; + +int server_init(struct gmnisrv_server *server, struct gmnisrv_config *conf); +void server_run(struct gmnisrv_server *server); +void server_finish(struct gmnisrv_server *server); + +#endif diff --git a/src/config.c b/src/config.c index 9bc251c..f3172d2 100644 --- a/src/config.c +++ b/src/config.c @@ -31,7 +31,9 @@ parse_listen(struct gmnisrv_config *conf, const char *value) char *port = tok; struct gmnisrv_bind *bind = calloc(1, sizeof(struct gmnisrv_bind)); + assert(bind); bind->port = 1965; + bind->name = strdup(tok); if (tok[0] == '[') { bind->family = AF_INET6; @@ -133,6 +135,7 @@ conf_ini_handler(void *user, const char *section, struct gmnisrv_host *host = gmnisrv_config_get_host(conf, section); if (!host) { host = calloc(1, sizeof(struct gmnisrv_host)); + assert(host); host->hostname = strdup(section); host->next = conf->hosts; conf->hosts = host; @@ -194,3 +197,26 @@ load_config(struct gmnisrv_config *conf, const char *path) return validate_config(conf); } + +void +config_finish(struct gmnisrv_config *conf) +{ + free(conf->tls.store); + free(conf->tls.organization); + free(conf->tls.email); + struct gmnisrv_bind *bind = conf->binds; + while (bind) { + struct gmnisrv_bind *next = bind->next; + free(bind->name); + free(bind); + bind = next; + } + struct gmnisrv_host *host = conf->hosts; + while (host) { + struct gmnisrv_host *next = host->next; + free(host->hostname); + free(host->root); + free(host); + host = next; + } +} diff --git a/src/main.c b/src/main.c index b865b01..6e64965 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,7 @@ #include #include #include "config.h" +#include "server.h" static void usage(const char *argv_0) @@ -36,8 +37,19 @@ main(int argc, char **argv) int r = load_config(&conf, confpath); if (r != 0) { - return r; + goto exit_conf; } + struct gmnisrv_server server = {0}; + r = server_init(&server, &conf); + if (r != 0) { + goto exit; + } + server_run(&server); + +exit: + server_finish(&server); +exit_conf: + config_finish(&conf); return 0; } diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..39c2c07 --- /dev/null +++ b/src/server.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "server.h" + +int +server_init(struct gmnisrv_server *server, struct gmnisrv_config *conf) +{ + server->conf = conf; + for (struct gmnisrv_bind *b = conf->binds; b; b = b->next) { + ++server->nlisten; + } + + assert(server->nlisten < 1024); + server->nfds = server->nlisten; + server->fds = calloc(server->nfds, sizeof(struct pollfd)); + assert(server->fds); + + server->clientsz = 1024 - server->nlisten; + server->clients = calloc(server->clientsz, sizeof(struct gmnisrv_client)); + + size_t i = 0; + for (struct gmnisrv_bind *b = conf->binds; b; b = b->next) { + int sockfd = socket(b->family, SOCK_STREAM, 0); + if (sockfd < 0) { + fprintf(stderr, + "Failed to establish socket %s: %s\n", + b->name, strerror(errno)); + return 1; + } + + struct sockaddr *addr; + size_t addrsz; + if (b->family == AF_INET) { + struct sockaddr_in in = {0}; + in.sin_family = AF_INET; + memcpy(&in.sin_addr, b->addr, sizeof(b->addr)); + in.sin_port = htons(b->port); + addr = (struct sockaddr *)∈ + addrsz = sizeof(in); + } else if (b->family == AF_INET6) { + struct sockaddr_in6 in = {0}; + in.sin6_family = AF_INET6; + memcpy(&in.sin6_addr, b->addr, sizeof(b->addr)); + in.sin6_port = htons(b->port); + addr = (struct sockaddr *)∈ + addrsz = sizeof(in); +#ifdef LINUX + static int t = 1; + setsockopt(sockfd, IPPROTO_IPV6, + IPV6_V6ONLY, &t, sizeof(t)); +#endif + } else { + assert(0); + } + + int r = bind(sockfd, addr, addrsz); + if (r == -1) { + fprintf(stderr, + "Failed to bind socket %s: %s\n", + b->name, strerror(errno)); + return 1; + } + + r = listen(sockfd, 16); + + server->fds[i].fd = sockfd; + server->fds[i].events = POLLIN; + ++i; + } + + return 0; +} + +void +server_run(struct gmnisrv_server *server) +{ + // TODO + (void)server; +} + +void +server_finish(struct gmnisrv_server *server) +{ + // TODO + (void)server; +}