aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2023-01-25 12:59:51 +0100
committerHarald Welte <laforge@osmocom.org>2023-06-13 08:59:00 +0200
commit5bdd7822ee4dad866851e3b77ff2e5810729bdce (patch)
tree5fe5317d61efd1f4ab53ab1ada1f0833bf329f48
parent4f19586fce16617e8f62968eab5bfeddd09ed9b1 (diff)
stream: Allow user to request SCTP termination with ABORTlaforge/sctp_abort
By default, SCTP sockets are using a graceful shutdown using the SCTP SHUTDOWN chunk. The socket API allows us to explicitly request a SCTP ABORT. Introduce new osmo_stream_{cli,srv,srv_link}_set_sctp_abort() API calls by which the application can request that any termination of the related socket should request the kernel to do ABORT rather than shutdown. This obviously only works for explicit termination, and not for implicit termination via segfault and/or process exit(). Change-Id: I6a41ec4cdca2d789025839c84ff5650e0613c838 Related: SYS#6018
-rw-r--r--include/osmocom/netif/stream.h3
-rw-r--r--src/stream.c64
2 files changed, 67 insertions, 0 deletions
diff --git a/include/osmocom/netif/stream.h b/include/osmocom/netif/stream.h
index b9a7c6d..592dd2b 100644
--- a/include/osmocom/netif/stream.h
+++ b/include/osmocom/netif/stream.h
@@ -25,6 +25,7 @@ struct osmo_stream_srv_link *osmo_stream_srv_link_create(void *ctx);
void osmo_stream_srv_link_destroy(struct osmo_stream_srv_link *link);
void osmo_stream_srv_link_set_nodelay(struct osmo_stream_srv_link *link, bool nodelay);
+void osmo_stream_srv_link_set_sctp_abort(struct osmo_stream_srv_link *link, bool use_abort);
void osmo_stream_srv_link_set_addr(struct osmo_stream_srv_link *link, const char *addr);
int osmo_stream_srv_link_set_addrs(struct osmo_stream_srv_link *link, const char **addr, size_t addrcnt);
void osmo_stream_srv_link_set_port(struct osmo_stream_srv_link *link, uint16_t port);
@@ -51,6 +52,7 @@ struct osmo_fd *osmo_stream_srv_get_ofd(struct osmo_stream_srv *srv);
void osmo_stream_srv_destroy(struct osmo_stream_srv *conn);
void osmo_stream_srv_set_flush_and_destroy(struct osmo_stream_srv *conn);
+void osmo_stream_srv_set_sctp_abort(struct osmo_stream_srv *conn, bool use_abort);
void osmo_stream_srv_set_data(struct osmo_stream_srv *conn, void *data);
void osmo_stream_srv_send(struct osmo_stream_srv *conn, struct msgb *msg);
@@ -73,6 +75,7 @@ int osmo_stream_cli_set_local_addrs(struct osmo_stream_cli *cli, const char **ad
void osmo_stream_cli_set_local_port(struct osmo_stream_cli *cli, uint16_t port);
void osmo_stream_cli_set_data(struct osmo_stream_cli *cli, void *data);
void osmo_stream_cli_set_reconnect_timeout(struct osmo_stream_cli *cli, int timeout);
+void osmo_stream_cli_set_sctp_abort(struct osmo_stream_cli *cli, bool use_abort);
void *osmo_stream_cli_get_data(struct osmo_stream_cli *cli);
char *osmo_stream_cli_get_sockname(const struct osmo_stream_cli *cli);
struct osmo_fd *osmo_stream_cli_get_ofd(struct osmo_stream_cli *cli);
diff --git a/src/stream.c b/src/stream.c
index 2e38916..4a30eb5 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -217,6 +217,20 @@ static int setsockopt_nodelay(int fd, int proto, int on)
return rc;
}
+#ifdef HAVE_LIBSCTP
+static int sctp_send_abort(int fd, uint32_t ppid, uint16_t stream_no)
+{
+ /* sctp_sendmsg doesn't work for SOCK_STREAM, sadly */
+ //return sctp_sendmsg(fd, NULL, 0, NULL, 0, ppid, SCTP_ABORT, stream_no, 0, 0);
+
+ /* Section 8.1.4 of RFC6458 */
+ struct linger li = {
+ .l_onoff = 1,
+ .l_linger = 0,
+ };
+ return setsockopt(fd, SOL_SOCKET, SO_LINGER, &li, sizeof(li));
+}
+#endif
/*
* Client side.
@@ -240,6 +254,7 @@ static const struct value_string stream_cli_state_names[] = {
#define OSMO_STREAM_CLI_F_RECONF (1 << 0)
#define OSMO_STREAM_CLI_F_NODELAY (1 << 1)
+#define OSMO_STREAM_CLI_F_SCTP_ABORT (1 << 2)
#ifdef HAVE_LIBSCTP
#define OSMO_STREAM_MAX_ADDRS OSMO_SOCK_MAX_ADDRS
@@ -309,6 +324,11 @@ void osmo_stream_cli_close(struct osmo_stream_cli *cli)
if (cli->ofd.fd == -1)
return;
osmo_fd_unregister(&cli->ofd);
+#ifdef HAVE_LIBSCTP
+ if (cli->proto == IPPROTO_SCTP && cli->flags & OSMO_STREAM_CLI_F_SCTP_ABORT) {
+ sctp_send_abort(cli->ofd.fd, 0, 0);
+ }
+#endif
close(cli->ofd.fd);
cli->ofd.fd = -1;
@@ -736,6 +756,16 @@ void osmo_stream_cli_destroy(struct osmo_stream_cli *cli)
talloc_free(cli);
}
+#ifdef HAVE_LIBSCTP
+void osmo_stream_cli_set_sctp_abort(struct osmo_stream_cli *cli, bool use_abort)
+{
+ if (use_abort)
+ cli->flags |= OSMO_STREAM_CLI_F_SCTP_ABORT;
+ else
+ cli->flags &= ~OSMO_STREAM_CLI_F_SCTP_ABORT;
+}
+#endif
+
/*! \brief DEPRECATED: use osmo_stream_cli_set_reconnect_timeout() or osmo_stream_cli_reconnect() instead!
* Open connection of an Osmocom stream client
* \param[in] cli Stream Client to connect
@@ -939,6 +969,7 @@ void osmo_stream_cli_clear_tx_queue(struct osmo_stream_cli *cli)
#define OSMO_STREAM_SRV_F_RECONF (1 << 0)
#define OSMO_STREAM_SRV_F_NODELAY (1 << 1)
+#define OSMO_STREAM_SRV_F_SCTP_ABORT (1 << 2)
struct osmo_stream_srv_link {
struct osmo_fd ofd;
@@ -1058,6 +1089,16 @@ void osmo_stream_srv_link_set_nodelay(struct osmo_stream_srv_link *link, bool no
link->flags &= ~OSMO_STREAM_SRV_F_NODELAY;
}
+#ifdef HAVE_LIBSCTP
+void osmo_stream_srv_link_set_sctp_abort(struct osmo_stream_srv_link *link, bool use_abort)
+{
+ if (use_abort)
+ link->flags |= OSMO_STREAM_CLI_F_SCTP_ABORT;
+ else
+ link->flags &= ~OSMO_STREAM_CLI_F_SCTP_ABORT;
+}
+#endif
+
/*! \brief Set the local address to which we bind
* \param[in] link Stream Server Link to modify
* \param[in] addr Local IP address
@@ -1296,6 +1337,11 @@ void osmo_stream_srv_link_close(struct osmo_stream_srv_link *link)
return;
osmo_fd_unregister(&link->ofd);
+#ifdef HAVE_LIBSCTP
+ if (link->proto == IPPROTO_SCTP && link->flags & OSMO_STREAM_SRV_F_SCTP_ABORT) {
+ sctp_send_abort(link->ofd.fd, 0, 0);
+ }
+#endif
close(link->ofd.fd);
link->ofd.fd = -1;
}
@@ -1431,6 +1477,9 @@ osmo_stream_srv_create(void *ctx, struct osmo_stream_srv_link *link,
conn->read_cb = read_cb;
conn->closed_cb = closed_cb;
conn->data = data;
+ /* inherit the SCTP_ABORT flag */
+ if (link->flags & OSMO_STREAM_SRV_F_SCTP_ABORT)
+ conn->flags |= OSMO_STREAM_SRV_F_SCTP_ABORT;
INIT_LLIST_HEAD(&conn->tx_queue);
if (osmo_fd_register(&conn->ofd) < 0) {
@@ -1451,6 +1500,16 @@ void osmo_stream_srv_set_flush_and_destroy(struct osmo_stream_srv *conn)
conn->flags |= OSMO_STREAM_SRV_F_FLUSH_DESTROY;
}
+#ifdef HAVE_LIBSCTP
+void osmo_stream_srv_set_sctp_abort(struct osmo_stream_srv *conn, bool use_abort)
+{
+ if (use_abort)
+ conn->flags |= OSMO_STREAM_SRV_F_SCTP_ABORT;
+ else
+ conn->flags &= ~OSMO_STREAM_SRV_F_SCTP_ABORT;
+}
+#endif
+
/*! \brief Set application private data of the stream server
* \param[in] conn Stream Server to modify
* \param[in] data User-specific data (available in call-back functions) */
@@ -1495,6 +1554,11 @@ struct osmo_stream_srv_link *osmo_stream_srv_get_master(struct osmo_stream_srv *
void osmo_stream_srv_destroy(struct osmo_stream_srv *conn)
{
osmo_fd_unregister(&conn->ofd);
+#ifdef HAVE_LIBSCTP
+ if (conn->srv->proto == IPPROTO_SCTP && conn->srv->flags & OSMO_STREAM_SRV_F_SCTP_ABORT) {
+ sctp_send_abort(conn->ofd.fd, 0, 0);
+ }
+#endif
close(conn->ofd.fd);
conn->ofd.fd = -1;
if (conn->closed_cb)