pespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-netif/+/40479?usp=email )
Change subject: stream: Support configuring TCP_USER_TIMEOUT parameter ......................................................................
stream: Support configuring TCP_USER_TIMEOUT parameter
This is set for instance in libosmo-abis, and may affect how keepalive behaves. See man 7 tcp for more information.
Change-Id: I22c7df92b463cf4ca82854a12ec24337d53e8b20 --- M TODO-RELEASE M include/osmocom/netif/stream.h M include/osmocom/netif/stream_private.h M src/stream.c M src/stream_cli.c M src/stream_srv.c 6 files changed, 50 insertions(+), 1 deletion(-)
Approvals: osmith: Looks good to me, but someone else must approve Jenkins Builder: Verified fixeria: Looks good to me, but someone else must approve pespin: Looks good to me, approved
diff --git a/TODO-RELEASE b/TODO-RELEASE index e519375..6340cdf 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -8,3 +8,4 @@ # If any interfaces have been removed or changed since the last public release: c:r:0. #library what description / commit summary line stream add OSMO_STREAM_{CLI,SRV,SRV_LINK}_TCP_SOCKOPT_KEEP*, osmo_stream_srv_set_param() +stream add OSMO_STREAM_{CLI,SRV,SRV_LINK}_TCP_SOCKOPT_USER_TIMEOUT diff --git a/include/osmocom/netif/stream.h b/include/osmocom/netif/stream.h index 7b74e87..8c3fad5 100644 --- a/include/osmocom/netif/stream.h +++ b/include/osmocom/netif/stream.h @@ -103,6 +103,7 @@ OSMO_STREAM_SRV_LINK_PAR_TCP_SOCKOPT_KEEPIDLE, /* int: seconds */ OSMO_STREAM_SRV_LINK_PAR_TCP_SOCKOPT_KEEPINTVL, /* int: seconds */ OSMO_STREAM_SRV_LINK_PAR_TCP_SOCKOPT_KEEPCNT, /* int: Number of probes */ + OSMO_STREAM_SRV_LINK_PAR_TCP_SOCKOPT_USER_TIMEOUT, /* unsigned int: 0 "system default", >0 see sockopt TCP_USER_TIMEOUT */ };
int osmo_stream_srv_link_set_param(struct osmo_stream_srv_link *link, enum osmo_stream_srv_link_param par, @@ -159,6 +160,7 @@ OSMO_STREAM_SRV_PAR_TCP_SOCKOPT_KEEPIDLE, /* int: seconds */ OSMO_STREAM_SRV_PAR_TCP_SOCKOPT_KEEPINTVL, /* int: seconds */ OSMO_STREAM_SRV_PAR_TCP_SOCKOPT_KEEPCNT, /* int: Number of probes */ + OSMO_STREAM_SRV_PAR_TCP_SOCKOPT_USER_TIMEOUT, /* unsigned int: 0 "system default", >0 see sockopt TCP_USER_TIMEOUT */ }; int osmo_stream_srv_set_param(struct osmo_stream_srv *conn, enum osmo_stream_srv_param par, void *val, size_t val_len); @@ -274,6 +276,7 @@ OSMO_STREAM_CLI_PAR_TCP_SOCKOPT_KEEPIDLE, /* int: seconds */ OSMO_STREAM_CLI_PAR_TCP_SOCKOPT_KEEPINTVL, /* int: seconds */ OSMO_STREAM_CLI_PAR_TCP_SOCKOPT_KEEPCNT, /* int: Number of probes */ + OSMO_STREAM_CLI_PAR_TCP_SOCKOPT_USER_TIMEOUT, /* unsigned int: 0 "system default", >0 see sockopt TCP_USER_TIMEOUT */ };
int osmo_stream_cli_set_param(struct osmo_stream_cli *cli, enum osmo_stream_cli_param par, diff --git a/include/osmocom/netif/stream_private.h b/include/osmocom/netif/stream_private.h index 7fb0de6..154e7f7 100644 --- a/include/osmocom/netif/stream_private.h +++ b/include/osmocom/netif/stream_private.h @@ -46,8 +46,10 @@
struct stream_tcp_pars { struct stream_tcp_keepalive_pars ka; - /* Others like TCP_USER_TIMEOUT will be added here in the future. */ + bool user_timeout_present; + unsigned int user_timeout_value; }; +int stream_setsockopt_tcp_user_timeout(int fd, unsigned int user_timeout);
struct osmo_io_fd; struct msghdr; diff --git a/src/stream.c b/src/stream.c index a1e077a..339dd6a 100644 --- a/src/stream.c +++ b/src/stream.c @@ -240,6 +240,17 @@ return 0; }
+int stream_setsockopt_tcp_user_timeout(int fd, unsigned int user_timeout) +{ + int ret = setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout, sizeof(user_timeout)); + if (ret < 0) { + ret = errno; + LOGP(DLINP, LOGL_ERROR, "Failed to set TCP_USER_TIMEOUT on fd %d: %s\n", fd, strerror(ret)); + return -ret; + } + return 0; +} + int stream_tcp_keepalive_pars_apply(int fd, const struct stream_tcp_keepalive_pars *tkp) { int ret; diff --git a/src/stream_cli.c b/src/stream_cli.c index 1a2a768..c623fff 100644 --- a/src/stream_cli.c +++ b/src/stream_cli.c @@ -1291,6 +1291,11 @@ ret = stream_tcp_keepalive_pars_apply(fd, &cli->tcp_pars.ka); if (ret < 0) goto error_close_socket; + if (cli->tcp_pars.user_timeout_present) { + ret = stream_setsockopt_tcp_user_timeout(fd, cli->tcp_pars.user_timeout_value); + if (ret < 0) + goto error_close_socket; + } }
switch (cli->mode) { @@ -1571,6 +1576,14 @@ if (stream_cli_is_opened(cli)) return stream_setsockopt_tcp_keepcnt(osmo_stream_cli_get_fd(cli), cli->tcp_pars.ka.probes_value); break; + case OSMO_STREAM_CLI_PAR_TCP_SOCKOPT_USER_TIMEOUT: + if (!val || val_len != sizeof(unsigned int)) + return -EINVAL; + cli->tcp_pars.user_timeout_present = true; + cli->tcp_pars.user_timeout_value = *(int *)val; + if (stream_cli_is_opened(cli)) + return stream_setsockopt_tcp_user_timeout(osmo_stream_cli_get_fd(cli), cli->tcp_pars.user_timeout_value); + break; default: return -ENOENT; }; diff --git a/src/stream_srv.c b/src/stream_srv.c index e80d5e4..2e80909 100644 --- a/src/stream_srv.c +++ b/src/stream_srv.c @@ -150,6 +150,9 @@ LOGSLNK(link, LOGL_ERROR, "failed applying TCP keep-alive pars on fd %d\n", sock_fd); goto error_close_socket; } + /* tcp_pars.user_timeout (sockopt TCP_USER_TIMEOUT) is + * inherited by accept() connected sockets automatically, + * no need to re-apply it here. */ break; case IPPROTO_SCTP: _setsockopt_nosigpipe(link, sock_fd); @@ -710,6 +713,15 @@ link->tcp_pars.ka.probes_value = *(int *)val; /* Will be applied on accepted sockets */ break; + case OSMO_STREAM_SRV_LINK_PAR_TCP_SOCKOPT_USER_TIMEOUT: + if (!val || val_len != sizeof(unsigned int)) + return -EINVAL; + link->tcp_pars.user_timeout_present = true; + link->tcp_pars.user_timeout_value = *(int *)val; + /* This value is inherited by accept() connected sockets (hence by child stream_srv): */ + if (osmo_stream_srv_link_is_opened(link)) + return stream_setsockopt_tcp_user_timeout(osmo_stream_srv_link_get_fd(link), + link->tcp_pars.user_timeout_value); default: return -ENOENT; }; @@ -1451,6 +1463,7 @@ { uint8_t on; int i; + unsigned int u; OSMO_ASSERT(conn);
switch (par) { @@ -1475,6 +1488,12 @@ return -EINVAL; i = *(int *)val; return stream_setsockopt_tcp_keepcnt(osmo_stream_srv_get_fd(conn), i); + case OSMO_STREAM_SRV_PAR_TCP_SOCKOPT_USER_TIMEOUT: + if (!val || val_len != sizeof(unsigned int)) + return -EINVAL; + u = *(unsigned int *)val; + return stream_setsockopt_tcp_user_timeout(osmo_stream_srv_get_fd(conn), u); + break; default: return -ENOENT; };