diff --git a/docs/usage.md b/docs/usage.md index 9c3dfb3a..b751a089 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -65,6 +65,7 @@ description: Guide to use arguments of FORT Validator. 51. [`--rsync.priority`](#--rsyncpriority) 53. [`--rsync.retry.count`](#--rsyncretrycount) 54. [`--rsync.retry.interval`](#--rsyncretryinterval) + 40. [`--rsync.transfer-timeout`](#--rsynctransfer-timeout) 55. [`--configuration-file`](#--configuration-file) 56. [`rsync.program`](#rsyncprogram) 57. [`rsync.arguments-recursive`](#rsyncarguments-recursive) @@ -103,6 +104,7 @@ description: Guide to use arguments of FORT Validator. [--rsync.priority=] [--rsync.retry.count=] [--rsync.retry.interval=] + [--rsync.transfer-timeout=] [--http.enabled=true|false] [--http.priority=] [--http.retry.count=] @@ -931,6 +933,17 @@ Whenever is necessary to execute an RSYNC, the validator will try at least one t Period of time (in seconds) to wait between each retry to execute an RSYNC. +### `--rsync.transfer-timeout` + +- **Type:** Integer +- **Availability:** `argv` and JSON +- **Default:** 900 +- **Range:** [0, [`UINT_MAX`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)] + +Maximum time in seconds that the rsync transfer can last. + +Once the connection is established with the server, the request will last a maximum of `rsync.transfer-timeout` seconds. A value of 0 means unlimited time. + ### `--configuration-file` - **Type:** String (Path to file) @@ -974,6 +987,7 @@ The configuration options are mostly the same as the ones from the `argv` interf "count": 1, "interval": 4 }, + "transfer-timeout": 0, "program": "rsync", "arguments-recursive": [ "-rtz", diff --git a/examples/config.json b/examples/config.json index 0c9ca9f2..034fff5c 100644 --- a/examples/config.json +++ b/examples/config.json @@ -56,6 +56,7 @@ "count": 2, "interval": 5 }, + "transfer-timeout": 900, "program": "rsync", "arguments-recursive": [ "--recursive", diff --git a/man/fort.8 b/man/fort.8 index 3411106c..ce02be33 100644 --- a/man/fort.8 +++ b/man/fort.8 @@ -1009,6 +1009,18 @@ By default, the value is \fI5\fR. .RE .P +.B \-\-rsync.transfer\-timeout=\fIUNSIGNED_INTEGER\fR +.RS 4 +Maximum time in seconds that the rsync process can last. +.P +Once the connection is established with the server, the request will last a +maximum of \fBrsync.transfer-timeout\fR seconds. A value of \fI0\fR means +unlimited time (default value). +.P +By default, it has a value of \fI900\fR. +.RE +.P + .B \-\-output.roa=\fIFILE\fR .RS 4 File where the ROAs will be printed in the configured format (see diff --git a/src/config.c b/src/config.c index e010a973..7f2af628 100644 --- a/src/config.c +++ b/src/config.c @@ -86,6 +86,7 @@ struct rpki_config { /* Interval (in seconds) between each retry */ unsigned int interval; } retry; + unsigned int transfer_timeout; char *program; struct { struct string_array flat; /* Deprecated */ @@ -486,6 +487,14 @@ static const struct option_field options[] = { /* Unlimited */ .max = 0, .deprecated = true, + }, { + .id = 3008, + .name = "rsync.transfer-timeout", + .type = >_uint, + .offset = offsetof(struct rpki_config, rsync.transfer_timeout), + .doc = "Maximum transfer time before killing the rsync process", + .min = 0, + .max = UINT_MAX, }, /* HTTP requests parameters */ @@ -946,6 +955,7 @@ set_default_values(void) rpki_config.rsync.strategy = pstrdup(""); rpki_config.rsync.retry.count = 1; rpki_config.rsync.retry.interval = 4; + rpki_config.rsync.transfer_timeout = 900; rpki_config.rsync.program = pstrdup("rsync"); string_array_init(&rpki_config.rsync.args.flat, flat_rsync_args, ARRAY_LEN(flat_rsync_args)); @@ -1342,6 +1352,12 @@ config_get_rsync_retry_interval(void) return rpki_config.rsync.retry.interval; } +long +config_get_rsync_transfer_timeout(void) +{ + return rpki_config.rsync.transfer_timeout; +} + char * config_get_rsync_program(void) { diff --git a/src/config.h b/src/config.h index 32dd17fd..70c3c398 100644 --- a/src/config.h +++ b/src/config.h @@ -44,6 +44,7 @@ bool config_get_rsync_enabled(void); unsigned int config_get_rsync_priority(void); unsigned int config_get_rsync_retry_count(void); unsigned int config_get_rsync_retry_interval(void); +long config_get_rsync_transfer_timeout(void); char *config_get_rsync_program(void); struct string_array const *config_get_rsync_args(void); bool config_get_http_enabled(void); diff --git a/src/rsync/rsync.c b/src/rsync/rsync.c index 2425a95b..c48cc36a 100644 --- a/src/rsync/rsync.c +++ b/src/rsync/rsync.c @@ -154,21 +154,41 @@ read_pipe(int fd_pipe[2][2], int type) { char buffer[4096]; ssize_t count; - int error; + struct timeval timeout; + fd_set read_fds; + int error, res; while (1) { - count = read(fd_pipe[type][0], buffer, sizeof(buffer)); - if (count == -1) { - error = errno; - if (error == EINTR) + timeout.tv_sec = config_get_rsync_transfer_timeout(); + timeout.tv_usec = 0; + + FD_ZERO(&read_fds); + FD_SET(fd_pipe[type][0], &read_fds); + + res = select(fd_pipe[type][0] + 1, &read_fds, NULL, NULL, &timeout); + if (res == 0) { + pr_val_err("rsync transfer timeout reached"); + close(fd_pipe[type][0]); + return 1; + } else if (res < 0) { + if (res == EINTR) continue; - close(fd_pipe[type][0]); /* Close read end */ - pr_val_err("rsync buffer read error: %s", - strerror(error)); - return -error; + close(fd_pipe[type][0]); + return 1; + } else { + count = read(fd_pipe[type][0], buffer, sizeof(buffer)); + if (count == -1) { + error = errno; + if (error == EINTR) + continue; + close(fd_pipe[type][0]); /* Close read end */ + pr_val_err("rsync buffer read error: %s", + strerror(error)); + return -error; + } + if (count == 0) + break; } - if (count == 0) - break; log_buffer(buffer, count, type); } @@ -276,7 +296,7 @@ rsync_download(char const *src, char const *dst, bool is_directory) /* This code is run by us. */ error = read_pipes(fork_fds); if (error) - kill(child_pid, SIGCHLD); /* Stop the child */ + kill(child_pid, SIGTERM); /* Stop the child */ error = waitpid(child_pid, &child_status, 0); do {