summaryrefslogtreecommitdiff
path: root/shared
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 /shared
parent8c27290245b7bcc7cd2f72f3b4a7562294b43bbe (diff)
Big renaming, move some more functionality to shared lib
Diffstat (limited to 'shared')
-rw-r--r--shared/debug.h94
-rw-r--r--shared/list.h77
-rw-r--r--shared/meson.build1
-rw-r--r--shared/utils.c169
-rw-r--r--shared/utils.h106
5 files changed, 447 insertions, 0 deletions
diff --git a/shared/debug.h b/shared/debug.h
new file mode 100644
index 0000000..8581a9a
--- /dev/null
+++ b/shared/debug.h
@@ -0,0 +1,94 @@
+#ifndef foodebughfoo
+#define foodebughfoo
+
+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),
+};
+
+static inline bool
+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))) \
+ __debug((lvl), fmt "\n"__VA_OPT__(,) __VA_ARGS__); \
+ } while (0)
+
+#define debug(lvl, fmt, ...) __ifdebug((lvl), "%s:%s:%i: " fmt, \
+ __FILE__, __func__, __LINE__ \
+ __VA_OPT__(,) __VA_ARGS__)
+#define verbose(fmt, ...) __ifdebug(DBG_VERBOSE, fmt, __VA_ARGS__)
+#define info(fmt, ...) __ifdebug(DBG_INFO, fmt, __VA_ARGS__)
+#define error(fmt, ...) __ifdebug(DBG_ERROR, "%s:%s:%i: " fmt, \
+ __FILE__, __func__, __LINE__ \
+ __VA_OPT__(,) __VA_ARGS__)
+
+#define die(fmt, ...) \
+ __die("%s:%s:%i: " fmt "\n", \
+ __FILE__, __func__, __LINE__ \
+ __VA_OPT__(,) __VA_ARGS__)
+
+#define assert_log(expr, msg) \
+ ((expr) ? \
+ (true) : \
+ (__debug(DBG_ERROR, "%s:%s:%i: assertion \"" msg "\" failed\n", \
+ __FILE__, __func__, __LINE__), false))
+
+#define assert_return(expr, ...) \
+ do { \
+ if (!assert_log(expr, #expr)) \
+ return __VA_ARGS__; \
+ } while (0)
+
+#define assert_return_silent(expr, ...) \
+ do { \
+ if (!(expr)) \
+ return __VA_ARGS__; \
+ } while (0)
+
+#define assert_die(expr, msg) \
+ do { \
+ if (!assert_log(expr, #expr)) \
+ die(msg); \
+ } while (0)
+
+#define assert_task_alive_or(lvl, t, cmd) \
+do { \
+ if (!(t)) { \
+ error("invalid task"); \
+ cmd; \
+ } \
+ \
+ if ((t)->dead) { \
+ debug((lvl), "task dead"); \
+ cmd; \
+ } \
+} while(0)
+
+#define assert_task_alive(lvl, t) assert_task_alive_or((lvl), (t), return)
+
+#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
+