2011-10-03 20:09:45 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <arpa/inet.h>
|
2015-02-25 10:17:51 +00:00
|
|
|
#include <netinet/in.h>
|
2011-10-03 20:09:45 +00:00
|
|
|
|
2011-10-05 10:31:43 +00:00
|
|
|
#include <osmocom/core/timer.h>
|
2011-10-03 20:09:45 +00:00
|
|
|
#include <osmocom/core/select.h>
|
|
|
|
#include <osmocom/gsm/tlv.h>
|
|
|
|
#include <osmocom/core/msgb.h>
|
|
|
|
#include <osmocom/core/logging.h>
|
|
|
|
#include <osmocom/core/talloc.h>
|
|
|
|
#include <osmocom/core/socket.h>
|
|
|
|
|
|
|
|
#include <osmocom/netif/stream.h>
|
|
|
|
|
2015-12-21 19:54:19 +00:00
|
|
|
#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
|
|
|
|
}
|
|
|
|
|
2011-10-03 20:09:45 +00:00
|
|
|
/*
|
|
|
|
* Client side.
|
|
|
|
*/
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
enum osmo_stream_cli_state {
|
|
|
|
STREAM_CLI_STATE_NONE = 0,
|
|
|
|
STREAM_CLI_STATE_CONNECTING = 1,
|
|
|
|
STREAM_CLI_STATE_CONNECTED = 2,
|
|
|
|
STREAM_CLI_STATE_MAX
|
2011-10-03 20:09:45 +00:00
|
|
|
};
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
#define OSMO_STREAM_CLI_F_RECONF (1 << 0)
|
2011-10-09 18:18:49 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_cli {
|
2011-10-03 20:09:45 +00:00
|
|
|
struct osmo_fd ofd;
|
|
|
|
struct llist_head tx_queue;
|
|
|
|
struct osmo_timer_list timer;
|
2012-08-15 19:14:38 +00:00
|
|
|
enum osmo_stream_cli_state state;
|
2011-10-03 20:09:45 +00:00
|
|
|
const char *addr;
|
|
|
|
uint16_t port;
|
2015-12-21 19:54:19 +00:00
|
|
|
uint16_t proto;
|
2012-08-15 19:14:38 +00:00
|
|
|
int (*connect_cb)(struct osmo_stream_cli *srv);
|
|
|
|
int (*read_cb)(struct osmo_stream_cli *srv);
|
|
|
|
int (*write_cb)(struct osmo_stream_cli *srv);
|
2011-10-03 20:09:45 +00:00
|
|
|
void *data;
|
2011-10-09 18:18:49 +00:00
|
|
|
int flags;
|
2011-11-08 09:10:10 +00:00
|
|
|
int reconnect_timeout;
|
2011-10-03 20:09:45 +00:00
|
|
|
};
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_cli_close(struct osmo_stream_cli *cli);
|
2011-10-03 20:09:45 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
static void osmo_stream_cli_reconnect(struct osmo_stream_cli *cli)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
if (cli->reconnect_timeout < 0) {
|
2011-11-08 09:10:10 +00:00
|
|
|
LOGP(DLINP, LOGL_DEBUG, "not reconnecting, disabled.\n");
|
|
|
|
return;
|
|
|
|
}
|
2011-10-03 20:09:45 +00:00
|
|
|
LOGP(DLINP, LOGL_DEBUG, "connection closed\n");
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_close(cli);
|
2011-11-08 09:10:10 +00:00
|
|
|
LOGP(DLINP, LOGL_DEBUG, "retrying in %d seconds...\n",
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->reconnect_timeout);
|
|
|
|
osmo_timer_schedule(&cli->timer, cli->reconnect_timeout, 0);
|
|
|
|
cli->state = STREAM_CLI_STATE_CONNECTING;
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_cli_close(struct osmo_stream_cli *cli)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_fd_unregister(&cli->ofd);
|
|
|
|
close(cli->ofd.fd);
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
static void osmo_stream_cli_read(struct osmo_stream_cli *cli)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "message received\n");
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
if (cli->read_cb)
|
|
|
|
cli->read_cb(cli);
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
static int osmo_stream_cli_write(struct osmo_stream_cli *cli)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2015-12-21 19:54:19 +00:00
|
|
|
#ifdef HAVE_LIBSCTP
|
|
|
|
struct sctp_sndrcvinfo sinfo;
|
|
|
|
#endif
|
2011-10-03 20:09:45 +00:00
|
|
|
struct msgb *msg;
|
|
|
|
struct llist_head *lh;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "sending data\n");
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
if (llist_empty(&cli->tx_queue)) {
|
|
|
|
cli->ofd.when &= ~BSC_FD_WRITE;
|
2011-10-03 20:09:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-08-15 19:14:38 +00:00
|
|
|
lh = cli->tx_queue.next;
|
2011-10-03 20:09:45 +00:00
|
|
|
llist_del(lh);
|
|
|
|
msg = llist_entry(lh, struct msgb, list);
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
if (cli->state == STREAM_CLI_STATE_CONNECTING) {
|
2011-10-03 20:09:45 +00:00
|
|
|
LOGP(DLINP, LOGL_ERROR, "not connected, dropping data!\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-12-21 19:54:19 +00:00
|
|
|
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;
|
|
|
|
}
|
2011-10-03 20:09:45 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
if (errno == EPIPE || errno == ENOTCONN) {
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_reconnect(cli);
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
LOGP(DLINP, LOGL_ERROR, "error to send\n");
|
|
|
|
}
|
|
|
|
msgb_free(msg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
static int osmo_stream_cli_fd_cb(struct osmo_fd *ofd, unsigned int what)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_cli *cli = ofd->data;
|
2011-10-03 20:09:45 +00:00
|
|
|
int error, ret;
|
|
|
|
socklen_t len = sizeof(error);
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
switch(cli->state) {
|
|
|
|
case STREAM_CLI_STATE_CONNECTING:
|
2011-10-03 20:09:45 +00:00
|
|
|
ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
|
|
|
|
if (ret >= 0 && error > 0) {
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_reconnect(cli);
|
2011-10-03 20:09:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ofd->when &= ~BSC_FD_WRITE;
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "connection done.\n");
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->state = STREAM_CLI_STATE_CONNECTED;
|
2015-12-21 19:54:19 +00:00
|
|
|
if (cli->proto == IPPROTO_SCTP)
|
|
|
|
sctp_sock_activate_events(ofd->fd);
|
2012-08-15 19:14:38 +00:00
|
|
|
if (cli->connect_cb)
|
|
|
|
cli->connect_cb(cli);
|
2011-10-03 20:09:45 +00:00
|
|
|
break;
|
2012-08-15 19:14:38 +00:00
|
|
|
case STREAM_CLI_STATE_CONNECTED:
|
2011-10-03 20:09:45 +00:00
|
|
|
if (what & BSC_FD_READ) {
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "connected read\n");
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_read(cli);
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
if (what & BSC_FD_WRITE) {
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "connected write\n");
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_write(cli);
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
static void cli_timer_cb(void *data);
|
2011-10-03 20:09:45 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_cli *osmo_stream_cli_create(void *ctx)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_cli *cli;
|
2011-10-03 20:09:45 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
cli = talloc_zero(ctx, struct osmo_stream_cli);
|
|
|
|
if (!cli)
|
2011-10-03 20:09:45 +00:00
|
|
|
return NULL;
|
|
|
|
|
2015-12-21 19:54:19 +00:00
|
|
|
cli->proto = IPPROTO_TCP;
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->ofd.fd = -1;
|
|
|
|
cli->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
|
|
|
|
cli->ofd.priv_nr = 0; /* XXX */
|
|
|
|
cli->ofd.cb = osmo_stream_cli_fd_cb;
|
|
|
|
cli->ofd.data = cli;
|
|
|
|
cli->state = STREAM_CLI_STATE_CONNECTING;
|
|
|
|
cli->timer.cb = cli_timer_cb;
|
|
|
|
cli->timer.data = link;
|
|
|
|
cli->reconnect_timeout = 5; /* default is 5 seconds. */
|
|
|
|
INIT_LLIST_HEAD(&cli->tx_queue);
|
2011-10-03 20:09:45 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
return cli;
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_set_addr(struct osmo_stream_cli *cli, const char *addr)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->addr = talloc_strdup(cli, addr);
|
|
|
|
cli->flags |= OSMO_STREAM_CLI_F_RECONF;
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_set_port(struct osmo_stream_cli *cli, uint16_t port)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->port = port;
|
|
|
|
cli->flags |= OSMO_STREAM_CLI_F_RECONF;
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
2015-12-21 19:54:19 +00:00
|
|
|
void
|
|
|
|
osmo_stream_cli_set_proto(struct osmo_stream_cli *cli, uint16_t proto)
|
|
|
|
{
|
|
|
|
cli->proto = proto;
|
|
|
|
cli->flags |= OSMO_STREAM_CLI_F_RECONF;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void
|
|
|
|
osmo_stream_cli_set_reconnect_timeout(struct osmo_stream_cli *cli, int timeout)
|
2011-11-08 09:10:10 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->reconnect_timeout = timeout;
|
2011-11-08 09:10:10 +00:00
|
|
|
}
|
|
|
|
|
2011-10-03 20:09:45 +00:00
|
|
|
void
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_set_data(struct osmo_stream_cli *cli, void *data)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->data = data;
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void *osmo_stream_cli_get_data(struct osmo_stream_cli *cli)
|
2011-10-09 19:19:13 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
return cli->data;
|
2011-10-09 19:19:13 +00:00
|
|
|
}
|
|
|
|
|
2011-10-17 17:49:33 +00:00
|
|
|
struct osmo_fd *
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_get_ofd(struct osmo_stream_cli *cli)
|
2011-10-17 17:49:33 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
return &cli->ofd;
|
2011-10-17 17:49:33 +00:00
|
|
|
}
|
|
|
|
|
2011-10-03 20:09:45 +00:00
|
|
|
void
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_set_connect_cb(struct osmo_stream_cli *cli,
|
|
|
|
int (*connect_cb)(struct osmo_stream_cli *cli))
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->connect_cb = connect_cb;
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_set_read_cb(struct osmo_stream_cli *cli,
|
|
|
|
int (*read_cb)(struct osmo_stream_cli *cli))
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->read_cb = read_cb;
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_cli_destroy(struct osmo_stream_cli *cli)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
talloc_free(link);
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
int osmo_stream_cli_open(struct osmo_stream_cli *cli)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2011-10-09 18:18:49 +00:00
|
|
|
/* we are reconfiguring this socket, close existing first. */
|
2012-08-15 19:14:38 +00:00
|
|
|
if ((cli->flags & OSMO_STREAM_CLI_F_RECONF) && cli->ofd.fd >= 0)
|
|
|
|
osmo_stream_cli_close(cli);
|
2011-10-09 18:18:49 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->flags &= ~OSMO_STREAM_CLI_F_RECONF;
|
2011-10-09 18:18:49 +00:00
|
|
|
|
2015-12-21 19:54:19 +00:00
|
|
|
ret = osmo_sock_init(AF_INET, SOCK_STREAM, cli->proto,
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->addr, cli->port,
|
2015-12-21 19:54:19 +00:00
|
|
|
OSMO_SOCK_F_CONNECT);
|
2011-10-03 20:09:45 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
if (errno != EINPROGRESS)
|
|
|
|
return ret;
|
|
|
|
}
|
2012-08-15 19:14:38 +00:00
|
|
|
cli->ofd.fd = ret;
|
|
|
|
if (osmo_fd_register(&cli->ofd) < 0) {
|
2011-10-03 20:09:45 +00:00
|
|
|
close(ret);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
static void cli_timer_cb(void *data)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_cli *cli = data;
|
2011-10-03 20:09:45 +00:00
|
|
|
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "reconnecting.\n");
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
switch(cli->state) {
|
|
|
|
case STREAM_CLI_STATE_CONNECTING:
|
|
|
|
osmo_stream_cli_open(cli);
|
2011-10-03 20:09:45 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_cli_send(struct osmo_stream_cli *cli, struct msgb *msg)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
msgb_enqueue(&cli->tx_queue, msg);
|
|
|
|
cli->ofd.when |= BSC_FD_WRITE;
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
int osmo_stream_cli_recv(struct osmo_stream_cli *cli, struct msgb *msg)
|
2011-10-17 10:50:58 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
ret = recv(cli->ofd.fd, msg->data, msg->data_len, 0);
|
2011-10-17 10:50:58 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
if (errno == EPIPE || errno == ECONNRESET) {
|
|
|
|
LOGP(DLINP, LOGL_ERROR,
|
2012-08-15 19:14:38 +00:00
|
|
|
"lost connection with srv\n");
|
2011-10-17 10:50:58 +00:00
|
|
|
}
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_cli_reconnect(cli);
|
2011-10-17 10:50:58 +00:00
|
|
|
return ret;
|
|
|
|
} else if (ret == 0) {
|
2012-08-15 19:14:38 +00:00
|
|
|
LOGP(DLINP, LOGL_ERROR, "connection closed with srv\n");
|
|
|
|
osmo_stream_cli_reconnect(cli);
|
2011-10-17 10:50:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
msgb_put(msg, ret);
|
2012-08-15 19:14:38 +00:00
|
|
|
LOGP(DLINP, LOGL_DEBUG, "received %d bytes from srv\n", ret);
|
2011-10-17 10:50:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-10-03 20:09:45 +00:00
|
|
|
/*
|
|
|
|
* Server side.
|
|
|
|
*/
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
#define OSMO_STREAM_SRV_F_RECONF (1 << 0)
|
2011-10-09 18:18:49 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_srv_link {
|
2011-10-03 20:09:45 +00:00
|
|
|
struct osmo_fd ofd;
|
|
|
|
const char *addr;
|
|
|
|
uint16_t port;
|
2015-12-21 19:54:19 +00:00
|
|
|
uint16_t proto;
|
2012-08-15 19:14:38 +00:00
|
|
|
int (*accept_cb)(struct osmo_stream_srv_link *srv, int fd);
|
2011-10-03 20:09:45 +00:00
|
|
|
void *data;
|
2011-10-09 18:18:49 +00:00
|
|
|
int flags;
|
2011-10-03 20:09:45 +00:00
|
|
|
};
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
static int osmo_stream_srv_fd_cb(struct osmo_fd *ofd, unsigned int what)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct sockaddr_in sa;
|
|
|
|
socklen_t sa_len = sizeof(sa);
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_srv_link *link = ofd->data;
|
2011-10-03 20:09:45 +00:00
|
|
|
|
|
|
|
ret = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
|
|
|
|
if (ret < 0) {
|
|
|
|
LOGP(DLINP, LOGL_ERROR, "failed to accept from origin "
|
|
|
|
"peer, reason=`%s'\n", strerror(errno));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "accept()ed new link from %s to port %u\n",
|
|
|
|
inet_ntoa(sa.sin_addr), link->port);
|
|
|
|
|
2015-12-21 19:54:19 +00:00
|
|
|
if (link->proto == IPPROTO_SCTP)
|
|
|
|
sctp_sock_activate_events(ret);
|
|
|
|
|
2011-10-03 20:09:45 +00:00
|
|
|
if (link->accept_cb)
|
|
|
|
link->accept_cb(link, ret);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_srv_link *osmo_stream_srv_link_create(void *ctx)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_srv_link *link;
|
2011-10-03 20:09:45 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
link = talloc_zero(ctx, struct osmo_stream_srv_link);
|
2011-10-03 20:09:45 +00:00
|
|
|
if (!link)
|
|
|
|
return NULL;
|
|
|
|
|
2015-12-21 19:54:19 +00:00
|
|
|
link->proto = IPPROTO_TCP;
|
2011-10-09 18:18:49 +00:00
|
|
|
link->ofd.fd = -1;
|
2011-10-03 20:09:45 +00:00
|
|
|
link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
|
2012-08-15 19:14:38 +00:00
|
|
|
link->ofd.cb = osmo_stream_srv_fd_cb;
|
2011-10-03 20:09:45 +00:00
|
|
|
link->ofd.data = link;
|
|
|
|
|
|
|
|
return link;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_srv_link_set_addr(struct osmo_stream_srv_link *link,
|
2011-10-09 16:00:53 +00:00
|
|
|
const char *addr)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
link->addr = talloc_strdup(link, addr);
|
2012-08-15 19:14:38 +00:00
|
|
|
link->flags |= OSMO_STREAM_SRV_F_RECONF;
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_srv_link_set_port(struct osmo_stream_srv_link *link,
|
2011-10-09 16:00:53 +00:00
|
|
|
uint16_t port)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
link->port = port;
|
2012-08-15 19:14:38 +00:00
|
|
|
link->flags |= OSMO_STREAM_SRV_F_RECONF;
|
2011-10-03 20:09:45 +00:00
|
|
|
}
|
|
|
|
|
2015-12-21 19:54:19 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-10-09 19:19:13 +00:00
|
|
|
void
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_srv_link_set_data(struct osmo_stream_srv_link *link,
|
2011-10-09 19:19:13 +00:00
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
link->data = data;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void *osmo_stream_srv_link_get_data(struct osmo_stream_srv_link *link)
|
2011-10-09 19:19:13 +00:00
|
|
|
{
|
|
|
|
return link->data;
|
|
|
|
}
|
|
|
|
|
2011-10-17 17:49:33 +00:00
|
|
|
struct osmo_fd *
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_srv_link_get_ofd(struct osmo_stream_srv_link *link)
|
2011-10-17 17:49:33 +00:00
|
|
|
{
|
|
|
|
return &link->ofd;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_srv_link_set_accept_cb(struct osmo_stream_srv_link *link,
|
|
|
|
int (*accept_cb)(struct osmo_stream_srv_link *link, int fd))
|
2011-10-03 20:09:45 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
link->accept_cb = accept_cb;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_srv_link_destroy(struct osmo_stream_srv_link *link)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
talloc_free(link);
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
int osmo_stream_srv_link_open(struct osmo_stream_srv_link *link)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2011-10-09 18:18:49 +00:00
|
|
|
/* we are reconfiguring this socket, close existing first. */
|
2012-08-15 19:14:38 +00:00
|
|
|
if ((link->flags & OSMO_STREAM_SRV_F_RECONF) && link->ofd.fd >= 0)
|
|
|
|
osmo_stream_srv_link_close(link);
|
2011-10-09 18:18:49 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
link->flags &= ~OSMO_STREAM_SRV_F_RECONF;
|
2011-10-09 18:18:49 +00:00
|
|
|
|
2015-12-21 19:54:19 +00:00
|
|
|
ret = osmo_sock_init(AF_INET, SOCK_STREAM, link->proto,
|
2011-10-03 20:09:45 +00:00
|
|
|
link->addr, link->port, OSMO_SOCK_F_BIND);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
link->ofd.fd = ret;
|
|
|
|
if (osmo_fd_register(&link->ofd) < 0) {
|
|
|
|
close(ret);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_srv_link_close(struct osmo_stream_srv_link *link)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
osmo_fd_unregister(&link->ofd);
|
|
|
|
close(link->ofd.fd);
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_srv {
|
|
|
|
struct osmo_stream_srv_link *srv;
|
2011-10-03 20:09:45 +00:00
|
|
|
struct osmo_fd ofd;
|
|
|
|
struct llist_head tx_queue;
|
2012-08-15 19:14:38 +00:00
|
|
|
int (*closed_cb)(struct osmo_stream_srv *peer);
|
|
|
|
int (*cb)(struct osmo_stream_srv *peer);
|
2011-10-03 20:09:45 +00:00
|
|
|
void *data;
|
|
|
|
};
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
static void osmo_stream_srv_read(struct osmo_stream_srv *conn)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "message received\n");
|
|
|
|
|
|
|
|
if (conn->cb)
|
2011-10-17 10:50:58 +00:00
|
|
|
conn->cb(conn);
|
2011-10-03 20:09:45 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
static void osmo_stream_srv_write(struct osmo_stream_srv *conn)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2015-12-21 19:54:19 +00:00
|
|
|
#ifdef HAVE_LIBSCTP
|
|
|
|
struct sctp_sndrcvinfo sinfo;
|
|
|
|
#endif
|
2011-10-03 20:09:45 +00:00
|
|
|
struct msgb *msg;
|
|
|
|
struct llist_head *lh;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "sending data\n");
|
|
|
|
|
|
|
|
if (llist_empty(&conn->tx_queue)) {
|
|
|
|
conn->ofd.when &= ~BSC_FD_WRITE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
lh = conn->tx_queue.next;
|
|
|
|
llist_del(lh);
|
|
|
|
msg = llist_entry(lh, struct msgb, list);
|
|
|
|
|
2015-12-21 19:54:19 +00:00
|
|
|
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;
|
|
|
|
}
|
2011-10-03 20:09:45 +00:00
|
|
|
if (ret < 0) {
|
|
|
|
LOGP(DLINP, LOGL_ERROR, "error to send\n");
|
|
|
|
}
|
|
|
|
msgb_free(msg);
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
static int osmo_stream_srv_cb(struct osmo_fd *ofd, unsigned int what)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_srv *conn = ofd->data;
|
2011-10-03 20:09:45 +00:00
|
|
|
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "connected read/write\n");
|
|
|
|
if (what & BSC_FD_READ)
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_srv_read(conn);
|
2011-10-03 20:09:45 +00:00
|
|
|
if (what & BSC_FD_WRITE)
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_srv_write(conn);
|
2011-10-03 20:09:45 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_srv *
|
|
|
|
osmo_stream_srv_create(void *ctx, struct osmo_stream_srv_link *link,
|
2011-10-09 16:00:53 +00:00
|
|
|
int fd,
|
2012-08-15 19:14:38 +00:00
|
|
|
int (*cb)(struct osmo_stream_srv *conn),
|
|
|
|
int (*closed_cb)(struct osmo_stream_srv *conn), void *data)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
2012-08-15 19:14:38 +00:00
|
|
|
struct osmo_stream_srv *conn;
|
2011-10-03 20:09:45 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
conn = talloc_zero(ctx, struct osmo_stream_srv);
|
2011-10-03 20:09:45 +00:00
|
|
|
if (conn == NULL) {
|
2012-08-15 19:14:38 +00:00
|
|
|
LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in srv, "
|
2011-10-03 20:09:45 +00:00
|
|
|
"reason=`%s'\n", strerror(errno));
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-08-15 19:14:38 +00:00
|
|
|
conn->srv = link;
|
2011-10-03 20:09:45 +00:00
|
|
|
conn->ofd.fd = fd;
|
|
|
|
conn->ofd.data = conn;
|
2012-08-15 19:14:38 +00:00
|
|
|
conn->ofd.cb = osmo_stream_srv_cb;
|
2011-10-03 20:09:45 +00:00
|
|
|
conn->ofd.when = BSC_FD_READ;
|
|
|
|
conn->cb = cb;
|
|
|
|
conn->closed_cb = closed_cb;
|
|
|
|
conn->data = data;
|
|
|
|
INIT_LLIST_HEAD(&conn->tx_queue);
|
|
|
|
|
|
|
|
if (osmo_fd_register(&conn->ofd) < 0) {
|
|
|
|
LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
|
|
|
|
talloc_free(conn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return conn;
|
|
|
|
}
|
|
|
|
|
2011-11-06 19:47:08 +00:00
|
|
|
void
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_srv_set_data(struct osmo_stream_srv *conn,
|
2011-11-06 19:47:08 +00:00
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
conn->data = data;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void *osmo_stream_srv_get_data(struct osmo_stream_srv *link)
|
2011-10-09 19:19:13 +00:00
|
|
|
{
|
|
|
|
return link->data;
|
|
|
|
}
|
|
|
|
|
2011-10-17 17:49:33 +00:00
|
|
|
struct osmo_fd *
|
2012-08-15 19:14:38 +00:00
|
|
|
osmo_stream_srv_get_ofd(struct osmo_stream_srv *link)
|
2011-10-17 17:49:33 +00:00
|
|
|
{
|
|
|
|
return &link->ofd;
|
|
|
|
}
|
|
|
|
|
2012-08-19 16:35:10 +00:00
|
|
|
struct osmo_stream_srv_link *osmo_stream_srv_get_master(struct osmo_stream_srv *conn)
|
|
|
|
{
|
|
|
|
return conn->srv;
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_srv_destroy(struct osmo_stream_srv *conn)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
close(conn->ofd.fd);
|
|
|
|
osmo_fd_unregister(&conn->ofd);
|
|
|
|
if (conn->closed_cb)
|
|
|
|
conn->closed_cb(conn);
|
|
|
|
talloc_free(conn);
|
|
|
|
}
|
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
void osmo_stream_srv_send(struct osmo_stream_srv *conn, struct msgb *msg)
|
2011-10-03 20:09:45 +00:00
|
|
|
{
|
|
|
|
msgb_enqueue(&conn->tx_queue, msg);
|
|
|
|
conn->ofd.when |= BSC_FD_WRITE;
|
|
|
|
}
|
2011-10-17 10:50:58 +00:00
|
|
|
|
2012-08-15 19:14:38 +00:00
|
|
|
int osmo_stream_srv_recv(struct osmo_stream_srv *conn, struct msgb *msg)
|
2011-10-17 10:50:58 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = recv(conn->ofd.fd, msg->data, msg->data_len, 0);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (errno == EPIPE || errno == ECONNRESET) {
|
|
|
|
LOGP(DLINP, LOGL_ERROR,
|
2012-08-15 19:14:38 +00:00
|
|
|
"lost connection with srv\n");
|
2011-10-17 10:50:58 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
} else if (ret == 0) {
|
2012-08-15 19:14:38 +00:00
|
|
|
LOGP(DLINP, LOGL_ERROR, "connection closed with srv\n");
|
2011-10-17 10:50:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
msgb_put(msg, ret);
|
|
|
|
LOGP(DLINP, LOGL_DEBUG, "received %d bytes from client\n", ret);
|
|
|
|
return ret;
|
|
|
|
}
|