From c6a2150a7da730ea1580673a8680a2a3ec505673 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Tue, 23 Feb 2016 10:46:40 -0800 Subject: [PATCH] Initial pass at async resolving. This is ugly and leaks memory and I hate it, so dedicated thread incoming. --- adsbus/Makefile | 4 +-- adsbus/incoming.c | 42 ++++++++++++++------------ adsbus/outgoing.c | 30 +++++++++--------- adsbus/resolve.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++ adsbus/resolve.h | 6 ++++ 5 files changed, 124 insertions(+), 35 deletions(-) create mode 100644 adsbus/resolve.c create mode 100644 adsbus/resolve.h diff --git a/adsbus/Makefile b/adsbus/Makefile index 831da8e..6223b8c 100644 --- a/adsbus/Makefile +++ b/adsbus/Makefile @@ -1,11 +1,11 @@ CC ?= clang CFLAGS ?= -Wall -Werror -O4 -g --std=gnu11 --pedantic-errors -fPIE -pie -fstack-protector-strong LDFLAGS ?= $(CFLAGS) -Wl,-z,relro -Wl,-z,now -LIBS ?= -ljansson +LIBS ?= -ljansson -lanl OBJ_NETWORK = incoming.o outgoing.o receive.o send.o OBJ_PROTOCOL = airspy_adsb.o beast.o json.o raw.o stats.o -OBJ_UTIL = buf.o hex.o opts.o packet.o peer.o rand.o server.o uuid.o wakeup.o +OBJ_UTIL = buf.o hex.o opts.o packet.o peer.o rand.o resolve.o server.o uuid.o wakeup.o all: adsbus diff --git a/adsbus/incoming.c b/adsbus/incoming.c index 9797373..6466e0f 100644 --- a/adsbus/incoming.c +++ b/adsbus/incoming.c @@ -11,6 +11,7 @@ #include #include "peer.h" +#include "resolve.h" #include "wakeup.h" #include "uuid.h" @@ -21,6 +22,8 @@ struct incoming { char id[UUID_LEN]; char *node; char *service; + struct addrinfo *addrs; + const char *error; uint32_t attempt; incoming_connection_handler handler; void *passthrough; @@ -71,25 +74,9 @@ static void incoming_del(struct incoming *incoming) { free(incoming); } -static void incoming_resolve(struct incoming *incoming) { - fprintf(stderr, "I %s: Resolving %s/%s...\n", incoming->id, incoming->node, incoming->service); - - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - .ai_flags = AI_PASSIVE | AI_V4MAPPED | AI_ADDRCONFIG, - }; - - struct addrinfo *addrs; - int gai_err = getaddrinfo(incoming->node, incoming->service, &hints, &addrs); - if (gai_err) { - fprintf(stderr, "I %s: Failed to resolve %s/%s: %s\n", incoming->id, incoming->node, incoming->service, gai_strerror(gai_err)); - incoming_retry(incoming); - return; - } - +static void incoming_listen(struct incoming *incoming) { struct addrinfo *addr; - for (addr = addrs; addr; addr = addr->ai_next) { + for (addr = incoming->addrs; addr; addr = addr->ai_next) { char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; assert(getnameinfo(addr->ai_addr, addr->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0); fprintf(stderr, "I %s: Listening on %s/%s...\n", incoming->id, hbuf, sbuf); @@ -110,7 +97,7 @@ static void incoming_resolve(struct incoming *incoming) { break; } - freeaddrinfo(addrs); + freeaddrinfo(incoming->addrs); if (addr == NULL) { fprintf(stderr, "I %s: Failed to bind any addresses for %s/%s...\n", incoming->id, incoming->node, incoming->service); @@ -122,6 +109,23 @@ static void incoming_resolve(struct incoming *incoming) { peer_epoll_add((struct peer *) incoming, EPOLLIN); } +static void incoming_resolve_handler(struct peer *peer) { + struct incoming *incoming = (struct incoming *) peer; + if (incoming->addrs) { + incoming_listen(incoming); + } else { + fprintf(stderr, "I %s: Failed to resolve %s/%s: %s\n", incoming->id, incoming->node, incoming->service, incoming->error); + incoming_retry(incoming); + } +} + +static void incoming_resolve(struct incoming *incoming) { + fprintf(stderr, "I %s: Resolving %s/%s...\n", incoming->id, incoming->node, incoming->service); + incoming->peer.fd = -1; + incoming->peer.event_handler = incoming_resolve_handler; + resolve((struct peer *) incoming, incoming->node, incoming->service, AI_PASSIVE, &incoming->addrs, &incoming->error); +} + static void incoming_resolve_wrapper(struct peer *peer) { incoming_resolve((struct incoming *) peer); } diff --git a/adsbus/outgoing.c b/adsbus/outgoing.c index 57d6de6..29a70cc 100644 --- a/adsbus/outgoing.c +++ b/adsbus/outgoing.c @@ -9,6 +9,7 @@ #include #include "peer.h" +#include "resolve.h" #include "wakeup.h" #include "uuid.h" @@ -21,6 +22,7 @@ struct outgoing { char *service; struct addrinfo *addrs; struct addrinfo *addr; + const char *error; uint32_t attempt; outgoing_connection_handler handler; void *passthrough; @@ -110,22 +112,22 @@ static void outgoing_connect_result(struct outgoing *outgoing, int result) { } } +static void outgoing_resolve_handler(struct peer *peer) { + struct outgoing *outgoing = (struct outgoing *) peer; + if (outgoing->addrs) { + outgoing->addr = outgoing->addrs; + outgoing_connect_next(outgoing); + } else { + fprintf(stderr, "O %s: Failed to resolve %s/%s: %s\n", outgoing->id, outgoing->node, outgoing->service, outgoing->error); + outgoing_retry(outgoing); + } +} + static void outgoing_resolve(struct outgoing *outgoing) { fprintf(stderr, "O %s: Resolving %s/%s...\n", outgoing->id, outgoing->node, outgoing->service); - - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - }; - - int gai_err = getaddrinfo(outgoing->node, outgoing->service, &hints, &outgoing->addrs); - if (gai_err) { - fprintf(stderr, "O %s: Failed to resolve %s/%s: %s\n", outgoing->id, outgoing->node, outgoing->service, gai_strerror(gai_err)); - outgoing_retry(outgoing); - return; - } - outgoing->addr = outgoing->addrs; - outgoing_connect_next(outgoing); + outgoing->peer.fd = -1; + outgoing->peer.event_handler = outgoing_resolve_handler; + resolve((struct peer *) outgoing, outgoing->node, outgoing->service, 0, &outgoing->addrs, &outgoing->error); } static void outgoing_resolve_wrapper(struct peer *peer) { diff --git a/adsbus/resolve.c b/adsbus/resolve.c new file mode 100644 index 0000000..c2bccc1 --- /dev/null +++ b/adsbus/resolve.c @@ -0,0 +1,77 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "peer.h" + +#include "resolve.h" + +struct resolve { + struct peer peer; + + struct addrinfo **addrs; + const char **error; + + struct peer *inner_peer; + + struct addrinfo ar_request; + struct gaicb gaicb; + struct gaicb *requests[1]; + + struct sigevent sev; +}; + +static void resolve_handler(struct peer *peer) { + struct resolve *res = (struct resolve *) peer; + + assert(!close(res->peer.fd)); + + int err = gai_error(&res->gaicb); + if (err == 0) { + *res->addrs = res->gaicb.ar_result; + *res->error = NULL; + } else { + *res->addrs = NULL; + *res->error = gai_strerror(err); + } + struct peer *inner_peer = res->inner_peer; + free(res); + inner_peer->event_handler(inner_peer); +} + +static void resolve_callback(union sigval val) { + assert(!close(val.sival_int)); +} + +void resolve(struct peer *peer, const char *node, const char *service, int flags, struct addrinfo **addrs, const char **error) { + struct resolve *res = malloc(sizeof(*res)); + res->addrs = addrs; + res->error = error; + res->inner_peer = peer; + + int fds[2]; + assert(!pipe2(fds, O_NONBLOCK)); + res->peer.fd = fds[0]; + res->peer.event_handler = resolve_handler; + peer_epoll_add((struct peer *) res, EPOLLRDHUP); + + res->requests[0] = &res->gaicb; + res->gaicb.ar_name = node; + res->gaicb.ar_service = service; + res->gaicb.ar_request = &res->ar_request; + res->ar_request.ai_family = AF_UNSPEC; + res->ar_request.ai_socktype = SOCK_STREAM; + res->ar_request.ai_protocol = 0; + res->ar_request.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | flags; + + res->sev.sigev_notify = SIGEV_THREAD; + res->sev.sigev_value.sival_int = fds[1]; + res->sev.sigev_notify_function = resolve_callback; + res->sev.sigev_notify_attributes = NULL; + + assert(!getaddrinfo_a(GAI_NOWAIT, res->requests, 1, &res->sev)); +} diff --git a/adsbus/resolve.h b/adsbus/resolve.h new file mode 100644 index 0000000..d81777c --- /dev/null +++ b/adsbus/resolve.h @@ -0,0 +1,6 @@ +#pragma once + +struct peer; +struct addrinfo; + +void resolve(struct peer *, const char *, const char *, int, struct addrinfo **, const char **);