pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-netif/+/34080 )
Change subject: WIP: stream_cli: Forward SCTP MSG_NOTIFICATION to upper layers ......................................................................
WIP: stream_cli: Forward SCTP MSG_NOTIFICATION to upper layers
Same mechanism as already used in strea_srv.
Change-Id: I4cb94d264109f1b763cccd44c6ba049cc7509319 --- M src/stream_cli.c 1 file changed, 114 insertions(+), 2 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-netif refs/changes/80/34080/1
diff --git a/src/stream_cli.c b/src/stream_cli.c index e90b5e4..cc63297 100644 --- a/src/stream_cli.c +++ b/src/stream_cli.c @@ -913,18 +913,119 @@ } }
+#ifdef HAVE_LIBSCTP +static int _sctp_recvmsg_wrapper(int fd, struct msgb *msg) +{ + struct sctp_sndrcvinfo sinfo; + int flags = 0; + int ret; + uint8_t *data = msg->tail; + + ret = sctp_recvmsg(fd, data, msgb_tailroom(msg), + NULL, NULL, &sinfo, &flags); + msgb_sctp_msg_flags(msg) = 0; + msgb_sctp_ppid(msg) = ntohl(sinfo.sinfo_ppid); + msgb_sctp_stream(msg) = sinfo.sinfo_stream; + if (flags & MSG_NOTIFICATION) { + union sctp_notification *notif = (union sctp_notification *)data; + LOGP(DLINP, LOGL_INFO, "NOTIFICATION %u flags=0x%x\n", notif->sn_header.sn_type, notif->sn_header.sn_flags); + msgb_put(msg, sizeof(union sctp_notification)); + msgb_sctp_msg_flags(msg) = OSMO_STREAM_SCTP_MSG_FLAGS_NOTIFICATION; + switch (notif->sn_header.sn_type) { + case SCTP_ASSOC_CHANGE: + LOGP(DLINP, LOGL_INFO, "===> ASSOC CHANGE:"); + switch (notif->sn_assoc_change.sac_state) { + case SCTP_COMM_UP: + LOGPC(DLINP, LOGL_INFO, " UP\n"); + break; + case SCTP_COMM_LOST: + LOGPC(DLINP, LOGL_INFO, " LOST\n"); + /* Handle this like a regular disconnect */ + return 0; + case SCTP_RESTART: + LOGPC(DLINP, LOGL_INFO, " RESTART\n"); + break; + case SCTP_SHUTDOWN_COMP: + LOGPC(DLINP, LOGL_INFO, " SHUTDOWN COMP\n"); + break; + case SCTP_CANT_STR_ASSOC: + LOGPC(DLINP, LOGL_INFO, " CANT STR ASSOC\n"); + break; + } + break; + case SCTP_SEND_FAILED: + LOGP(DLINP, LOGL_INFO, "===> SEND FAILED\n"); + break; + case SCTP_PEER_ADDR_CHANGE: + { + char addr_str[INET6_ADDRSTRLEN + 10]; + struct sockaddr_storage sa = notif->sn_paddr_change.spc_aaddr; + osmo_sockaddr_to_str_buf(addr_str, sizeof(addr_str), + (const struct osmo_sockaddr *)&sa); + LOGP(DLINP, LOGL_INFO, "===> PEER ADDR CHANGE: %s %s err=%s\n", + addr_str, osmo_sctp_paddr_chg_str(notif->sn_paddr_change.spc_state), + (notif->sn_paddr_change.spc_state == SCTP_ADDR_UNREACHABLE) ? + osmo_sctp_sn_error_str(notif->sn_paddr_change.spc_error) : "None"); + } + break; + case SCTP_SHUTDOWN_EVENT: + LOGP(DLINP, LOGL_INFO, "===> SHUTDOWN EVT\n"); + /* Handle this like a regular disconnect */ + return 0; + } + return -EAGAIN; + } + return ret; +} +#endif + /*! \brief Receive data via an Osmocom stream client * \param[in] cli Stream Client through which we want to send * \param msg pre-allocate message buffer to which received data is appended - * \returns number of bytes read; <=0 in case of error */ + * \returns number of bytes read; <=0 in case of erro + * + * If conn is an SCTP connection, additional specific considerations shall be taken: + * - msg->cb is always filled with SCTP ppid, and SCTP stream values, see msgb_sctp_*() APIs. + * - If an SCTP notification was received when reading from the SCTP socket, + * msgb_sctp_msg_flags(msg) will contain bit flag + * OSMO_STREAM_SCTP_MSG_FLAGS_NOTIFICATION set, and the msgb will + * contain a "union sctp_notification" instead of user data. In this case the + * return code will be either 0 (if conn is considered dead after the + * notification) or -EAGAIN (if conn is considered still alive after the + * notification) resembling the standard recv() API. + */ int osmo_stream_cli_recv(struct osmo_stream_cli *cli, struct msgb *msg) { int ret; OSMO_ASSERT(cli); OSMO_ASSERT(msg);
- ret = recv(cli->ofd.fd, msg->tail, msgb_tailroom(msg), 0); + switch (cli->sk_domain) { + case AF_UNIX: + ret = recv(cli->ofd.fd, msg->tail, msgb_tailroom(msg), 0); + break; + case AF_INET: + case AF_INET6: + case AF_UNSPEC: + switch (cli->proto) { +#ifdef HAVE_LIBSCTP + case IPPROTO_SCTP: + ret = _sctp_recvmsg_wrapper(cli->ofd.fd, msg); + break; +#endif + case IPPROTO_TCP: + default: + ret = recv(cli->ofd.fd, msg->tail, msgb_tailroom(msg), 0); + break; + } + break; + default: + ret = -ENOTSUP; + } + if (ret < 0) { + if (ret == -EAGAIN) + return ret; if (errno == EPIPE || errno == ECONNRESET) LOGSCLI(cli, LOGL_ERROR, "lost connection with srv\n"); osmo_stream_cli_reconnect(cli);