From b6a582e95a073542000b31ee6fb73e8c7681c523 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Mon, 29 Feb 2016 22:17:37 -0800 Subject: [PATCH] Do flow-specific setsockopt() before accept() --- adsbus/flow.c | 8 ++++++++ adsbus/flow.h | 10 ++++------ adsbus/incoming.c | 6 ++++-- adsbus/outgoing.c | 2 +- adsbus/receive.c | 2 +- adsbus/send.c | 3 ++- adsbus/socket.c | 33 +++++++++++++++++---------------- adsbus/socket.h | 11 ++++++----- 8 files changed, 43 insertions(+), 32 deletions(-) diff --git a/adsbus/flow.c b/adsbus/flow.c index 4aa46a7..b7db29c 100644 --- a/adsbus/flow.c +++ b/adsbus/flow.c @@ -1,9 +1,17 @@ #include #include "buf.h" +#include "socket.h" #include "flow.h" +void flow_socket_connected(int fd, struct flow *flow) { + socket_connected(fd); + if (flow->socket_connected) { + flow->socket_connected(fd); + } +} + bool flow_hello(int fd, struct flow *flow, void *passthrough) { if (!flow->get_hello) { return true; diff --git a/adsbus/flow.h b/adsbus/flow.h index dfe9d07..ddacf0a 100644 --- a/adsbus/flow.h +++ b/adsbus/flow.h @@ -6,15 +6,13 @@ struct buf; struct peer; -typedef void (*flow_bound_socket_init)(int); -typedef void (*flow_new)(int, void *, struct peer *); -typedef void (*flow_get_hello)(struct buf **, void *); struct flow { const char *name; - flow_bound_socket_init bound_socket_init; - flow_new new; - flow_get_hello get_hello; + void (*socket_connected)(int); + void (*new)(int, void *, struct peer *); + void (*get_hello)(struct buf **, void *); uint32_t *ref_count; }; +void flow_socket_connected(int, struct flow *); bool flow_hello(int, struct flow *, void *); diff --git a/adsbus/incoming.c b/adsbus/incoming.c index 62da1bd..1b93991 100644 --- a/adsbus/incoming.c +++ b/adsbus/incoming.c @@ -95,7 +95,7 @@ static void incoming_listen(struct incoming *incoming) { incoming->peer.fd = socket(addr->ai_family, addr->ai_socktype | SOCK_CLOEXEC, addr->ai_protocol); assert(incoming->peer.fd >= 0); - socket_pre_bind_init(incoming->peer.fd); + socket_pre_bind(incoming->peer.fd); if (bind(incoming->peer.fd, addr->ai_addr, addr->ai_addrlen) != 0) { fprintf(stderr, "I %s: Failed to bind to %s/%s: %s\n", incoming->id, hbuf, sbuf, strerror(errno)); @@ -103,7 +103,9 @@ static void incoming_listen(struct incoming *incoming) { continue; } - socket_bound_init(incoming->peer.fd); + socket_pre_listen(incoming->peer.fd); + // Options are inherited through accept() + flow_socket_connected(incoming->peer.fd, incoming->flow); assert(listen(incoming->peer.fd, 255) == 0); break; diff --git a/adsbus/outgoing.c b/adsbus/outgoing.c index 23bdeb1..ce37b9f 100644 --- a/adsbus/outgoing.c +++ b/adsbus/outgoing.c @@ -96,7 +96,7 @@ static void outgoing_connect_result(struct outgoing *outgoing, int result) { case 0: fprintf(stderr, "O %s: Connected to %s/%s\n", outgoing->id, hbuf, sbuf); freeaddrinfo(outgoing->addrs); - socket_connected_init(outgoing->peer.fd); + flow_socket_connected(outgoing->peer.fd, outgoing->flow); outgoing->attempt = 0; int fd = outgoing->peer.fd; outgoing->peer.fd = -1; diff --git a/adsbus/receive.c b/adsbus/receive.c index 3839498..3537139 100644 --- a/adsbus/receive.c +++ b/adsbus/receive.c @@ -137,7 +137,7 @@ static void receive_read(struct peer *peer) { static void receive_new(int fd, void __attribute__((unused)) *passthrough, struct peer *on_close) { peer_count_in++; - socket_receive_init(fd); + socket_receive(fd); struct receive *receive = malloc(sizeof(*receive)); assert(receive); diff --git a/adsbus/send.c b/adsbus/send.c index 6d3cd7f..326c365 100644 --- a/adsbus/send.c +++ b/adsbus/send.c @@ -38,6 +38,7 @@ static void send_get_hello(struct buf **, void *); static struct flow _send_flow = { .name = "send", + .socket_connected = socket_connected_send, .new = send_new, .get_hello = send_get_hello, .ref_count = &peer_count_out, @@ -104,7 +105,7 @@ static void send_new(int fd, void *passthrough, struct peer *on_close) { peer_count_out++; - socket_send_init(fd); + socket_send(fd); struct send *send = malloc(sizeof(*send)); assert(send); diff --git a/adsbus/socket.c b/adsbus/socket.c index 5e34ccb..f90bdf0 100644 --- a/adsbus/socket.c +++ b/adsbus/socket.c @@ -7,23 +7,19 @@ #include "socket.h" -void socket_pre_bind_init(int fd) { +void socket_pre_bind(int fd) { // Called by transport code; safe to assume that fd is a socket int optval = 1; assert(!setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval))); } -void socket_bound_init(int fd) { +void socket_pre_listen(int fd) { // Called by transport code; safe to assume that fd is a socket int qlen = 5; assert(!setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &qlen, sizeof(qlen))); - - // These options are inherited through accept() - // Verified by flamingcow on kernel 4.2.0 - socket_connected_init(fd); } -void socket_connected_init(int fd) { +void socket_connected(int fd) { // Called by transport code; safe to assume that fd is a socket int optval = 1; assert(!setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval))); @@ -35,25 +31,30 @@ void socket_connected_init(int fd) { assert(!setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval))); } -void socket_send_init(int fd) { - // Called by data flow code; NOT safe to assume that fd is a socket - int res = shutdown(fd, SHUT_RD); - assert(res == 0 || (res == -1 && errno == ENOTSOCK)); - +void socket_connected_send(int fd) { int optval = 128; // Lowest value that the kernel will accept - res = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval)); - assert(res == 0 || (res == -1 && errno == ENOTSOCK)); + int res = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &optval, sizeof(optval)); + if (res == -1 && errno == ENOTSOCK) { + return; + } + assert(res == 0); optval = 128; // Lowest value that the kernel will accept res = setsockopt(fd, IPPROTO_TCP, TCP_WINDOW_CLAMP, &optval, sizeof(optval)); - assert(res == 0 || (res == -1 && errno == ENOTSOCK)); + assert(res == 0); optval = 60000; // 60s res = setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &optval, sizeof(optval)); + assert(res == 0); +} + +void socket_send(int fd) { + // Called by data flow code; NOT safe to assume that fd is a socket + int res = shutdown(fd, SHUT_RD); assert(res == 0 || (res == -1 && errno == ENOTSOCK)); } -void socket_receive_init(int fd) { +void socket_receive(int fd) { // Called by data flow code; NOT safe to assume that fd is a socket int res = shutdown(fd, SHUT_WR); assert(res == 0 || (res == -1 && errno == ENOTSOCK)); diff --git a/adsbus/socket.h b/adsbus/socket.h index d5ae8dd..b1989a6 100644 --- a/adsbus/socket.h +++ b/adsbus/socket.h @@ -1,7 +1,8 @@ #pragma once -void socket_pre_bind_init(int); -void socket_bound_init(int); -void socket_connected_init(int); -void socket_send_init(int); -void socket_receive_init(int); +void socket_pre_bind(int); +void socket_pre_listen(int); +void socket_connected(int); +void socket_connected_send(int); +void socket_send(int); +void socket_receive(int);