summaryrefslogtreecommitdiff
path: root/shared/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'shared/utils.c')
-rw-r--r--shared/utils.c169
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;
+}
+