/* SPDX-License-Identifier: GPL-2.0 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "utils.h" unsigned debug_mask = 0; const char *ansi_red = ""; const char *ansi_green = ""; const char *ansi_yellow = ""; const char *ansi_blue = ""; const char *ansi_magenta = ""; const char *ansi_grey = ""; const char *ansi_normal = ""; void enable_colors() { ansi_red = ANSI_RED; ansi_green = ANSI_GREEN; ansi_yellow = ANSI_YELLOW; ansi_blue = ANSI_BLUE; ansi_magenta = ANSI_MAGENTA; ansi_grey = ANSI_GREY; ansi_normal = ANSI_NORMAL; } void free_password(char **password) { if (!password || !*password) return; explicit_bzero(*password, strlen(*password)); xfree(*password); *password = NULL; } 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->st.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->st.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, ""); 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_any_to_loopback(struct saddr *saddr) { switch (saddr->st.ss_family) { case AF_INET: if (saddr->in4.sin_addr.s_addr != htonl(INADDR_ANY)) return; saddr->in4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); break; case AF_INET6: if (memcmp(&saddr->in6.sin6_addr, &in6addr_any, sizeof(in6addr_any))) return; saddr->in6.sin6_addr = in6addr_loopback; break; default: return; } saddr_set_addrstr(saddr); } void saddr_set_addrstr(struct saddr *saddr) { // assert_return(saddr); char abuf[ADDRSTRLEN]; switch (saddr->st.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; if (empty_str(str)) return -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; } char *xsprintf(size_t *rlen, const char *fmt, ...) { va_list ap; int len; char *str; va_start(ap, fmt); len = vsnprintf(NULL, 0, fmt, ap); va_end(ap); if (len < 0) return NULL; len++; str = zmalloc(len); if (!str) return NULL; va_start(ap, fmt); len = vsnprintf(str, len, fmt, ap); va_end(ap); if (len < 0) { xfree(str); return NULL; } if (rlen) *rlen = len; return str; }