From: Elias Fleckenstein Date: Sun, 17 Apr 2022 15:07:24 +0000 (+0200) Subject: Use getaddrinfo and getnameinfo for address parsing X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=eb33e93d3af69b098141558d47ab042acf791a1d;p=dragonnet.git Use getaddrinfo and getnameinfo for address parsing --- diff --git a/addr.c b/addr.c index b9a6d37..da8fc25 100644 --- a/addr.c +++ b/addr.c @@ -1,56 +1,56 @@ -#include #include #include #include #include #include -DragonnetAddr dragonnet_addr_parse_str(char *str) +struct addrinfo *dragonnet_str2addr(const char *str) { - DragonnetAddr addr = {0}; - - size_t colon_i = 0; - for (ssize_t i = strlen(str)-1; i >= 0; --i) { - if (str[i] == ':') { - colon_i = i; - break; - } + const char *port = str + strlen(str) - 1; + while (port >= str && *port != ':') + port--; + port++; + + const char *host_begin = str; + if (*host_begin == '[') + host_begin++; + + const char *host_end = port - 2; + if (host_end >= str && *host_end == ']') + host_end--; + + ssize_t host_len = host_end - host_begin + 1; + if (host_len < 0) + host_len = 0; + + char host[host_len + 1]; + host[host_len] = '\0'; + memcpy(host, host_begin, host_len); + + struct addrinfo *result, hints = {0}; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + int err; + if ((err = getaddrinfo(host, port, &hints, &result))) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err)); + return NULL; } - size_t ip_addr_i = 0, port_i = 0; - for (size_t i = 0; i < strlen(str); ++i) { - if (i < colon_i && str[i] != '[' && str[i] != ']') - addr.ip[ip_addr_i++] = str[i]; - else if (i > colon_i) - addr.port[port_i++] = str[i]; - } - - return addr; -} - -char *dragonnet_addr_str(DragonnetAddr addr) -{ - char *ptr; - asprintf(&ptr, "[%s]:%s", addr.ip, addr.port); - return ptr; + return result; } -DragonnetAddr dragonnet_addr_parse_sock(struct sockaddr_in6 ai_addr) +char *dragonnet_addr2str(struct sockaddr *addr, socklen_t addr_len) { - DragonnetAddr addr = {0}; - sprintf(addr.port, "%d", ntohs(ai_addr.sin6_port)); - inet_ntop(AF_INET6, &ai_addr.sin6_addr, addr.ip, INET6_ADDRSTRLEN); + char host[NI_MAXHOST], port[NI_MAXSERV]; - return addr; -} - -struct sockaddr_in6 dragonnet_addr_sock(DragonnetAddr addr) -{ - struct sockaddr_in6 ai_addr = {0}; - ai_addr.sin6_family = AF_INET6; - ai_addr.sin6_flowinfo = 0; - ai_addr.sin6_port = htons(atoi(addr.port)); - inet_pton(AF_INET6, addr.ip, &ai_addr.sin6_addr); + int err; + if ((err = getnameinfo(addr, addr_len, host, NI_MAXHOST, port, NI_MAXSERV, NI_NUMERICSERV))) { + fprintf(stderr, "getnameinfo: %s\n", gai_strerror(err)); + return NULL; + } - return ai_addr; + char str[1 + strlen(host) + 1 + 1 + strlen(port) + 1]; + sprintf(str, "[%s]:%s", host, port); + return strdup(str); } diff --git a/addr.h b/addr.h index b70ed1f..fdffa4a 100644 --- a/addr.h +++ b/addr.h @@ -1,17 +1,11 @@ #ifndef _DRAGONNET_ADDR_H_ #define _DRAGONNET_ADDR_H_ -#include +#include +#include +#include -typedef struct { - char ip[INET6_ADDRSTRLEN]; - char port[6]; -} DragonnetAddr; - -DragonnetAddr dragonnet_addr_parse_str(char *addr); -char *dragonnet_addr_str(DragonnetAddr addr); - -DragonnetAddr dragonnet_addr_parse_sock(struct sockaddr_in6 ai_addr); -struct sockaddr_in6 dragonnet_addr_sock(DragonnetAddr addr); +struct addrinfo *dragonnet_str2addr(const char *str); +char *dragonnet_addr2str(struct sockaddr *addr, socklen_t addr_len); #endif diff --git a/listen.c b/listen.c index b65ca8b..83adba6 100644 --- a/listen.c +++ b/listen.c @@ -1,5 +1,6 @@ #define _GNU_SOURCE #include +#include #include #include #include @@ -16,13 +17,12 @@ // ---- static bool dragonnet_peer_init_accepted(DragonnetPeer *p, int sock, - struct sockaddr_in6 addr, DragonnetListener *l) + char *addr, DragonnetListener *l) { pthread_mutex_init(&p->mtx, NULL); p->sock = sock; - p->laddr = l->laddr; - p->raddr = dragonnet_addr_parse_sock(addr); + p->address = addr; p->on_disconnect = l->on_disconnect; p->on_recv = l->on_recv; p->on_recv_type = l->on_recv_type; @@ -30,13 +30,14 @@ static bool dragonnet_peer_init_accepted(DragonnetPeer *p, int sock, return true; } -static DragonnetPeer *dragonnet_peer_accept(int sock, struct sockaddr_in6 addr, +static DragonnetPeer *dragonnet_peer_accept(int sock, char *addr, DragonnetListener *l) { DragonnetPeer *p = malloc(sizeof *p); if (!dragonnet_peer_init_accepted(p, sock, addr, l)) { pthread_mutex_destroy(&p->mtx); free(p); + free(addr); return NULL; } @@ -49,10 +50,15 @@ static DragonnetPeer *dragonnet_peer_accept(int sock, struct sockaddr_in6 addr, DragonnetListener *dragonnet_listener_new(char *addr) { + struct addrinfo *info = dragonnet_str2addr(addr); + if (!info) + return NULL; + DragonnetListener *l = malloc(sizeof *l); l->active = true; - l->sock = socket(AF_INET6, SOCK_STREAM, 0); + l->sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol); + l->address = dragonnet_addr2str(info->ai_addr, info->ai_addrlen); l->on_connect = NULL; l->on_disconnect = NULL; l->on_recv = NULL; @@ -62,19 +68,20 @@ DragonnetListener *dragonnet_listener_new(char *addr) if (setsockopt(l->sock, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof so_reuseaddr) < 0) { perror("setsockopt"); + freeaddrinfo(info); dragonnet_listener_delete(l); return NULL; } - l->laddr = dragonnet_addr_parse_str(addr); - struct sockaddr_in6 ai_addr = dragonnet_addr_sock(l->laddr); - - if (bind(l->sock, (const struct sockaddr *) &ai_addr, sizeof ai_addr) < 0) { + if (bind(l->sock, info->ai_addr, info->ai_addrlen) < 0) { perror("bind"); + freeaddrinfo(info); dragonnet_listener_delete(l); return NULL; } + freeaddrinfo(info); + if (listen(l->sock, 10) < 0) { perror("listen"); dragonnet_listener_delete(l); @@ -93,8 +100,8 @@ static void *listener_main(void *g_listener) DragonnetListener *l = (DragonnetListener *) g_listener; while (l->active) { - struct sockaddr_in6 clt_addr; - socklen_t clt_addrlen = sizeof clt_addr; + struct sockaddr_storage clt_addr; + socklen_t clt_addrlen; int clt_sock = accept(l->sock, (struct sockaddr *) &clt_addr, &clt_addrlen); if (clt_sock < 0) { @@ -103,7 +110,8 @@ static void *listener_main(void *g_listener) continue; } - DragonnetPeer *p = dragonnet_peer_accept(clt_sock, clt_addr, l); + char *clt_addstr = dragonnet_addr2str((struct sockaddr *) &clt_addr, clt_addrlen); + DragonnetPeer *p = dragonnet_peer_accept(clt_sock, clt_addstr, l); if (p == NULL) continue; @@ -134,5 +142,6 @@ void dragonnet_listener_close(DragonnetListener *l) void dragonnet_listener_delete(DragonnetListener *l) { free(l->on_recv_type); + free(l->address); free(l); } diff --git a/listen.h b/listen.h index 8346ccc..6d31eaa 100644 --- a/listen.h +++ b/listen.h @@ -6,7 +6,8 @@ typedef struct { int sock; - DragonnetAddr laddr; + char *address; + pthread_t accept_thread; bool active; diff --git a/peer.c b/peer.c index 75eb6ab..ad17be6 100644 --- a/peer.c +++ b/peer.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -10,28 +11,25 @@ static bool dragonnet_peer_init(DragonnetPeer *p, char *addr) { pthread_mutex_init(&p->mtx, NULL); - p->sock = socket(AF_INET6, SOCK_STREAM, 0); - p->raddr = dragonnet_addr_parse_str(addr); - p->on_disconnect = NULL; - p->on_recv = NULL; - p->on_recv_type = calloc(sizeof *p->on_recv_type, dragonnet_num_types); + struct addrinfo *info = dragonnet_str2addr(addr); + if (!info) + return false; + + p->sock = socket(info->ai_family, info->ai_socktype, info->ai_protocol); + p->address = dragonnet_addr2str(info->ai_addr, info->ai_addrlen); - struct sockaddr_in6 sock_addr = dragonnet_addr_sock(p->raddr); - if (connect(p->sock, (const struct sockaddr *) &sock_addr, - sizeof sock_addr) < 0) { + if (connect(p->sock, info->ai_addr, info->ai_addrlen) < 0) { + freeaddrinfo(info); perror("connect"); return false; } - struct sockaddr_in6 sock_name; - socklen_t sock_namelen = sizeof sock_name; + freeaddrinfo(info); - if (getsockname(p->sock, (struct sockaddr *) &sock_name, &sock_namelen) < 0) { - perror("getsockname"); - return false; - } + p->on_disconnect = NULL; + p->on_recv = NULL; + p->on_recv_type = calloc(sizeof *p->on_recv_type, dragonnet_num_types); // fixme: memory leak - p->laddr = dragonnet_addr_parse_sock(sock_name); return true; } diff --git a/peer.h b/peer.h index 8b1a65a..ce6100b 100644 --- a/peer.h +++ b/peer.h @@ -1,7 +1,6 @@ #ifndef _DRAGONNET_PEER_H_ #define _DRAGONNET_PEER_H_ -#include #include #include #include @@ -10,7 +9,8 @@ typedef uint16_t DragonnetTypeId; typedef struct dragonnet_peer { int sock; - DragonnetAddr laddr, raddr; + char *address; + pthread_t recv_thread; pthread_mutex_t mtx; diff --git a/recv.c b/recv.c index 75a3719..4cb9be3 100644 --- a/recv.c +++ b/recv.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include bool dragonnet_recv_raw(DragonnetPeer *p, void *buf, size_t n) diff --git a/recv_thread.c b/recv_thread.c index aefb335..a84e109 100644 --- a/recv_thread.c +++ b/recv_thread.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include void *dragonnet_peer_recv_thread(void *g_peer) @@ -41,6 +43,7 @@ void *dragonnet_peer_recv_thread(void *g_peer) p->on_disconnect(p); close(p->sock); + free(p->address); pthread_mutex_destroy(&p->mtx); free(p); diff --git a/send.c b/send.c index ce37366..c9dc260 100644 --- a/send.c +++ b/send.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include bool dragonnet_send_raw(DragonnetPeer *p, bool submit, const void *buf, size_t n) {