diff options
-rw-r--r-- | mcserverctl/meson.build | 14 | ||||
-rw-r--r-- | mcserverproxy/utils.h | 245 | ||||
-rw-r--r-- | meson.build | 6 | ||||
-rw-r--r-- | minecctl/meson.build | 14 | ||||
-rw-r--r-- | minecctl/minecctl.c (renamed from mcserverctl/mcserverctl.c) | 0 | ||||
-rw-r--r-- | minecproxy/announce.c (renamed from mcserverproxy/announce.c) | 0 | ||||
-rw-r--r-- | minecproxy/announce.h (renamed from mcserverproxy/announce.h) | 0 | ||||
-rw-r--r-- | minecproxy/config-parser.c (renamed from mcserverproxy/config-parser.c) | 2 | ||||
-rw-r--r-- | minecproxy/config-parser.h (renamed from mcserverproxy/config-parser.h) | 0 | ||||
-rw-r--r-- | minecproxy/idle.c (renamed from mcserverproxy/idle.c) | 0 | ||||
-rw-r--r-- | minecproxy/idle.h (renamed from mcserverproxy/idle.h) | 0 | ||||
-rw-r--r-- | minecproxy/igmp.c (renamed from mcserverproxy/igmp.c) | 0 | ||||
-rw-r--r-- | minecproxy/igmp.h (renamed from mcserverproxy/igmp.h) | 0 | ||||
-rw-r--r-- | minecproxy/main.c (renamed from mcserverproxy/main.c) | 3 | ||||
-rw-r--r-- | minecproxy/main.h | 107 | ||||
-rw-r--r-- | minecproxy/meson.build (renamed from mcserverproxy/meson.build) | 12 | ||||
-rw-r--r-- | minecproxy/misc.c (renamed from mcserverproxy/utils.c) | 155 | ||||
-rw-r--r-- | minecproxy/misc.h | 36 | ||||
-rw-r--r-- | minecproxy/ptimer.c (renamed from mcserverproxy/ptimer.c) | 0 | ||||
-rw-r--r-- | minecproxy/ptimer.h (renamed from mcserverproxy/ptimer.h) | 0 | ||||
-rw-r--r-- | minecproxy/server-config.c (renamed from mcserverproxy/server-config.c) | 0 | ||||
-rw-r--r-- | minecproxy/server-config.h (renamed from mcserverproxy/server-config.h) | 0 | ||||
-rw-r--r-- | minecproxy/server-proxy.c (renamed from mcserverproxy/server-proxy.c) | 4 | ||||
-rw-r--r-- | minecproxy/server-proxy.h (renamed from mcserverproxy/server-proxy.h) | 0 | ||||
-rw-r--r-- | minecproxy/server-rcon.c (renamed from mcserverproxy/server-rcon.c) | 0 | ||||
-rw-r--r-- | minecproxy/server-rcon.h (renamed from mcserverproxy/server-rcon.h) | 0 | ||||
-rw-r--r-- | minecproxy/server.c (renamed from mcserverproxy/server.c) | 1 | ||||
-rw-r--r-- | minecproxy/server.h (renamed from mcserverproxy/server.h) | 0 | ||||
-rw-r--r-- | minecproxy/signal-handler.c (renamed from mcserverproxy/signal-handler.c) | 0 | ||||
-rw-r--r-- | minecproxy/signal-handler.h (renamed from mcserverproxy/signal-handler.h) | 0 | ||||
-rw-r--r-- | minecproxy/systemd.c (renamed from mcserverproxy/systemd.c) | 0 | ||||
-rw-r--r-- | minecproxy/systemd.h (renamed from mcserverproxy/systemd.h) | 0 | ||||
-rw-r--r-- | minecproxy/uring.c (renamed from mcserverproxy/uring.c) | 0 | ||||
-rw-r--r-- | minecproxy/uring.h (renamed from mcserverproxy/uring.h) | 0 | ||||
-rw-r--r-- | shared/debug.h (renamed from mcserverproxy/main.h) | 91 | ||||
-rw-r--r-- | shared/list.h | 77 | ||||
-rw-r--r-- | shared/meson.build | 1 | ||||
-rw-r--r-- | shared/utils.c | 169 | ||||
-rw-r--r-- | shared/utils.h | 106 |
39 files changed, 532 insertions, 511 deletions
diff --git a/mcserverctl/meson.build b/mcserverctl/meson.build deleted file mode 100644 index 4e960b7..0000000 --- a/mcserverctl/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -mcserverctl_sources = [ - 'mcserverctl.c', -] - -mcserverctl_deps = [ - dep_libshared, -] - -executable( - 'mcserverctl', - mcserverctl_sources, - dependencies: mcserverctl_deps, -) - diff --git a/mcserverproxy/utils.h b/mcserverproxy/utils.h deleted file mode 100644 index c36a36c..0000000 --- a/mcserverproxy/utils.h +++ /dev/null @@ -1,245 +0,0 @@ -#ifndef fooutilshfoo -#define fooutilshfoo - -#include <stdio.h> -#include <string.h> -#include <stdbool.h> -#include <stdlib.h> -#include <linux/if_packet.h> - -struct list_head { - struct list_head *next; - struct list_head *prev; -}; - -#define zmalloc(s) __zmalloc(__func__, __LINE__, s) -void *__zmalloc(const char *fn, int line, size_t s); - -#define xstrdup(s) __xstrdup(__func__, __LINE__, s) -char *__xstrdup(const char *fn, int line, const char *s); - -#define xstrndup(s, n) __xstrndup(__func__, __LINE__, s, n) -char *__xstrndup(const char *fn, int line, const char *s, size_t n); - -#define xfree(s) __xfree(__func__, __LINE__, s) -void __xfree(const char *fn, int line, void *ptr); - -void debug_resource_usage(); - -/* Length of longest DNS name = 253 + trailing dot */ -#define FQDN_STR_LEN 254 - -/* Length of longest port string = strlen("65535") */ -#define PORT_STR_LEN 5 - -/* Length of longest address family string = strlen("AF_INETX") */ -#define AF_STR_LEN 8 - -/* Length of longest addrstr, format = "AF_INETX <IPADDR> <PORT> */ -#define ADDRSTRLEN (AF_STR_LEN + 1 + INET6_ADDRSTRLEN + 1 + PORT_STR_LEN + 1) -struct saddr { - union { - struct sockaddr_storage storage; - struct sockaddr_in in4; - struct sockaddr_in6 in6; - struct sockaddr_ll ll; - }; - socklen_t addrlen; - char addrstr[ADDRSTRLEN]; - struct list_head list; -}; - -struct connection; - -typedef void(*connection_cb_t)(struct connection *, bool); - -struct connection { - struct saddr remote; - struct saddr local; - - struct list_head *addrs; - unsigned next_addr; - - connection_cb_t cb; -}; - -struct uring_task; - -void socket_set_low_latency(int sfd); - -void connection_set_local(struct connection *conn, int fd); - -void connection_set_remote(struct connection *conn, struct saddr *remote); - -void connect_any(struct uring_task *task, - struct list_head *addrs, struct connection *conn, - connection_cb_t cb); - -char *saddr_addr(struct saddr *saddr, char *buf, size_t len); - -uint16_t saddr_port(struct saddr *saddr); - -void saddr_set_ipv4(struct saddr *saddr, in_addr_t ip, in_port_t port); - -void saddr_set_ipv6(struct saddr *saddr, const struct in6_addr *ip, in_port_t port); - -void saddr_set_addrstr(struct saddr *saddr); - -int strtou16_strict(const char *str, uint16_t *result); - -static inline bool empty_str(const char *str) -{ - if (!str || str[0] == '\0') - return true; - else - return false; -} - -static inline bool streq(const char *a, const char *b) -{ - return strcmp(a, b) == 0; -} - -static inline bool strcaseeq(const char *a, const char *b) -{ - return strcasecmp(a, b) == 0; -} - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define chtobe32(x) __bswap_constant_32(x) -#else -#define chtobe32(x) (x) -#endif - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define cinet_addr(a,b,c,d) ((uint32_t)((a)<<0|(b)<<8|(c)<<16|(d)<<24)) -#else -#define cinet_addr(a,b,c,d) ((uint32_t)((a)<<24|(b)<<16|(c)<<8|(d)<<0)) -#endif - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name) - -static inline void list_init(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -static inline void list_del(struct list_head *list) -{ - list->next->prev = list->prev; - list->prev->next = list->next; -} - -static inline void list_add(struct list_head *new, struct list_head *list) -{ - list->next->prev = new; - new->next = list->next; - new->prev = list; - list->next = new; -} - -static inline void list_replace(struct list_head *old, struct list_head *new) -{ - old->prev->next = new; - old->next->prev = new; - new->next = old->next; - new->prev = old->prev; - old->next = old->prev = NULL; -} - -static inline bool list_empty(struct list_head *list) -{ - return list->next == list; -} - -#define PIPE_RD 0 -#define PIPE_WR 1 - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -#define list_next_entry(pos, member) \ - list_entry((pos)->member.next, typeof(*(pos)), member) - -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -#define list_for_each_entry(pos, head, member) \ - for (pos = list_first_entry(head, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_next_entry(pos, member)) - -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/* -#define _cleanup_(x) __attribute__((cleanup(x))) - -#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ - static inline void func##p(type *p) { \ - if (*p) \ - func(*p); \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -static inline unsigned -strv_length(char **strv) -{ - unsigned len; - - for (len = 0; strv && *strv; strv++) - len++; - - return len; -} - -static inline void strv_free(char **l) { - char **k; - if (l) { - for (k = l; *k; k++) - free(k); - free(l); - } -} -DEFINE_TRIVIAL_CLEANUP_FUNC(char **, strv_free); -#define _cleanup_strv_free_ _cleanup_(strv_freep) - -static inline void freep(void *p) { - free(*(void**) p); -} -#define _cleanup_free_ _cleanup_(freep) - -DEFINE_TRIVIAL_CLEANUP_FUNC(int, close); -#define _cleanup_close_ _cleanup_(closep) - -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE *, fclose); -#define _cleanup_fclose_ _cleanup_(fclosep) - -DEFINE_TRIVIAL_CLEANUP_FUNC(DIR *, closedir); -#define _cleanup_closedir_ _cleanup_(closedirp) - -*/ - -#endif - diff --git a/meson.build b/meson.build index 1f8424a..cc9edc1 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('mcproxy', +project('minecproxy', 'c', version: '0.1.0', license: 'GPL2+', @@ -29,6 +29,6 @@ dep_config_h = declare_dependency( ) subdir('shared') -subdir('mcserverproxy') -subdir('mcserverctl') +subdir('minecproxy') +subdir('minecctl') diff --git a/minecctl/meson.build b/minecctl/meson.build new file mode 100644 index 0000000..3490338 --- /dev/null +++ b/minecctl/meson.build @@ -0,0 +1,14 @@ +minecctl_sources = [ + 'minecctl.c', +] + +minecctl_deps = [ + dep_libshared, +] + +executable( + 'minecctl', + minecctl_sources, + dependencies: minecctl_deps, +) + diff --git a/mcserverctl/mcserverctl.c b/minecctl/minecctl.c index e29dcef..e29dcef 100644 --- a/mcserverctl/mcserverctl.c +++ b/minecctl/minecctl.c diff --git a/mcserverproxy/announce.c b/minecproxy/announce.c index 13ef423..13ef423 100644 --- a/mcserverproxy/announce.c +++ b/minecproxy/announce.c diff --git a/mcserverproxy/announce.h b/minecproxy/announce.h index 77a36f2..77a36f2 100644 --- a/mcserverproxy/announce.h +++ b/minecproxy/announce.h diff --git a/mcserverproxy/config-parser.c b/minecproxy/config-parser.c index ffed7f1..9c89cf2 100644 --- a/mcserverproxy/config-parser.c +++ b/minecproxy/config-parser.c @@ -8,7 +8,7 @@ #include <arpa/inet.h> #include <inttypes.h> -#include "main.h" +#include "utils.h" #include "config-parser.h" static void diff --git a/mcserverproxy/config-parser.h b/minecproxy/config-parser.h index 3a117a3..3a117a3 100644 --- a/mcserverproxy/config-parser.h +++ b/minecproxy/config-parser.h diff --git a/mcserverproxy/idle.c b/minecproxy/idle.c index c49846d..c49846d 100644 --- a/mcserverproxy/idle.c +++ b/minecproxy/idle.c diff --git a/mcserverproxy/idle.h b/minecproxy/idle.h index d7e4ab0..d7e4ab0 100644 --- a/mcserverproxy/idle.h +++ b/minecproxy/idle.h diff --git a/mcserverproxy/igmp.c b/minecproxy/igmp.c index dc43a9f..dc43a9f 100644 --- a/mcserverproxy/igmp.c +++ b/minecproxy/igmp.c diff --git a/mcserverproxy/igmp.h b/minecproxy/igmp.h index 80875b0..80875b0 100644 --- a/mcserverproxy/igmp.h +++ b/minecproxy/igmp.h diff --git a/mcserverproxy/main.c b/minecproxy/main.c index 047e70e..bbe3fad 100644 --- a/mcserverproxy/main.c +++ b/minecproxy/main.c @@ -33,7 +33,6 @@ /* Global */ struct cfg *cfg = NULL; bool exiting = false; -unsigned debug_mask = DBG_ERROR | DBG_INFO; /* Local */ static bool daemonize = false; @@ -655,6 +654,8 @@ main(int argc, char **argv) unsigned server_count; struct rlimit old_rlimit; + debug_mask = DBG_ERROR | DBG_INFO; + cfg_init(argc, argv); cfg_apply(); diff --git a/minecproxy/main.h b/minecproxy/main.h new file mode 100644 index 0000000..f1f5df2 --- /dev/null +++ b/minecproxy/main.h @@ -0,0 +1,107 @@ +#ifndef foomainhfoo +#define foomainhfoo + +#include <sys/socket.h> +#include <netinet/ip.h> + +struct cfg; +struct uring_task; + +#include "misc.h" +#include "utils.h" + +extern struct cfg *cfg; +extern bool exiting; + +/* +enum debug_lvl { + DBG_ERROR = (0x1 << 1), + DBG_INFO = (0x1 << 2), + DBG_VERBOSE = (0x1 << 3), + DBG_CFG = (0x1 << 4), + DBG_REF = (0x1 << 5), + DBG_MALLOC = (0x1 << 6), + DBG_ANN = (0x1 << 7), + DBG_SIG = (0x1 << 8), + DBG_UR = (0x1 << 9), + DBG_SRV = (0x1 << 10), + DBG_PROXY = (0x1 << 11), + DBG_RCON = (0x1 << 12), + DBG_IDLE = (0x1 << 13), + DBG_IGMP = (0x1 << 14), + DBG_SYSD = (0x1 << 15), + DBG_DNS = (0x1 << 16), + DBG_TIMER = (0x1 << 17), +}; +*/ + +void dump_tree(); + +/* To save typing in all the function definitions below */ +typedef void (*utask_cb_t)(struct uring_task *, int res); +typedef int (*rutask_cb_t)(struct uring_task *, int res); + +struct uring_task_buf { + char buf[4096]; + size_t len; + size_t done; + struct iovec iov; + struct msghdr msg; +}; + +struct uring_task { + const char *name; + unsigned refcount; + int fd; + struct uring_task *parent; + void (*free)(struct uring_task *); + bool dead; + struct uring_task_buf *tbuf; + + /* called once or repeatedly until is_complete_cb is satisfied */ + utask_cb_t cb; + + /* returns: 0 = not complete; < 0 = error; > 0 = complete */ + rutask_cb_t is_complete_cb; + + /* called once tbuf processing is done */ + utask_cb_t final_cb; + + /* used for recvmsg/sendmsg */ + struct saddr saddr; + void *priv; +}; + +struct cfg { + /* Options */ + uid_t uid; + gid_t gid; + const char *cfg_dir; + const char *cfg_file; + bool do_igmp; + char *igmp_iface; + bool splice_supported; + uint16_t announce_interval; + uint16_t proxy_connection_interval; + uint16_t proxy_connection_attempts; + bool socket_defer; + bool socket_freebind; + bool socket_keepalive; + bool socket_iptos; + bool socket_nodelay; + + /* Bookkeeping */ + struct uring_ev *uring; + struct server_cfg_monitor *server_cfg_monitor; + struct signal_ev *signal; + struct announce *announce; + struct ptimer *ptimer; + struct igmp *igmp; + struct idle *idle; + struct sd_bus *sd_bus; + bool sd_bus_failed; + struct uring_task task; + struct list_head servers; +}; + +#endif diff --git a/mcserverproxy/meson.build b/minecproxy/meson.build index e5fa7bc..db6a31b 100644 --- a/mcserverproxy/meson.build +++ b/minecproxy/meson.build @@ -1,4 +1,4 @@ -mcproxy_sources = [ +minecproxy_sources = [ 'main.c', 'uring.c', 'signal-handler.c', @@ -12,14 +12,14 @@ mcproxy_sources = [ 'ptimer.c', 'igmp.c', 'systemd.c', - 'utils.c' + 'misc.c', ] dep_liburing = dependency('liburing') dep_libsystemd = dependency('libsystemd') dep_libcapng = dependency('libcap-ng') -mcproxy_deps = [ +minecproxy_deps = [ dep_liburing, dep_libsystemd, dep_libcapng, @@ -28,9 +28,9 @@ mcproxy_deps = [ ] executable( - 'mcproxy', - mcproxy_sources, + 'minecproxy', + minecproxy_sources, link_args: [ '-lanl' ], - dependencies: mcproxy_deps, + dependencies: minecproxy_deps, ) diff --git a/mcserverproxy/utils.c b/minecproxy/misc.c index eacc586..f954618 100644 --- a/mcserverproxy/utils.c +++ b/minecproxy/misc.c @@ -14,7 +14,7 @@ #include <inttypes.h> #include "main.h" -#include "utils.h" +#include "misc.h" #include "uring.h" static unsigned total_malloc_count = 0; @@ -169,35 +169,6 @@ debug_resource_usage() } void -socket_set_low_latency(int sfd) -{ - int option; - - assert_return(sfd >= 0); - - /* Probably not necessary, but can't hurt */ - if (cfg->socket_defer) { - option = true; - if (setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)) < 0) - error("setsockopt: %m"); - } - - /* Doubtful if it has much effect, but can't hurt */ - if (cfg->socket_iptos) { - option = IPTOS_LOWDELAY; - if (setsockopt(sfd, IPPROTO_IP, IP_TOS, &option, sizeof(option)) < 0) - error("setsockopt: %m"); - } - - /* Nagle's algorithm is a poor fit for gaming */ - if (cfg->socket_nodelay) { - option = true; - if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)) < 0) - error("setsockopt: %m"); - } -} - -void connection_set_local(struct connection *conn, int fd) { assert_return(conn && fd >= 0); @@ -283,7 +254,8 @@ again: goto again; } - socket_set_low_latency(sfd); + socket_set_low_latency(sfd, cfg->socket_keepalive, + cfg->socket_iptos, cfg->socket_nodelay); task->priv = conn; uring_task_set_fd(task, sfd); @@ -307,124 +279,3 @@ connect_any(struct uring_task *task, connect_next(task, conn); } -uint16_t -saddr_port(struct saddr *saddr) -{ - assert_return(saddr, 0); - - switch (saddr->storage.ss_family) { - case AF_INET: - return ntohs(saddr->in4.sin_port); - case AF_INET6: - return ntohs(saddr->in6.sin6_port); - default: - return 0; - } -} - -char * -saddr_addr(struct saddr *saddr, char *buf, size_t len) -{ - assert_return(saddr && buf && len > 0, NULL); - - switch (saddr->storage.ss_family) { - case AF_INET: - if (inet_ntop(saddr->in4.sin_family, &saddr->in4.sin_addr, buf, len)) - return buf; - break; - case AF_INET6: - if (inet_ntop(saddr->in6.sin6_family, &saddr->in6.sin6_addr, buf, len)) - return buf; - break; - default: - break; - } - - snprintf(buf, len, "<unknown>"); - return buf; -} - -void -saddr_set_ipv4(struct saddr *saddr, in_addr_t ip, in_port_t port) -{ - assert_return(saddr); - - memset(&saddr->in4, 0, sizeof(saddr->in4)); - saddr->in4.sin_family = AF_INET; - saddr->in4.sin_port = port; - saddr->in4.sin_addr.s_addr = ip; - saddr->addrlen = sizeof(saddr->in4); - saddr_set_addrstr(saddr); -} - -void -saddr_set_ipv6(struct saddr *saddr, const struct in6_addr *ip, in_port_t port) -{ - assert_return(saddr && ip); - - memset(&saddr->in6, 0, sizeof(saddr->in6)); - saddr->in6.sin6_family = AF_INET6; - saddr->in6.sin6_port = port; - if (ip) - saddr->in6.sin6_addr = *ip; - saddr->addrlen = sizeof(saddr->in6); - saddr_set_addrstr(saddr); -} - -void -saddr_set_addrstr(struct saddr *saddr) -{ - assert_return(saddr); - - char abuf[ADDRSTRLEN]; - - switch (saddr->storage.ss_family) { - case AF_INET: - snprintf(saddr->addrstr, sizeof(saddr->addrstr), - "AF_INET4 %s %" PRIu16, - saddr_addr(saddr, abuf, sizeof(abuf)), - saddr_port(saddr)); - break; - case AF_INET6: - snprintf(saddr->addrstr, sizeof(saddr->addrstr), - "AF_INET6 %s %" PRIu16, - saddr_addr(saddr, abuf, sizeof(abuf)), - saddr_port(saddr)); - break; - default: - snprintf(saddr->addrstr, sizeof(saddr->addrstr), "AF_UNKNOWN"); - break; - } -} - -int -strtou16_strict(const char *str, uint16_t *result) -{ - char *end; - long val; - - assert_return(!empty_str(str) && result, -EINVAL); - - errno = 0; - val = strtol(str, &end, 10); - - if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) - return -EINVAL; - - if (errno != 0 && val == 0) - return -EINVAL; - - if (end == str) - return -EINVAL; - - if (*end != '\0') - return -EINVAL; - - if (val < 1 || val > UINT16_MAX) - return -EINVAL; - - if (result) - *result = val; - return 0; -} - diff --git a/minecproxy/misc.h b/minecproxy/misc.h new file mode 100644 index 0000000..6627913 --- /dev/null +++ b/minecproxy/misc.h @@ -0,0 +1,36 @@ +#ifndef foomischfoo +#define foomischfoo + +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include <linux/if_packet.h> + +#include "utils.h" + +void debug_resource_usage(); + +struct connection; + +typedef void(*connection_cb_t)(struct connection *, bool); + +struct connection { + struct saddr remote; + struct saddr local; + + struct list_head *addrs; + unsigned next_addr; + + connection_cb_t cb; +}; + +void connection_set_local(struct connection *conn, int fd); + +void connection_set_remote(struct connection *conn, struct saddr *remote); + +void connect_any(struct uring_task *task, + struct list_head *addrs, struct connection *conn, + connection_cb_t cb); + +#endif diff --git a/mcserverproxy/ptimer.c b/minecproxy/ptimer.c index 5f9cf5d..5f9cf5d 100644 --- a/mcserverproxy/ptimer.c +++ b/minecproxy/ptimer.c diff --git a/mcserverproxy/ptimer.h b/minecproxy/ptimer.h index 0b53590..0b53590 100644 --- a/mcserverproxy/ptimer.h +++ b/minecproxy/ptimer.h diff --git a/mcserverproxy/server-config.c b/minecproxy/server-config.c index 549cf16..549cf16 100644 --- a/mcserverproxy/server-config.c +++ b/minecproxy/server-config.c diff --git a/mcserverproxy/server-config.h b/minecproxy/server-config.h index 590dae0..590dae0 100644 --- a/mcserverproxy/server-config.h +++ b/minecproxy/server-config.h diff --git a/mcserverproxy/server-proxy.c b/minecproxy/server-proxy.c index 4cbbb87..d8ff0cf 100644 --- a/mcserverproxy/server-proxy.c +++ b/minecproxy/server-proxy.c @@ -13,7 +13,6 @@ #include "ptimer.h" #include "server.h" #include "server-proxy.h" -#include "utils.h" static void format_bytes(char *buf, size_t len, uint64_t val) @@ -503,7 +502,8 @@ local_open(struct server_local *local) error("setsockopt: %m"); } - socket_set_low_latency(sfd); + socket_set_low_latency(sfd, cfg->socket_keepalive, + cfg->socket_iptos, cfg->socket_nodelay); r = bind(sfd, (struct sockaddr *)&local->local.storage, local->local.addrlen); if (r < 0) { diff --git a/mcserverproxy/server-proxy.h b/minecproxy/server-proxy.h index ee3bda3..ee3bda3 100644 --- a/mcserverproxy/server-proxy.h +++ b/minecproxy/server-proxy.h diff --git a/mcserverproxy/server-rcon.c b/minecproxy/server-rcon.c index 1f8ef70..1f8ef70 100644 --- a/mcserverproxy/server-rcon.c +++ b/minecproxy/server-rcon.c diff --git a/mcserverproxy/server-rcon.h b/minecproxy/server-rcon.h index 6625f25..6625f25 100644 --- a/mcserverproxy/server-rcon.h +++ b/minecproxy/server-rcon.h diff --git a/mcserverproxy/server.c b/minecproxy/server.c index de42721..534ceca 100644 --- a/mcserverproxy/server.c +++ b/minecproxy/server.c @@ -17,7 +17,6 @@ #include "server.h" #include "server-proxy.h" #include "server-rcon.h" -#include "utils.h" #include "config-parser.h" #include "idle.h" #include "systemd.h" diff --git a/mcserverproxy/server.h b/minecproxy/server.h index ff4c28e..ff4c28e 100644 --- a/mcserverproxy/server.h +++ b/minecproxy/server.h diff --git a/mcserverproxy/signal-handler.c b/minecproxy/signal-handler.c index 67c2e0b..67c2e0b 100644 --- a/mcserverproxy/signal-handler.c +++ b/minecproxy/signal-handler.c diff --git a/mcserverproxy/signal-handler.h b/minecproxy/signal-handler.h index e0140b3..e0140b3 100644 --- a/mcserverproxy/signal-handler.h +++ b/minecproxy/signal-handler.h diff --git a/mcserverproxy/systemd.c b/minecproxy/systemd.c index a44b0d8..a44b0d8 100644 --- a/mcserverproxy/systemd.c +++ b/minecproxy/systemd.c diff --git a/mcserverproxy/systemd.h b/minecproxy/systemd.h index d455044..d455044 100644 --- a/mcserverproxy/systemd.h +++ b/minecproxy/systemd.h diff --git a/mcserverproxy/uring.c b/minecproxy/uring.c index e979471..e979471 100644 --- a/mcserverproxy/uring.c +++ b/minecproxy/uring.c diff --git a/mcserverproxy/uring.h b/minecproxy/uring.h index 9c33104..9c33104 100644 --- a/mcserverproxy/uring.h +++ b/minecproxy/uring.h diff --git a/mcserverproxy/main.h b/shared/debug.h index 256ddae..8581a9a 100644 --- a/mcserverproxy/main.h +++ b/shared/debug.h @@ -1,16 +1,5 @@ -#ifndef foomainhfoo -#define foomainhfoo - -#include <sys/socket.h> -#include <netinet/ip.h> - -struct cfg; - -#include "utils.h" - -extern struct cfg *cfg; -extern bool exiting; -extern unsigned debug_mask; +#ifndef foodebughfoo +#define foodebughfoo enum debug_lvl { DBG_ERROR = (0x1 << 1), @@ -38,8 +27,11 @@ debug_enabled(enum debug_lvl lvl) return !!(lvl & debug_mask); } +/* These need to be defined in the linking binary */ void __debug(enum debug_lvl lvl, const char *fmt, ...) __attribute__((format(printf, 2, 3))); +void __die(const char *fmt, ...) __attribute__((format(printf, 1, 2))); + #define __ifdebug(lvl, fmt, ...) \ do { \ if (debug_enabled((lvl))) \ @@ -55,8 +47,6 @@ void __debug(enum debug_lvl lvl, const char *fmt, ...) __attribute__((format(pri __FILE__, __func__, __LINE__ \ __VA_OPT__(,) __VA_ARGS__) -void __die(const char *fmt, ...) __attribute__((format(printf, 1, 2))); - #define die(fmt, ...) \ __die("%s:%s:%i: " fmt "\n", \ __FILE__, __func__, __LINE__ \ @@ -101,75 +91,4 @@ do { \ #define assert_task_alive(lvl, t) assert_task_alive_or((lvl), (t), return) -void dump_tree(); - -struct uring_task; - -/* To save typing in all the function definitions below */ -typedef void (*utask_cb_t)(struct uring_task *, int res); -typedef int (*rutask_cb_t)(struct uring_task *, int res); - -struct uring_task_buf { - char buf[4096]; - size_t len; - size_t done; - struct iovec iov; - struct msghdr msg; -}; - -struct uring_task { - const char *name; - unsigned refcount; - int fd; - struct uring_task *parent; - void (*free)(struct uring_task *); - bool dead; - struct uring_task_buf *tbuf; - - /* called once or repeatedly until is_complete_cb is satisfied */ - utask_cb_t cb; - - /* returns: 0 = not complete; < 0 = error; > 0 = complete */ - rutask_cb_t is_complete_cb; - - /* called once tbuf processing is done */ - utask_cb_t final_cb; - - /* used for recvmsg/sendmsg */ - struct saddr saddr; - void *priv; -}; - -struct cfg { - /* Options */ - uid_t uid; - gid_t gid; - const char *cfg_dir; - const char *cfg_file; - bool do_igmp; - char *igmp_iface; - bool splice_supported; - uint16_t announce_interval; - uint16_t proxy_connection_interval; - uint16_t proxy_connection_attempts; - bool socket_defer; - bool socket_freebind; - bool socket_keepalive; - bool socket_iptos; - bool socket_nodelay; - - /* Bookkeeping */ - struct uring_ev *uring; - struct server_cfg_monitor *server_cfg_monitor; - struct signal_ev *signal; - struct announce *announce; - struct ptimer *ptimer; - struct igmp *igmp; - struct idle *idle; - struct sd_bus *sd_bus; - bool sd_bus_failed; - struct uring_task task; - struct list_head servers; -}; - #endif diff --git a/shared/list.h b/shared/list.h new file mode 100644 index 0000000..df4092a --- /dev/null +++ b/shared/list.h @@ -0,0 +1,77 @@ +#ifndef foolisthfoo +#define foolisthfoo + +struct list_head { + struct list_head *next; + struct list_head *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name) + +static inline void list_init(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void list_del(struct list_head *list) +{ + list->next->prev = list->prev; + list->prev->next = list->next; +} + +static inline void list_add(struct list_head *new, struct list_head *list) +{ + list->next->prev = new; + new->next = list->next; + new->prev = list; + list->next = new; +} + +static inline void list_replace(struct list_head *old, struct list_head *new) +{ + old->prev->next = new; + old->next->prev = new; + new->next = old->next; + new->prev = old->prev; + old->next = old->prev = NULL; +} + +static inline bool list_empty(struct list_head *list) +{ + return list->next == list; +} + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#endif + diff --git a/shared/meson.build b/shared/meson.build index cbb7dca..ccf502e 100644 --- a/shared/meson.build +++ b/shared/meson.build @@ -1,5 +1,6 @@ srcs_libshared = [ 'rcon-protocol.c', + 'utils.c', ] inc_libshared = include_directories('.') diff --git a/shared/utils.c b/shared/utils.c new file mode 100644 index 0000000..1284a73 --- /dev/null +++ b/shared/utils.c @@ -0,0 +1,169 @@ +#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/ip.h> +#include <netinet/tcp.h> +#include <inttypes.h> + +#include "utils.h" + +unsigned debug_mask = 0; + +void +socket_set_low_latency(int sfd, bool keepalive, bool iptos, bool nodelay) +{ + int option; + + assert_return(sfd >= 0); + + /* Probably not necessary, but can't hurt */ + if (keepalive) { + option = true; + if (setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof(option)) < 0) + error("setsockopt: %m"); + } + + /* Doubtful if it has much effect, but can't hurt */ + if (iptos) { + option = IPTOS_LOWDELAY; + if (setsockopt(sfd, IPPROTO_IP, IP_TOS, &option, sizeof(option)) < 0) + error("setsockopt: %m"); + } + + /* Nagle's algorithm is a poor fit for gaming */ + if (nodelay) { + option = true; + if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)) < 0) + error("setsockopt: %m"); + } +} + +uint16_t +saddr_port(struct saddr *saddr) +{ + //assert_return(saddr, 0); + + switch (saddr->storage.ss_family) { + case AF_INET: + return ntohs(saddr->in4.sin_port); + case AF_INET6: + return ntohs(saddr->in6.sin6_port); + default: + return 0; + } +} + +char * +saddr_addr(struct saddr *saddr, char *buf, size_t len) +{ + //assert_return(saddr && buf && len > 0, NULL); + + switch (saddr->storage.ss_family) { + case AF_INET: + if (inet_ntop(saddr->in4.sin_family, &saddr->in4.sin_addr, buf, len)) + return buf; + break; + case AF_INET6: + if (inet_ntop(saddr->in6.sin6_family, &saddr->in6.sin6_addr, buf, len)) + return buf; + break; + default: + break; + } + + snprintf(buf, len, "<unknown>"); + return buf; +} + +void +saddr_set_ipv4(struct saddr *saddr, in_addr_t ip, in_port_t port) +{ + //assert_return(saddr); + + memset(&saddr->in4, 0, sizeof(saddr->in4)); + saddr->in4.sin_family = AF_INET; + saddr->in4.sin_port = port; + saddr->in4.sin_addr.s_addr = ip; + saddr->addrlen = sizeof(saddr->in4); + saddr_set_addrstr(saddr); +} + +void +saddr_set_ipv6(struct saddr *saddr, const struct in6_addr *ip, in_port_t port) +{ + //assert_return(saddr && ip); + + memset(&saddr->in6, 0, sizeof(saddr->in6)); + saddr->in6.sin6_family = AF_INET6; + saddr->in6.sin6_port = port; + if (ip) + saddr->in6.sin6_addr = *ip; + saddr->addrlen = sizeof(saddr->in6); + saddr_set_addrstr(saddr); +} + +void +saddr_set_addrstr(struct saddr *saddr) +{ + //assert_return(saddr); + + char abuf[ADDRSTRLEN]; + + switch (saddr->storage.ss_family) { + case AF_INET: + snprintf(saddr->addrstr, sizeof(saddr->addrstr), + "AF_INET4 %s %" PRIu16, + saddr_addr(saddr, abuf, sizeof(abuf)), + saddr_port(saddr)); + break; + case AF_INET6: + snprintf(saddr->addrstr, sizeof(saddr->addrstr), + "AF_INET6 %s %" PRIu16, + saddr_addr(saddr, abuf, sizeof(abuf)), + saddr_port(saddr)); + break; + default: + snprintf(saddr->addrstr, sizeof(saddr->addrstr), "AF_UNKNOWN"); + break; + } +} + +int +strtou16_strict(const char *str, uint16_t *result) +{ + char *end; + long val; + + //assert_return(!empty_str(str) && result, -EINVAL); + + errno = 0; + val = strtol(str, &end, 10); + + if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) + return -EINVAL; + + if (errno != 0 && val == 0) + return -EINVAL; + + if (end == str) + return -EINVAL; + + if (*end != '\0') + return -EINVAL; + + if (val < 1 || val > UINT16_MAX) + return -EINVAL; + + if (result) + *result = val; + return 0; +} + diff --git a/shared/utils.h b/shared/utils.h new file mode 100644 index 0000000..df728b2 --- /dev/null +++ b/shared/utils.h @@ -0,0 +1,106 @@ +#ifndef fooutilshfoo +#define fooutilshfoo + +#include <stdio.h> +#include <string.h> +#include <stdbool.h> +#include <stdlib.h> +#include <linux/if_packet.h> + +extern unsigned debug_mask; + +#include "list.h" +#include "debug.h" + +/* These functions need to be defined in the linking binary */ +#define zmalloc(s) __zmalloc(__func__, __LINE__, s) +void *__zmalloc(const char *fn, int line, size_t s); + +#define xstrdup(s) __xstrdup(__func__, __LINE__, s) +char *__xstrdup(const char *fn, int line, const char *s); + +#define xstrndup(s, n) __xstrndup(__func__, __LINE__, s, n) +char *__xstrndup(const char *fn, int line, const char *s, size_t n); + +#define xfree(s) __xfree(__func__, __LINE__, s) +void __xfree(const char *fn, int line, void *ptr); + +/* Length of longest DNS name = 253 + trailing dot */ +#define FQDN_STR_LEN 254 + +/* Length of longest port string = strlen("65535") */ +#define PORT_STR_LEN 5 + +/* Length of longest address family string = strlen("AF_INETX") */ +#define AF_STR_LEN 8 + +/* Length of longest addrstr, format = "AF_INETX <IPADDR> <PORT> */ +#define ADDRSTRLEN (AF_STR_LEN + 1 + INET6_ADDRSTRLEN + 1 + PORT_STR_LEN + 1) + +struct saddr { + union { + struct sockaddr_storage storage; + struct sockaddr_in in4; + struct sockaddr_in6 in6; + struct sockaddr_ll ll; + }; + socklen_t addrlen; + char addrstr[ADDRSTRLEN]; + struct list_head list; +}; + +void socket_set_low_latency(int sfd, bool keepalive, bool iptos, bool nodelay); + +char *saddr_addr(struct saddr *saddr, char *buf, size_t len); + +uint16_t saddr_port(struct saddr *saddr); + +void saddr_set_ipv4(struct saddr *saddr, in_addr_t ip, in_port_t port); + +void saddr_set_ipv6(struct saddr *saddr, const struct in6_addr *ip, in_port_t port); + +void saddr_set_addrstr(struct saddr *saddr); + +int strtou16_strict(const char *str, uint16_t *result); + +static inline bool empty_str(const char *str) +{ + if (!str || str[0] == '\0') + return true; + else + return false; +} + +static inline bool streq(const char *a, const char *b) +{ + return strcmp(a, b) == 0; +} + +static inline bool strcaseeq(const char *a, const char *b) +{ + return strcasecmp(a, b) == 0; +} + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define chtobe32(x) __bswap_constant_32(x) +#else +#define chtobe32(x) (x) +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define cinet_addr(a,b,c,d) ((uint32_t)((a)<<0|(b)<<8|(c)<<16|(d)<<24)) +#else +#define cinet_addr(a,b,c,d) ((uint32_t)((a)<<24|(b)<<16|(c)<<8|(d)<<0)) +#endif + +#define PIPE_RD 0 +#define PIPE_WR 1 + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) + +#endif + |