From ddb9bf65f497ac0c4879b5114e887383f47e5686 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Wed, 5 Oct 2011 12:28:21 +0200 Subject: add generic datagram socket infrastructure and examples This patch adds new datagram socket infrastructure and it reworks the previous examples (now it's LAPD over datagram). --- src/Makefile.am | 3 +- src/datagram.c | 354 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 src/datagram.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 30e1e72..bf2d60a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,4 +8,5 @@ AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(COVERAG lib_LTLIBRARIES = libosmonetif.la -libosmonetif_la_SOURCES = stream.c +libosmonetif_la_SOURCES = datagram.c \ + stream.c diff --git a/src/datagram.c b/src/datagram.c new file mode 100644 index 0000000..cd09025 --- /dev/null +++ b/src/datagram.c @@ -0,0 +1,354 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Client side. + */ + +struct datagram_client_conn { + struct osmo_fd ofd; + struct llist_head tx_queue; + const char *addr; + uint16_t port; + int (*write_cb)(struct datagram_client_conn *conn); + void *data; +}; + +void datagram_client_conn_close(struct datagram_client_conn *conn) +{ + osmo_fd_unregister(&conn->ofd); + close(conn->ofd.fd); +} + +static int datagram_client_write(struct datagram_client_conn *conn) +{ + 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 0; + } + lh = conn->tx_queue.next; + llist_del(lh); + msg = llist_entry(lh, struct msgb, list); + + ret = send(conn->ofd.fd, msg->data, msg->len, 0); + if (ret < 0) { + LOGP(DLINP, LOGL_ERROR, "error to send (%s)\n", + strerror(errno)); + } + msgb_free(msg); + return 0; +} + +static int datagram_client_fd_cb(struct osmo_fd *ofd, unsigned int what) +{ + struct datagram_client_conn *conn = ofd->data; + + if (what & BSC_FD_WRITE) { + LOGP(DLINP, LOGL_DEBUG, "connected write\n"); + datagram_client_write(conn); + } + return 0; +} + +struct datagram_client_conn *datagram_client_conn_create(void *ctx) +{ + struct datagram_client_conn *conn; + + conn = talloc_zero(ctx, struct datagram_client_conn); + if (!conn) + return NULL; + + conn->ofd.when |= BSC_FD_READ; + conn->ofd.priv_nr = 0; /* XXX */ + conn->ofd.cb = datagram_client_fd_cb; + conn->ofd.data = conn; + INIT_LLIST_HEAD(&conn->tx_queue); + + return conn; +} + +void +datagram_client_conn_set_addr(struct datagram_client_conn *conn, const char *addr) +{ + conn->addr = talloc_strdup(conn, addr); +} + +void +datagram_client_conn_set_port(struct datagram_client_conn *conn, uint16_t port) +{ + conn->port = port; +} + +void +datagram_client_conn_set_data(struct datagram_client_conn *conn, void *data) +{ + conn->data = data; +} + +void datagram_client_conn_destroy(struct datagram_client_conn *conn) +{ + talloc_free(conn); +} + +int datagram_client_conn_open(struct datagram_client_conn *conn) +{ + int ret; + + ret = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP, + conn->addr, conn->port, + OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK); + if (ret < 0) { + if (errno != EINPROGRESS) + return ret; + } + conn->ofd.fd = ret; + if (osmo_fd_register(&conn->ofd) < 0) { + close(ret); + return -EIO; + } + return 0; +} + +void datagram_client_conn_send(struct datagram_client_conn *conn, struct msgb *msg) +{ + msgb_enqueue(&conn->tx_queue, msg); + conn->ofd.when |= BSC_FD_WRITE; +} + +/* + * Server side. + */ + +struct datagram_server_conn { + struct osmo_fd ofd; + const char *addr; + uint16_t port; + int (*cb)(struct datagram_server_conn *conn, struct msgb *msg); + void *data; +}; + +static void datagram_server_conn_read(struct datagram_server_conn *conn) +{ + struct msgb *msg; + int ret; + + LOGP(DLINP, LOGL_DEBUG, "message received\n"); + + msg = msgb_alloc(1200, "LAPD/client"); + if (!msg) { + LOGP(DLINP, LOGL_ERROR, "cannot allocate room for message\n"); + return; + } + ret = recv(conn->ofd.fd, msg->data, msg->data_len, 0); + if (ret < 0) { + if (errno == EPIPE || errno == ECONNRESET) { + LOGP(DLINP, LOGL_ERROR, "lost connection with server\n"); + } + datagram_server_conn_destroy(conn); + return; + } else if (ret == 0) { + LOGP(DLINP, LOGL_ERROR, "connection closed with server\n"); + datagram_server_conn_destroy(conn); + return; + } + msgb_put(msg, ret); + LOGP(DLINP, LOGL_NOTICE, "received %d bytes from client\n", ret); + if (conn->cb) + conn->cb(conn, msg); + + return; +} + +static int datagram_server_conn_cb(struct osmo_fd *ofd, unsigned int what) +{ + struct datagram_server_conn *conn = ofd->data; + + LOGP(DLINP, LOGL_DEBUG, "connected read/write\n"); + if (what & BSC_FD_READ) + datagram_server_conn_read(conn); + + return 0; +} + +struct datagram_server_conn *datagram_server_conn_create(void *ctx) +{ + struct datagram_server_conn *conn; + + conn = talloc_zero(ctx, struct datagram_server_conn); + if (!conn) + return NULL; + + conn->ofd.when |= BSC_FD_READ; + conn->ofd.cb = datagram_server_conn_cb; + conn->ofd.data = conn; + + return conn; +} + +void datagram_server_conn_set_addr(struct datagram_server_conn *conn, const char *addr) +{ + conn->addr = talloc_strdup(conn, addr); +} + +void datagram_server_conn_set_port(struct datagram_server_conn *conn, uint16_t port) +{ + conn->port = port; +} + +void datagram_server_conn_set_read_cb(struct datagram_server_conn *conn, + int (*read_cb)(struct datagram_server_conn *conn, struct msgb *msg)) +{ + conn->cb = read_cb; +} + +void datagram_server_conn_destroy(struct datagram_server_conn *conn) +{ + talloc_free(conn); +} + +int datagram_server_conn_open(struct datagram_server_conn *conn) +{ + int ret; + + ret = osmo_sock_init(AF_INET, SOCK_DGRAM, IPPROTO_UDP, + conn->addr, conn->port, OSMO_SOCK_F_BIND); + if (ret < 0) + return ret; + + conn->ofd.fd = ret; + if (osmo_fd_register(&conn->ofd) < 0) { + close(ret); + return -EIO; + } + return 0; +} + +void datagram_server_conn_close(struct datagram_server_conn *conn) +{ + osmo_fd_unregister(&conn->ofd); + close(conn->ofd.fd); +} + +/* + * Client+Server (bidirectional communications). + */ + +struct datagram_conn { + struct datagram_server_conn *server; + struct datagram_client_conn *client; + void *data; +}; + +struct datagram_conn *datagram_conn_create(void *ctx) +{ + struct datagram_conn *conn; + + conn = talloc_zero(ctx, struct datagram_conn); + if (!conn) + return NULL; + + conn->server = datagram_server_conn_create(ctx); + if (conn->server == NULL) + return NULL; + + conn->client = datagram_client_conn_create(ctx); + if (conn->client == NULL) { + datagram_server_conn_destroy(conn->server); + return NULL; + } + + return conn; +} + +void datagram_conn_destroy(struct datagram_conn *conn) +{ + datagram_server_conn_destroy(conn->server); + datagram_client_conn_destroy(conn->client); +} + +void +datagram_conn_set_local_addr(struct datagram_conn *conn, const char *addr) +{ + datagram_server_conn_set_addr(conn->server, addr); +} + +void +datagram_conn_set_remote_addr(struct datagram_conn *conn, const char *addr) +{ + datagram_client_conn_set_addr(conn->client, addr); +} + +void +datagram_conn_set_local_port(struct datagram_conn *conn, uint16_t port) +{ + datagram_server_conn_set_port(conn->server, port); +} + +void +datagram_conn_set_remote_port(struct datagram_conn *conn, uint16_t port) +{ + datagram_client_conn_set_port(conn->client, port); +} + +void datagram_conn_set_read_cb(struct datagram_conn *conn, + int (*read_cb)(struct datagram_server_conn *conn, struct msgb *msg)) +{ + conn->server->cb = read_cb; +} + +void +datagram_conn_set_data(struct datagram_client_conn *conn, void *data) +{ + conn->data = data; +} + +int datagram_conn_open(struct datagram_conn *conn) +{ + int ret; + + ret = datagram_server_conn_open(conn->server); + if (ret < 0) + return ret; + + ret = datagram_client_conn_open(conn->client); + if (ret < 0) { + datagram_server_conn_close(conn->server); + return ret; + } + return ret; +} + +void datagram_conn_close(struct datagram_conn *conn) +{ + datagram_server_conn_close(conn->server); + datagram_client_conn_close(conn->client); +} + +void datagram_conn_send(struct datagram_conn *conn, struct msgb *msg) +{ + datagram_client_conn_send(conn->client, msg); +} -- cgit v1.2.3