diff options
author | David Härdeman <david@hardeman.nu> | 2020-06-23 20:56:22 +0200 |
---|---|---|
committer | David Härdeman <david@hardeman.nu> | 2020-06-23 20:56:22 +0200 |
commit | ea053d96f7e89e053d4af8d39b04c5428760345f (patch) | |
tree | 8182ca73675ad3933b0f38cb48a99c69101309b4 /shared | |
parent | 8c27290245b7bcc7cd2f72f3b4a7562294b43bbe (diff) |
Big renaming, move some more functionality to shared lib
Diffstat (limited to 'shared')
-rw-r--r-- | shared/debug.h | 94 | ||||
-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 |
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 + |