aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordberg.se>2019-04-25 11:57:33 +0200
committerThomas Gschwantner <tharre3@gmail.com>2019-05-26 01:07:46 +0200
commite3ee9edc258eaaed4bcc2cd948fdca2249c369b5 (patch)
tree702f3d5c66d158cad476a186495df943bbe94dbb
parentNo need to clear bits in pollfd revents (diff)
downloadwg-dynamic-e3ee9edc258eaaed4bcc2cd948fdca2249c369b5.tar.xz
wg-dynamic-e3ee9edc258eaaed4bcc2cd948fdca2249c369b5.zip
Use blocking I/O in client
Avoiding the unnecessary complexity of non-blocking I/O.
-rw-r--r--wg-dynamic-client.c158
1 files changed, 39 insertions, 119 deletions
diff --git a/wg-dynamic-client.c b/wg-dynamic-client.c
index 1bef297..4e3ea24 100644
--- a/wg-dynamic-client.c
+++ b/wg-dynamic-client.c
@@ -14,17 +14,16 @@
#include <arpa/inet.h>
#include <libmnl/libmnl.h>
#include <linux/rtnetlink.h>
+#include <sys/param.h>
#include "common.h"
#include "dbg.h"
#include "netlink.h"
-#define LEASE_CHECK_INTERVAL 1000 /* 1s is convenient for testing */
-
static const char *progname;
static const char *wg_interface;
static wg_device *device = NULL;
-static struct pollfd pollfds[1];
+static int our_fd = -1;
static struct in6_addr our_lladdr = { 0 };
static struct wg_combined_ip our_gaddr4 = { 0 };
static struct wg_combined_ip our_gaddr6 = { 0 };
@@ -171,29 +170,9 @@ static bool get_and_validate_local_addrs(uint32_t ifindex,
return !IN6_IS_ADDR_UNSPECIFIED(cb_data.lladdr);
}
-#if 0
-static void dump_leases()
+static int try_connect(int *fd)
{
- char ip4str[INET6_ADDRSTRLEN], ip6str[INET6_ADDRSTRLEN];
- struct wg_dynamic_lease *l = &our_lease;
-
- if (l->start == 0) {
- debug("lease NONE\n");
- return;
- }
-
- debug("lease %u %u %s/%u %s/%u\n", l->start + l->leasetime,
- l->start + l->leasetime - current_time(),
- inet_ntop(AF_INET, &l->ip4.ip.ip4, ip4str, INET6_ADDRSTRLEN),
- l->ip4.cidr,
- inet_ntop(AF_INET6, &l->ip6.ip.ip6, ip6str, INET6_ADDRSTRLEN),
- l->ip6.cidr);
-}
-#endif
-
-static int do_connect(int *fd)
-{
- int res;
+ struct timeval tval = {.tv_sec = 1, .tv_usec = 0 };
struct sockaddr_in6 our_addr = {
.sin6_family = AF_INET6,
.sin6_addr = our_lladdr,
@@ -210,49 +189,39 @@ static int do_connect(int *fd)
if (*fd < 0)
fatal("Creating a socket failed");
+ if (setsockopt(*fd, SOL_SOCKET, SO_RCVTIMEO, &tval, sizeof tval) == -1)
+ fatal("Setting socket option failed");
+
if (bind(*fd, (struct sockaddr *)&our_addr, sizeof(our_addr)))
fatal("Binding socket failed");
if (inet_pton(AF_INET6, WG_DYNAMIC_ADDR, &their_addr.sin6_addr) != 1)
fatal("inet_pton()");
+
if (connect(*fd, (struct sockaddr *)&their_addr,
sizeof(struct sockaddr_in6))) {
char out[INET6_ADDRSTRLEN];
+
if (!inet_ntop(their_addr.sin6_family, &their_addr.sin6_addr,
out, sizeof out))
fatal("inet_ntop()");
debug("Connecting to [%s]:%u failed: %s\n", out,
ntohs(their_addr.sin6_port), strerror(errno));
+
if (close(*fd))
debug("Closing socket failed: %s\n", strerror(errno));
*fd = -1;
return -1;
}
- res = fcntl(*fd, F_GETFL, 0);
- if (res < 0 || fcntl(*fd, F_SETFL, res | O_NONBLOCK) < 0)
- fatal("Setting socket to nonblocking failed");
-
return 0;
}
-static size_t connect_and_send(unsigned char *buf, size_t *len)
-{
- size_t ret;
- if (pollfds[0].fd < 0)
- if (do_connect(&pollfds[0].fd))
- return 0;
- ret = send_message(pollfds[0].fd, buf, len);
- return ret;
-}
-
-static bool request_ip(struct wg_dynamic_request *req,
- const struct wg_dynamic_lease *lease)
+static void request_ip(int fd, const struct wg_dynamic_lease *lease)
{
unsigned char buf[MAX_RESPONSE_SIZE + 1];
char addrstr[INET6_ADDRSTRLEN];
size_t msglen;
- size_t written;
msglen = 0;
msglen += print_to_buf((char *)buf, sizeof buf, msglen, "%s=%d\n",
@@ -277,50 +246,20 @@ static bool request_ip(struct wg_dynamic_request *req,
msglen += print_to_buf((char *)buf, sizeof buf, msglen, "\n");
- written = connect_and_send(buf, &msglen);
- if (msglen == 0)
- return true;
-
- debug("Socket %d blocking with %lu bytes to write, postponing\n",
- pollfds[0].fd, msglen);
- send_later(req, buf + written, msglen);
- return false;
+ send_message(fd, buf, &msglen);
}
-static int maybe_refresh_lease(uint32_t now, struct wg_dynamic_lease *lease,
- struct wg_dynamic_request *req)
+static uint32_t time_until_refresh(uint32_t now, struct wg_dynamic_lease *lease)
{
- if (now > lease->start + (lease->leasetime * 2) / 3) {
- debug("Refreshing lease expiring on %u\n",
- lease->start + lease->leasetime);
- request_ip(req, lease);
- return 0;
- }
+ uint32_t refresh_at;
- return 1;
-}
-
-static bool lease_is_valid(uint32_t now, struct wg_dynamic_lease *lease)
-{
- return now < lease->start + lease->leasetime;
-}
-
-static void maybe_remove_lease(uint32_t now, struct wg_dynamic_lease *lease)
-{
- if (!lease_is_valid(now, lease))
- memset(lease, 0, sizeof *lease);
-}
-
-static void check_leases(struct wg_dynamic_request *req)
-{
- uint32_t now = current_time();
+ if (lease->leasetime == 0)
+ return 0;
+ refresh_at = lease->start + (lease->leasetime * 8) / 10;
- if (!lease_is_valid(now, &our_lease))
- request_ip(req, NULL);
- else {
- maybe_remove_lease(now, &our_lease);
- maybe_refresh_lease(now, &our_lease, req);
- }
+ if (refresh_at < now)
+ return 0;
+ return refresh_at - now;
}
static int handle_received_lease(const struct wg_dynamic_request *req)
@@ -387,9 +326,8 @@ static int handle_received_lease(const struct wg_dynamic_request *req)
static void cleanup()
{
wg_free_device(device);
- if (pollfds[0].fd >= 0)
- if (close(pollfds[0].fd))
- debug("Failed to close fd");
+ if (our_fd != -1 && close(our_fd))
+ debug("Failed to close fd %d\n", our_fd);
}
static bool handle_error(int fd, int ret)
@@ -446,10 +384,17 @@ static bool handle_response(int fd, struct wg_dynamic_request *req)
return true;
}
+static bool read_response(int fd, struct wg_dynamic_request *req,
+ bool (*success)(int, struct wg_dynamic_request *),
+ bool (*error)(int, int))
+{
+ return handle_request(fd, req, success, error);
+}
+
int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
{
+ int *fd = &our_fd;
struct wg_dynamic_request req = { 0 };
- uint32_t now = current_time();
progname = argv[0];
if (argc != 2)
@@ -462,8 +407,6 @@ int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
if (atexit(cleanup))
die("Failed to set exit function\n");
- if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
- fatal("Unable to ignore SIGPIPE");
if (!get_and_validate_local_addrs(device->ifindex, &our_lladdr,
&our_gaddr4, &our_gaddr6))
@@ -475,9 +418,11 @@ int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
debug("%s: %s\n", wg_interface,
inet_ntop(AF_INET6, &our_lladdr, lladr_str, sizeof lladr_str));
+ /* If we have an address configured, let's assume it's from a
+ * lease in order to get renewal done. */
if (our_gaddr4.ip.ip4.s_addr ||
!IN6_IS_ADDR_UNSPECIFIED(&our_gaddr6.ip.ip6)) {
- our_lease.start = now;
+ our_lease.start = current_time();
our_lease.leasetime = 15;
memcpy(&our_lease.ip4, &our_gaddr4,
sizeof(struct wg_combined_ip));
@@ -485,42 +430,17 @@ int main(int argc __attribute__((unused)), char *argv[] __attribute__((unused)))
sizeof(struct wg_combined_ip));
}
- /* TODO: use a blocking socket instead of the unnecessary
- * complexity of nonblocking */
-
- pollfds[0] = (struct pollfd){ .fd = -1, .events = POLLIN };
while (1) {
- size_t off;
- int nevents = poll(pollfds, 1, LEASE_CHECK_INTERVAL);
-
- if (nevents == -1)
- fatal("poll()");
+ sleep(MAX(1, time_until_refresh(current_time(), &our_lease)));
- if (nevents == 0) {
- /* FIXME: if there's any risk for this path to
- * be starving, maybe do this regardless of
- * socket readiness? */
- check_leases(&req);
+ if (*fd == -1 && try_connect(fd))
continue;
- }
- if (pollfds[0].revents & POLLOUT) {
- debug("sending, trying again with %lu bytes\n",
- req.buflen);
- off = send_message(pollfds[0].fd, req.buf, &req.buflen);
- if (req.buflen)
- memmove(req.buf, req.buf + off, req.buflen);
- else
- close_connection(&pollfds[0].fd, &req);
- }
+ request_ip(*fd, &our_lease);
- if (pollfds[0].revents & POLLIN) {
- if (handle_request(pollfds[0].fd, &req, handle_response,
- handle_error))
- close_connection(&pollfds[0].fd, &req);
- else if (req.buf)
- pollfds[0].events |= POLLOUT;
- }
+ while (!read_response(*fd, &req, handle_response, handle_error))
+ sleep(1);
+ close_connection(fd, &req);
}
return 0;