#include #include #include #include #include #include "main.h" #include "uring.h" #include "config.h" #include "server.h" #define ADDRSTRLEN (9 /*strlen("AF_INETX ")*/ + INET6_ADDRSTRLEN + 6 /*strlen(" 65535")*/ + 1) struct server_local { struct sockaddr_in46 addr; char addrstr[ADDRSTRLEN]; struct sockaddr_in46 peer; char peerstr[ADDRSTRLEN]; struct uring_task task; struct list_head list; }; /* FIXME: This can be a plain sockaddr_in46 */ struct server_remote { struct sockaddr_in46 addr; char addrstr[ADDRSTRLEN]; struct list_head list; }; struct server_proxy { struct sockaddr_in46 client; char clientstr[ADDRSTRLEN]; struct sockaddr_in46 server; char serverstr[ADDRSTRLEN]; struct uring_task task; char buf[4096]; size_t len; struct list_head list; }; void server_refdump(struct server *server) { struct server_local *local; struct server_proxy *proxy; uring_task_refdump(&server->task); list_for_each_entry(local, &server->locals, list) uring_task_refdump(&local->task); list_for_each_entry(proxy, &server->proxys, list) uring_task_refdump(&proxy->task); } static void server_free(struct uring_task *task) { struct server *scfg = container_of(task, struct server, task); fprintf(stderr, "Freeing scfg %s\n", scfg->name); list_del(&scfg->list); free(scfg->pretty_name); free(scfg->name); free(scfg); } void server_delete(struct cfg *cfg, struct server *scfg) { struct server_local *local, *ltmp; struct server_remote *remote, *rtmp; fprintf(stderr, "Removing server cfg: %s\n", scfg->name); list_for_each_entry_safe(remote, rtmp, &scfg->remotes, list) { list_del(&remote->list); free(remote); } list_for_each_entry_safe(local, ltmp, &scfg->locals, list) { uring_cancel(cfg, &local->task); } uring_task_put(cfg, &scfg->task); } void server_delete_by_name(struct cfg *cfg, const char *name) { struct server *scfg; if (!cfg || !name || name[0] == '\0') return; list_for_each_entry(scfg, &cfg->servers, list) { if (!strcmp(scfg->name, name)) { server_delete(cfg, scfg); return; } } } static char * server_print_addr(struct sockaddr_in46 *addr, char *buf, size_t buflen) { char abuf[ADDRSTRLEN]; switch (addr->storage.ss_family) { case AF_INET: snprintf(buf, buflen, "AF_INET4 %s %u", inet_ntop(addr->in4.sin_family, &addr->in4.sin_addr, abuf, sizeof(abuf)), (unsigned)ntohs(addr->in4.sin_port)); break; case AF_INET6: snprintf(buf, buflen, "AF_INET6 %s %u", inet_ntop(addr->in6.sin6_family, &addr->in6.sin6_addr, abuf, sizeof(abuf)), (unsigned)ntohs(addr->in6.sin6_port)); break; default: snprintf(buf, buflen, "AF_UNKNOWN"); break; } return buf; } static void server_dump(struct server *scfg) { struct server_local *local; struct server_remote *remote; fprintf(stderr, "Dumping server %s\n", scfg->name); switch (scfg->type) { case SERVER_TYPE_ANNOUNCE: fprintf(stderr, " * Type: announce\n"); break; case SERVER_TYPE_PROXY: fprintf(stderr, " * Type: proxy\n"); break; default: fprintf(stderr, " * Type: unknown\n"); break; } fprintf(stderr, " * Pretty name: %s\n", scfg->pretty_name ? scfg->pretty_name : ""); fprintf(stderr, " * Announce port: %" PRIu16 "\n", scfg->announce_port); fprintf(stderr, " * Listening ports:\n"); list_for_each_entry(local, &scfg->locals, list) fprintf(stderr, " * %s\n", local->addrstr); fprintf(stderr, " * Remote ports:\n"); list_for_each_entry(remote, &scfg->remotes, list) fprintf(stderr, " * %s\n", remote->addrstr); } /* struct server_active_proxy { struct sockaddr_in46 client; char clientstr[ADDRSTRLEN]; struct sockaddr_in46 server; char serverstr[ADDRSTRLEN] struct uring_task task; char buf[4096]; size_t len; struct list_head list; }; */ static void server_proxy_free(struct uring_task *task) { struct server_proxy *proxy = container_of(task, struct server_proxy, task); list_del(&proxy->list); free(proxy); } static void server_proxy_connected(struct cfg *cfg, struct uring_task *task, int res) { //struct server_proxy *proxy = container_of(task, struct server_proxy, task); fprintf(stderr, "%s: connected %i\n", __func__, res); return; } static void server_local_free(struct uring_task *task) { struct server_local *local = container_of(task, struct server_local, task); fprintf(stderr, "%s called: task 0x%p\n", __func__, task); list_del(&local->list); free(local); } static void server_local_accept(struct cfg *cfg, struct uring_task *task, int res) { struct server_local *local = container_of(task, struct server_local, task); struct server *scfg = container_of(task->parent, struct server, task); struct server_proxy *proxy; struct server_remote *remote; int sfd; fprintf(stderr, "%s called: task 0x%p and res %i\n", __func__, task, res); fprintf(stderr, "%s called: scfg name is %s\n", __func__, scfg->name); if (task->dead) { fprintf(stderr, "Task dead!\n"); uring_task_put(cfg, task); return; } if (res < 0) { fprintf(stderr, "%s: result was %i\n", __func__, res); goto out; } server_print_addr(&local->peer, local->peerstr, sizeof(local->peerstr)); fprintf(stderr, "%s: incoming proxy connection: %s -> %s\n", scfg->name, local->peerstr, local->addrstr); if (list_empty(&scfg->remotes)) { error("scfg->remotes empty!\n"); goto out; } proxy = zmalloc(sizeof(*proxy)); if (!proxy) { perror("malloc"); uring_close(cfg, NULL, res, NULL); goto out; } remote = list_first_entry(&scfg->remotes, struct server_remote, list); fprintf(stderr, "%s: attempting proxy connection to %s (len %u)\n", scfg->name, remote->addrstr, remote->addr.addrlen); sfd = socket(remote->addr.storage.ss_family, SOCK_STREAM, 0); if (sfd < 0) { perror("socket"); uring_close(cfg, NULL, res, NULL); goto out; } proxy->client = local->peer; memcpy(proxy->clientstr, local->peerstr, sizeof(proxy->clientstr)); uring_task_init(&proxy->task, "proxy", &scfg->task, server_proxy_free); uring_task_set_fd(&proxy->task, sfd); list_add(&proxy->list, &scfg->proxys); uring_connect(cfg, &proxy->task, &remote->addr, server_proxy_connected); out: uring_accept(cfg, &local->task, &local->peer, server_local_accept); } static bool server_local_open(struct cfg *cfg, struct server *scfg, struct server_local *local) { int sfd; int enable = 1; int r; sfd = socket(local->addr.storage.ss_family, SOCK_STREAM, 0); if (sfd < 0) { perror("socket"); goto out; } if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) { perror("setsockopt"); goto out; } r = bind(sfd, (struct sockaddr *)&local->addr.storage, local->addr.addrlen); if (r < 0) { perror("bind"); goto out; } r = listen(sfd, 100); if (r < 0) { perror("listen"); goto out; } uring_task_set_fd(&local->task, sfd); uring_accept(cfg, &local->task, &local->peer, server_local_accept); fprintf(stderr, "** Opened listening socket: %s\n", local->addrstr); return true; out: if (sfd >= 0) close(sfd); return false; } bool server_commit(struct cfg *cfg, struct server *scfg) { struct server_local *local; /* FIXME: config, dont reread config if server running, make sure fd is available before this is called */ /* FIXME: verify correct cfg */ server_dump(scfg); list_for_each_entry(local, &scfg->locals, list) { server_local_open(cfg, scfg, local); } return true; } bool server_add_remote(struct cfg *cfg, struct server *scfg, struct sockaddr_in46 *addr) { struct server_remote *remote; if (!scfg || !addr) return false; remote = zmalloc(sizeof(*remote)); if (!remote) return false; remote->addr.storage = addr->storage; remote->addr.addrlen = addr->addrlen; server_print_addr(&remote->addr, remote->addrstr, sizeof(remote->addrstr)); list_add(&remote->list, &scfg->remotes); return true; } bool server_add_local(struct cfg *cfg, struct server *scfg, struct sockaddr_in46 *addr) { struct server_local *local; if (!scfg || !addr) return false; local = zmalloc(sizeof(*local)); if (!local) return false; local->addr.storage = addr->storage; local->addr.addrlen = addr->addrlen; uring_task_init(&local->task, "local", &scfg->task, server_local_free); server_print_addr(&local->addr, local->addrstr, sizeof(local->addrstr)); fprintf(stderr, "Adding local: %s\n", local->addrstr); list_add(&local->list, &scfg->locals); return true; } bool server_set_port(struct cfg *cfg, struct server *scfg, uint16_t port) { if (!scfg || scfg->announce_port != 0) return false; scfg->announce_port = htons(port); return true; } bool server_set_type(struct cfg *cfg, struct server *scfg, enum server_type type) { if (!scfg || scfg->type != SERVER_TYPE_UNDEFINED) return false; switch (type) { case SERVER_TYPE_ANNOUNCE: scfg->type = SERVER_TYPE_ANNOUNCE; break; case SERVER_TYPE_PROXY: scfg->type = SERVER_TYPE_PROXY; break; default: return false; } return true; } bool server_set_pretty_name(struct cfg *cfg, struct server *scfg, const char *pretty_name) { if (!pretty_name || pretty_name[0] == '\0' || !scfg || scfg->pretty_name) return false; scfg->pretty_name = strdup(pretty_name); if (!scfg->pretty_name) return false; return true; } struct server * server_new(struct cfg *cfg, const char *name) { struct server *scfg; list_for_each_entry(scfg, &cfg->servers, list) { if (strcmp(name, scfg->name)) continue; debug(2, "Server already exists: %s\n", name); return scfg; } debug(2, "Would add server cfg: %s\n", name); scfg = zmalloc(sizeof(*scfg)); if (!scfg) { error("malloc"); return NULL; } scfg->type = SERVER_TYPE_UNDEFINED; scfg->name = strdup(name); scfg->running = false; uring_task_init(&scfg->task, "scfg", &cfg->task, server_free); list_init(&scfg->remotes); list_init(&scfg->locals); list_init(&scfg->proxys); list_add(&scfg->list, &cfg->servers); return scfg; }