aboutsummaryrefslogtreecommitdiffstats
path: root/src/stream.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2015-12-21 20:54:19 +0100
committerHarald Welte <laforge@gnumonks.org>2015-12-21 20:54:19 +0100
commitfb3e20b4b2a38cd09bf4ed7687dacd3ab6f15d44 (patch)
tree5329298f7338e29c0044129af611621fccec8180 /src/stream.c
parentd4be141ab0922427232db660e09befd064a6bace (diff)
SCTP support for osmo_stream_{cli,srv} code
Wih this change, osmo_stream_ client and server API can be used not only for TCP but also for SCTP. The latter is needed in SIGTRAN ad Iuh applications, for example.
Diffstat (limited to 'src/stream.c')
-rw-r--r--src/stream.c89
1 files changed, 84 insertions, 5 deletions
diff --git a/src/stream.c b/src/stream.c
index 8c7fde7..21c99c7 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -20,6 +20,29 @@
#include <osmocom/netif/stream.h>
+#include "config.h"
+
+#ifdef HAVE_LIBSCTP
+#include <netinet/sctp.h>
+#endif
+
+static int sctp_sock_activate_events(int fd)
+{
+#ifdef HAVE_LIBSCTP
+ struct sctp_event_subscribe event;
+ int rc;
+
+ /* subscribe for all events */
+ memset((uint8_t *)&event, 1, sizeof(event));
+ rc = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
+ &event, sizeof(event));
+
+ return rc;
+#else
+ return -1;
+#endif
+}
+
/*
* Client side.
*/
@@ -40,6 +63,7 @@ struct osmo_stream_cli {
enum osmo_stream_cli_state state;
const char *addr;
uint16_t port;
+ uint16_t proto;
int (*connect_cb)(struct osmo_stream_cli *srv);
int (*read_cb)(struct osmo_stream_cli *srv);
int (*write_cb)(struct osmo_stream_cli *srv);
@@ -80,6 +104,9 @@ static void osmo_stream_cli_read(struct osmo_stream_cli *cli)
static int osmo_stream_cli_write(struct osmo_stream_cli *cli)
{
+#ifdef HAVE_LIBSCTP
+ struct sctp_sndrcvinfo sinfo;
+#endif
struct msgb *msg;
struct llist_head *lh;
int ret;
@@ -99,7 +126,20 @@ static int osmo_stream_cli_write(struct osmo_stream_cli *cli)
return 0;
}
- ret = send(cli->ofd.fd, msg->data, msg->len, 0);
+ switch (cli->proto) {
+#ifdef HAVE_LIBSCTP
+ case IPPROTO_SCTP:
+ sinfo.sinfo_ppid = htonl(msgb_sctp_ppid(msg));
+ sinfo.sinfo_stream = htonl(msgb_sctp_stream(msg));
+ ret = sctp_send(cli->ofd.fd, msg->data, msgb_length(msg),
+ &sinfo, MSG_NOSIGNAL);
+ break;
+#endif
+ case IPPROTO_TCP:
+ default:
+ ret = send(cli->ofd.fd, msg->data, msg->len, 0);
+ break;
+ }
if (ret < 0) {
if (errno == EPIPE || errno == ENOTCONN) {
osmo_stream_cli_reconnect(cli);
@@ -126,6 +166,8 @@ static int osmo_stream_cli_fd_cb(struct osmo_fd *ofd, unsigned int what)
ofd->when &= ~BSC_FD_WRITE;
LOGP(DLINP, LOGL_DEBUG, "connection done.\n");
cli->state = STREAM_CLI_STATE_CONNECTED;
+ if (cli->proto == IPPROTO_SCTP)
+ sctp_sock_activate_events(ofd->fd);
if (cli->connect_cb)
cli->connect_cb(cli);
break;
@@ -155,6 +197,7 @@ struct osmo_stream_cli *osmo_stream_cli_create(void *ctx)
if (!cli)
return NULL;
+ cli->proto = IPPROTO_TCP;
cli->ofd.fd = -1;
cli->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
cli->ofd.priv_nr = 0; /* XXX */
@@ -184,6 +227,13 @@ osmo_stream_cli_set_port(struct osmo_stream_cli *cli, uint16_t port)
}
void
+osmo_stream_cli_set_proto(struct osmo_stream_cli *cli, uint16_t proto)
+{
+ cli->proto = proto;
+ cli->flags |= OSMO_STREAM_CLI_F_RECONF;
+}
+
+void
osmo_stream_cli_set_reconnect_timeout(struct osmo_stream_cli *cli, int timeout)
{
cli->reconnect_timeout = timeout;
@@ -235,9 +285,9 @@ int osmo_stream_cli_open(struct osmo_stream_cli *cli)
cli->flags &= ~OSMO_STREAM_CLI_F_RECONF;
- ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
+ ret = osmo_sock_init(AF_INET, SOCK_STREAM, cli->proto,
cli->addr, cli->port,
- OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
+ OSMO_SOCK_F_CONNECT);
if (ret < 0) {
if (errno != EINPROGRESS)
return ret;
@@ -303,6 +353,7 @@ struct osmo_stream_srv_link {
struct osmo_fd ofd;
const char *addr;
uint16_t port;
+ uint16_t proto;
int (*accept_cb)(struct osmo_stream_srv_link *srv, int fd);
void *data;
int flags;
@@ -324,6 +375,9 @@ static int osmo_stream_srv_fd_cb(struct osmo_fd *ofd, unsigned int what)
LOGP(DLINP, LOGL_DEBUG, "accept()ed new link from %s to port %u\n",
inet_ntoa(sa.sin_addr), link->port);
+ if (link->proto == IPPROTO_SCTP)
+ sctp_sock_activate_events(ret);
+
if (link->accept_cb)
link->accept_cb(link, ret);
@@ -338,6 +392,7 @@ struct osmo_stream_srv_link *osmo_stream_srv_link_create(void *ctx)
if (!link)
return NULL;
+ link->proto = IPPROTO_TCP;
link->ofd.fd = -1;
link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
link->ofd.cb = osmo_stream_srv_fd_cb;
@@ -361,6 +416,14 @@ void osmo_stream_srv_link_set_port(struct osmo_stream_srv_link *link,
}
void
+osmo_stream_srv_link_set_proto(struct osmo_stream_srv_link *link,
+ uint16_t proto)
+{
+ link->proto = proto;
+ link->flags |= OSMO_STREAM_SRV_F_RECONF;
+}
+
+void
osmo_stream_srv_link_set_data(struct osmo_stream_srv_link *link,
void *data)
{
@@ -400,7 +463,7 @@ int osmo_stream_srv_link_open(struct osmo_stream_srv_link *link)
link->flags &= ~OSMO_STREAM_SRV_F_RECONF;
- ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
+ ret = osmo_sock_init(AF_INET, SOCK_STREAM, link->proto,
link->addr, link->port, OSMO_SOCK_F_BIND);
if (ret < 0)
return ret;
@@ -440,6 +503,9 @@ static void osmo_stream_srv_read(struct osmo_stream_srv *conn)
static void osmo_stream_srv_write(struct osmo_stream_srv *conn)
{
+#ifdef HAVE_LIBSCTP
+ struct sctp_sndrcvinfo sinfo;
+#endif
struct msgb *msg;
struct llist_head *lh;
int ret;
@@ -454,7 +520,20 @@ static void osmo_stream_srv_write(struct osmo_stream_srv *conn)
llist_del(lh);
msg = llist_entry(lh, struct msgb, list);
- ret = send(conn->ofd.fd, msg->data, msg->len, 0);
+ switch (conn->srv->proto) {
+#ifdef HAVE_LIBSCTP
+ case IPPROTO_SCTP:
+ sinfo.sinfo_ppid = htonl(msgb_sctp_ppid(msg));
+ sinfo.sinfo_stream = htonl(msgb_sctp_stream(msg));
+ ret = sctp_send(conn->ofd.fd, msg->data, msgb_length(msg),
+ &sinfo, MSG_NOSIGNAL);
+ break;
+#endif
+ case IPPROTO_TCP:
+ default:
+ ret = send(conn->ofd.fd, msg->data, msg->len, 0);
+ break;
+ }
if (ret < 0) {
LOGP(DLINP, LOGL_ERROR, "error to send\n");
}