summaryrefslogtreecommitdiff
path: root/minecproxy/misc.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-23 20:56:22 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-23 20:56:22 +0200
commitea053d96f7e89e053d4af8d39b04c5428760345f (patch)
tree8182ca73675ad3933b0f38cb48a99c69101309b4 /minecproxy/misc.c
parent8c27290245b7bcc7cd2f72f3b4a7562294b43bbe (diff)
Big renaming, move some more functionality to shared lib
Diffstat (limited to 'minecproxy/misc.c')
-rw-r--r--minecproxy/misc.c281
1 files changed, 281 insertions, 0 deletions
diff --git a/minecproxy/misc.c b/minecproxy/misc.c
new file mode 100644
index 0000000..f954618
--- /dev/null
+++ b/minecproxy/misc.c
@@ -0,0 +1,281 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <stdint.h>
+#include <limits.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <inttypes.h>
+
+#include "main.h"
+#include "misc.h"
+#include "uring.h"
+
+static unsigned total_malloc_count = 0;
+static int malloc_count = 0;
+
+LIST_HEAD(malloc_list);
+
+struct allocation {
+ const char *allocfn;
+ const char *callerfn;
+ int line;
+ void *ptr;
+ size_t size;
+ struct list_head list;
+};
+
+static void
+add_allocation(const char *allocfn, const char *callerfn, int line, void *ptr, size_t size)
+{
+ struct allocation *a;
+
+ assert_die(!empty_str(allocfn) && !empty_str(callerfn) && line > 0 && ptr && size > 0, "invalid arguments");
+
+ a = malloc(sizeof(*a));
+ if (!a)
+ die("malloc: %m");
+ a->allocfn = allocfn;
+ a->callerfn = callerfn;
+ a->line = line;
+ a->ptr = ptr;
+ a->size = size;
+ list_add(&a->list, &malloc_list);
+ total_malloc_count++;
+ malloc_count++;
+ debug(DBG_MALLOC, "called from %s:%i - %s(%zu) = %p (%p)",
+ callerfn, line, allocfn, size, ptr, a);
+}
+
+void *
+__zmalloc(const char *fn, int line, size_t size)
+{
+ void *ptr;
+
+ assert_die(!empty_str(fn) && line > 0 && size > 0, "invalid arguments");
+
+ ptr = calloc(1, size);
+ if (ptr)
+ add_allocation("zmalloc", fn, line, ptr, size);
+ return ptr;
+}
+
+char *
+__xstrdup(const char *fn, int line, const char *s)
+{
+ char *ptr;
+
+ assert_die(!empty_str(fn) && line > 0 && !empty_str(s), "invalid arguments");
+
+ ptr = strdup(s);
+ if (ptr)
+ add_allocation("xstrdup", fn, line, ptr, strlen(s) + 1);
+ return ptr;
+}
+
+char *
+__xstrndup(const char *fn, int line, const char *s, size_t n)
+{
+ char *ptr;
+
+ assert_die(!empty_str(fn) && line > 0 && !empty_str(s) && n > 0, "invalid arguments");
+
+ ptr = strndup(s, n);
+ if (ptr)
+ add_allocation("xstrndup", fn, line, ptr, n);
+ return ptr;
+}
+
+void
+__xfree(const char *fn, int line, void *ptr)
+{
+ struct allocation *a, *tmp;
+ unsigned delete_count = 0;
+
+ assert_die(!empty_str(fn) && line > 0, "invalid arguments");
+
+ if (!ptr)
+ return;
+ free(ptr);
+ malloc_count--;
+
+ debug(DBG_MALLOC, "called from %s:%i - %p", fn, line, ptr);
+
+ list_for_each_entry_safe(a, tmp, &malloc_list, list) {
+ if (a->ptr == ptr) {
+ list_del(&a->list);
+ free(a);
+ delete_count++;
+ }
+ }
+
+ if (delete_count != 1) {
+ error("Delete count is %u for ptr 0x%p", delete_count, ptr);
+ exit(EXIT_FAILURE);
+ }
+}
+
+void
+debug_resource_usage()
+{
+ struct allocation *a;
+ DIR *dir;
+ struct dirent *dent;
+ char buf[4096];
+ ssize_t r;
+ unsigned file_count = 0;
+
+ debug(DBG_MALLOC, "Still malloced %i (total %u)",
+ malloc_count, total_malloc_count);
+
+ list_for_each_entry(a, &malloc_list, list) {
+ debug(DBG_MALLOC, "* Lost allocation - %s:%i - ptr: %p, size: %zu",
+ a->callerfn, a->line, a->ptr, a->size);
+ }
+
+ dir = opendir("/proc/self/fd");
+ if (!dir) {
+ error("failed to open fd dir");
+ return;
+ }
+
+ debug(DBG_MALLOC, "Open files:");
+ while ((dent = readdir(dir)) != NULL) {
+ if (streq(dent->d_name, ".") || streq(dent->d_name, ".."))
+ continue;
+
+ r = readlinkat(dirfd(dir), dent->d_name, buf, sizeof(buf));
+ if (r < 0) {
+ debug(DBG_MALLOC, "Failed to readlink %s", dent->d_name);
+ continue;
+ }
+ buf[r] = '\0';
+ debug(DBG_MALLOC, " * %s -> %s", dent->d_name, buf);
+ file_count++;
+ }
+ closedir(dir);
+
+ if (file_count > 4)
+ debug(DBG_MALLOC, "Lost file descriptor(s)");
+
+ debug(DBG_MALLOC, "CQEs used: %" PRIu64 ", SQEs used: %" PRIu64,
+ cqe_count, sqe_count);
+}
+
+void
+connection_set_local(struct connection *conn, int fd)
+{
+ assert_return(conn && fd >= 0);
+
+ conn->local.addrlen = sizeof(conn->local.storage);
+ if (getsockname(fd, (struct sockaddr *)&conn->local.storage,
+ &conn->local.addrlen) < 0)
+ sprintf(conn->local.addrstr, "<unknown>");
+ else
+ saddr_set_addrstr(&conn->local);
+}
+
+void
+connection_set_remote(struct connection *conn, struct saddr *remote)
+{
+ assert_return(conn && remote);
+
+ conn->remote = *remote;
+ saddr_set_addrstr(&conn->remote);
+}
+
+static void connect_next(struct uring_task *task, struct connection *conn);
+
+static void
+connect_cb(struct uring_task *task, int res)
+{
+ struct connection *conn;
+
+ assert_return(task && task->priv);
+
+ conn = task->priv;
+ if (res < 0) {
+ debug(DBG_SRV, "%s: connection to %s failed",
+ task->name, conn->remote.addrstr);
+ uring_task_close_fd(task);
+ connect_next(task, conn);
+ return;
+ }
+
+ connection_set_local(conn, task->fd);
+
+ debug(DBG_SRV, "%s: connection established %s -> %s",
+ task->name, conn->local.addrstr, conn->remote.addrstr);
+
+ conn->cb(conn, true);
+}
+
+static void
+connect_next(struct uring_task *task, struct connection *conn)
+{
+ struct saddr *remote, *tmp;
+ int sfd;
+ unsigned i;
+
+ assert_return(task && conn && conn->cb);
+again:
+ assert_task_alive_or(DBG_UR, task, goto out);
+
+ i = 0;
+ remote = NULL;
+ list_for_each_entry(tmp, conn->addrs, list) {
+ if (i == conn->next_addr) {
+ remote = tmp;
+ break;
+ }
+ i++;
+ }
+
+ if (!remote) {
+ debug(DBG_SRV, "%s: no more remote addresses to attempt",
+ task->name);
+ goto out;
+ }
+
+ conn->next_addr++;
+ connection_set_remote(conn, remote);
+ debug(DBG_SRV, "%s: attempting to connect to %s",
+ task->name, conn->remote.addrstr);
+
+ sfd = socket(conn->remote.storage.ss_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sfd < 0) {
+ error("socket: %m");
+ goto again;
+ }
+
+ socket_set_low_latency(sfd, cfg->socket_keepalive,
+ cfg->socket_iptos, cfg->socket_nodelay);
+
+ task->priv = conn;
+ uring_task_set_fd(task, sfd);
+ uring_connect(task, &conn->remote, connect_cb);
+ return;
+
+out:
+ conn->cb(conn, false);
+}
+
+void
+connect_any(struct uring_task *task,
+ struct list_head *addrs, struct connection *conn,
+ connection_cb_t cb)
+{
+ assert_return(task && addrs && conn && cb);
+
+ conn->next_addr = 0;
+ conn->addrs = addrs;
+ conn->cb = cb;
+ connect_next(task, conn);
+}
+