diff options
Diffstat (limited to 'shared/utils.c')
-rw-r--r-- | shared/utils.c | 169 |
1 files changed, 169 insertions, 0 deletions
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; +} + |