From ea053d96f7e89e053d4af8d39b04c5428760345f Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Tue, 23 Jun 2020 20:56:22 +0200 Subject: Big renaming, move some more functionality to shared lib --- minecproxy/misc.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 minecproxy/misc.c (limited to 'minecproxy/misc.c') 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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, ""); + 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); +} + -- cgit v1.2.3