From f809c0a42812fbf12753a363d1f56742af0832ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20Austerm=C3=BChle?= Date: Mon, 10 Jan 2022 15:21:36 +0100 Subject: [PATCH 1/3] Add support for TCP keepalives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stephan Austermühle --- includes/protocol.h | 10 ++++++++++ src/render_list.c | 15 ++++++++++++++- src/render_submit_queue.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/includes/protocol.h b/includes/protocol.h index a528d3bd..c1fc3f90 100644 --- a/includes/protocol.h +++ b/includes/protocol.h @@ -39,6 +39,16 @@ extern "C" { #define RENDER_PORT 7654 #define XMLCONFIG_MAX 41 +/* TCP keepalive configuration */ +struct keepalive_settings { + int enabled; + int time; + int interval; + int probes; +}; + +extern struct keepalive_settings keepalives; + enum protoCmd { cmdIgnore, cmdRender, cmdDirty, cmdDone, cmdNotDone, cmdRenderPrio, cmdRenderBulk, cmdRenderLow }; struct protocol { diff --git a/src/render_list.c b/src/render_list.c index e87b9a4e..a6a62aa1 100644 --- a/src/render_list.c +++ b/src/render_list.c @@ -52,6 +52,8 @@ int main(int argc, char **argv) } #else +struct keepalive_settings keepalives; + static int minZoom = 0; static int maxZoom = MAX_ZOOM; static int verbose = 0; @@ -92,6 +94,11 @@ int main(int argc, char **argv) struct storage_backend * store; struct stat_info s; + memset(&keepalives, 0, sizeof(struct keepalive_settings)); + keepalives.time = 60; + keepalives.interval = 60; + keepalives.probes = 9; + while (1) { int option_index = 0; static struct option long_options[] = { @@ -102,6 +109,7 @@ int main(int argc, char **argv) {"min-y", required_argument, 0, 'y'}, {"max-y", required_argument, 0, 'Y'}, {"socket", required_argument, 0, 's'}, + {"keepalives", no_argument, 0, 'k'}, {"num-threads", required_argument, 0, 'n'}, {"max-load", required_argument, 0, 'l'}, {"tile-dir", required_argument, 0, 't'}, @@ -113,7 +121,7 @@ int main(int argc, char **argv) {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hvaz:Z:x:X:y:Y:s:m:t:n:l:f", long_options, &option_index); + c = getopt_long(argc, argv, "hvaz:Z:x:X:y:Y:s:km:t:n:l:f", long_options, &option_index); if (c == -1) { break; @@ -129,6 +137,10 @@ int main(int argc, char **argv) spath = strdup(optarg); break; + case 'k': /* -k, --keepalives */ + keepalives.enabled = 1; + break; + case 't': /* -t, --tile-dir */ tile_dir = strdup(optarg); break; @@ -202,6 +214,7 @@ int main(int argc, char **argv) fprintf(stderr, " -m, --map=MAP render tiles in this map (defaults to '" XMLCONFIG_DEFAULT "')\n"); fprintf(stderr, " -l, --max-load=LOAD sleep if load is this high (defaults to %d)\n", MAX_LOAD_OLD); fprintf(stderr, " -s, --socket=SOCKET|HOSTNAME:PORT unix domain socket name or hostname and port for contacting renderd\n"); + fprintf(stderr, " -k, --keepalives enable TCP keepalives"); fprintf(stderr, " -n, --num-threads=N the number of parallel request threads (default 1)\n"); fprintf(stderr, " -t, --tile-dir tile cache directory (defaults to '" HASH_PATH "')\n"); fprintf(stderr, " -z, --min-zoom=ZOOM filter input to only render tiles greater or equal to this zoom level (default is 0)\n"); diff --git a/src/render_submit_queue.c b/src/render_submit_queue.c index ff9dde55..48ddbc74 100644 --- a/src/render_submit_queue.c +++ b/src/render_submit_queue.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -306,10 +307,45 @@ int make_connection(const char *spath) continue; } + if (keepalives.enabled) { + fprintf(stderr, "Enabling TCP keepalives\n"); + int optval = 0; + socklen_t optlen = sizeof(optval); + + optval = 1; + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) { + perror("setsockopt()"); + close(fd); + exit(2); + } + +#ifdef LINUX + if (keepalives.time > 0 && setsockopt(fd, SOL_SOCKET, TCP_KEEPIDLE, &keepalives.time, sizeof(keepalives.time)) < 0) { + perror("setsockopt()"); + close(fd); + exit(2); + } + + if (keepalives.interval > 0 && setsockopt(fd, SOL_SOCKET, TCP_KEEPINTVL, &keepalives.interval, sizeof(keepalives.interval)) < 0) { + perror("setsockopt()"); + close(fd); + exit(2); + } + + if (keepalives.probes > 0 && setsockopt(fd, SOL_SOCKET, TCP_KEEPCNT, &keepalives.probes, sizeof(keepalives.probes)) < 0) { + perror("setsockopt()"); + close(fd); + exit(2); + } +#endif + + } + char resolved_addr[NI_MAXHOST]; char resolved_port[NI_MAXSERV]; int name_info = getnameinfo(rp->ai_addr, rp->ai_addrlen, resolved_addr, sizeof(resolved_addr), resolved_port, sizeof(resolved_port), NI_NUMERICHOST | NI_NUMERICSERV); if (name_info != 0) { + close(fd); fprintf(stderr, "cannot retrieve name info: %d\n", name_info); exit(2); } From ecdbfd031c1df66cd4c79578a2a551670b986baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20Austerm=C3=BChle?= Date: Mon, 10 Jan 2022 15:47:44 +0100 Subject: [PATCH 2/3] Provide keepalive config in all apps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stephan Austermühle --- src/render_expired.c | 4 ++++ src/render_old.c | 4 +++- src/speedtest.cpp | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/render_expired.c b/src/render_expired.c index a606229c..4d1326a7 100644 --- a/src/render_expired.c +++ b/src/render_expired.c @@ -61,6 +61,8 @@ int main(int argc, char **argv) } #else +struct keepalive_settings keepalives; + // tile marking arrays unsigned int **tile_requested; @@ -109,6 +111,8 @@ int main(int argc, char **argv) struct storage_backend * store; char name[PATH_MAX]; + memset(&keepalives, 0, sizeof(struct keepalive_settings)); + // excess_zoomlevels is how many zoom levels at the large end // we can ignore because their tiles will share one meta tile. // with the default METATILE==8 this is 3. diff --git a/src/render_old.c b/src/render_old.c index 900a5a39..8559a7e1 100644 --- a/src/render_old.c +++ b/src/render_old.c @@ -65,7 +65,7 @@ static struct timeval start, end; int foreground = 1; - +struct keepalive_settings keepalives; void display_rate(struct timeval start, struct timeval end, int num) { @@ -199,6 +199,8 @@ int main(int argc, char **argv) int dd, mm, yy; struct tm tm; + memset(&keepalives, 0, sizeof(struct keepalive_settings)); + while (1) { int option_index = 0; static struct option long_options[] = { diff --git a/src/speedtest.cpp b/src/speedtest.cpp index b9678a35..3a782f28 100644 --- a/src/speedtest.cpp +++ b/src/speedtest.cpp @@ -49,6 +49,8 @@ int main(int argc, char **argv) } #else +struct keepalive_settings keepalives; + static const int minZoom = 0; static const int maxZoom = 18; @@ -208,6 +210,8 @@ int main(int argc, char **argv) int verbose = 0; int numThreads = 1; + memset(&keepalives, 0, sizeof(struct keepalive_settings)); + while (1) { int option_index = 0; static struct option long_options[] = { From fed5caffcf32db6ba730a7fa8b684beb24a42d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20Austerm=C3=BChle?= Date: Mon, 10 Jan 2022 17:01:09 +0100 Subject: [PATCH 3/3] Make TCP keepalive parameters configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stephan Austermühle --- src/render_list.c | 53 +++++++++++++++++++++++++++++++++++---- src/render_submit_queue.c | 7 ++++++ 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/render_list.c b/src/render_list.c index a6a62aa1..768aa157 100644 --- a/src/render_list.c +++ b/src/render_list.c @@ -95,9 +95,6 @@ int main(int argc, char **argv) struct stat_info s; memset(&keepalives, 0, sizeof(struct keepalive_settings)); - keepalives.time = 60; - keepalives.interval = 60; - keepalives.probes = 9; while (1) { int option_index = 0; @@ -110,6 +107,7 @@ int main(int argc, char **argv) {"max-y", required_argument, 0, 'Y'}, {"socket", required_argument, 0, 's'}, {"keepalives", no_argument, 0, 'k'}, + {"keepalive-config", required_argument, 0, 'K'}, {"num-threads", required_argument, 0, 'n'}, {"max-load", required_argument, 0, 'l'}, {"tile-dir", required_argument, 0, 't'}, @@ -121,7 +119,7 @@ int main(int argc, char **argv) {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "hvaz:Z:x:X:y:Y:s:km:t:n:l:f", long_options, &option_index); + c = getopt_long(argc, argv, "hvaz:Z:x:X:y:Y:s:kK:m:t:n:l:f", long_options, &option_index); if (c == -1) { break; @@ -141,6 +139,50 @@ int main(int argc, char **argv) keepalives.enabled = 1; break; + case 'K': { /* --keepalive-config=:: */ + char * confstr = strdup(optarg); + if (!strlen(confstr)) { + fprintf(stderr, "No parameters provided for the TCP keepalive config\n"); + return 1; + } + + int val_count = 0; + const int val_count_expected = 3; + char * val[val_count_expected]; + char * p = strtok(confstr, ":"); + while (p != NULL) { + val[ val_count++ ] = p; + p = strtok(NULL, ":"); + } + + if (val_count != val_count_expected) { + fprintf(stderr, "Must provide exactly %d instead of %d arguments to --kepalive-config. See help for details.\n", val_count_expected, val_count); + return 1; + } + + keepalives.enabled = 1; + char * error_char = NULL; + keepalives.time = strtol(val[0], &error_char, 10); + if (*error_char != '\0') { + fprintf(stderr, "TCP keepalive time contains invalid character\n"); + return 1; + } + + keepalives.interval = strtol(val[1], &error_char, 10); + if (*error_char != '\0') { + fprintf(stderr, "TCP keepalive interval contains invalid character\n"); + return 1; + } + + keepalives.probes = strtol(val[2], &error_char, 10); + if (*error_char != '\0') { + fprintf(stderr, "TCP keepalive probe count contains invalid character\n"); + return 1; + } + + break; + } + case 't': /* -t, --tile-dir */ tile_dir = strdup(optarg); break; @@ -214,7 +256,8 @@ int main(int argc, char **argv) fprintf(stderr, " -m, --map=MAP render tiles in this map (defaults to '" XMLCONFIG_DEFAULT "')\n"); fprintf(stderr, " -l, --max-load=LOAD sleep if load is this high (defaults to %d)\n", MAX_LOAD_OLD); fprintf(stderr, " -s, --socket=SOCKET|HOSTNAME:PORT unix domain socket name or hostname and port for contacting renderd\n"); - fprintf(stderr, " -k, --keepalives enable TCP keepalives"); + fprintf(stderr, " -k, --keepalives enable TCP keepalives\n"); + fprintf(stderr, " -K, --keepalive-config=:: TCP keepalive configuration. Send keepalives after t seconds of inactivity, every intvl seconds. Consider connection broken after count probes. Implicitly enables TCP keepalives.\n"); fprintf(stderr, " -n, --num-threads=N the number of parallel request threads (default 1)\n"); fprintf(stderr, " -t, --tile-dir tile cache directory (defaults to '" HASH_PATH "')\n"); fprintf(stderr, " -z, --min-zoom=ZOOM filter input to only render tiles greater or equal to this zoom level (default is 0)\n"); diff --git a/src/render_submit_queue.c b/src/render_submit_queue.c index 48ddbc74..c6c7c441 100644 --- a/src/render_submit_queue.c +++ b/src/render_submit_queue.c @@ -309,6 +309,13 @@ int make_connection(const char *spath) if (keepalives.enabled) { fprintf(stderr, "Enabling TCP keepalives\n"); + if (keepalives.time > 0) { + fprintf(stderr, "TCP keepalives configuration: time=%d, interval=%d, probes=%d\n", + keepalives.time, + keepalives.interval, + keepalives.probes + ); + } int optval = 0; socklen_t optlen = sizeof(optval);