diff options
-rw-r--r-- | examples/Makefile.am | 12 | ||||
-rw-r--r-- | examples/ipa-stream-client.c | 185 | ||||
-rw-r--r-- | examples/ipa-stream-server.c | 121 | ||||
-rw-r--r-- | include/osmocom/netif/Makefile.am | 1 | ||||
-rw-r--r-- | include/osmocom/netif/ipa.h | 52 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/ipa.c | 73 |
7 files changed, 444 insertions, 1 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am index 39e7207..be4ecde 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,11 +2,21 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -g $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) -noinst_PROGRAMS = lapd-over-datagram-user \ +noinst_PROGRAMS = ipa-stream-client \ + ipa-stream-server \ + lapd-over-datagram-user \ lapd-over-datagram-network \ stream-client \ stream-server +ipa_stream_client_SOURCES = ipa-stream-client.c +ipa_stream_client_LDADD = $(top_builddir)/src/libosmonetif.la \ + $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) + +ipa_stream_server_SOURCES = ipa-stream-server.c +ipa_stream_server_LDADD = $(top_builddir)/src/libosmonetif.la \ + $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) + lapd_over_datagram_user_SOURCES = lapd-over-datagram-user.c lapd_over_datagram_user_LDADD = $(top_builddir)/src/libosmonetif.la \ $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) \ diff --git a/examples/ipa-stream-client.c b/examples/ipa-stream-client.c new file mode 100644 index 0000000..2b90f2c --- /dev/null +++ b/examples/ipa-stream-client.c @@ -0,0 +1,185 @@ +/* IPA stream client example. */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/time.h> +#include <arpa/inet.h> + +#include <osmocom/core/select.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/application.h> + +#include <osmocom/netif/stream.h> +#include <osmocom/netif/ipa.h> + +static LLIST_HEAD(msg_sent_list); + +struct msg_sent { + struct llist_head head; + struct msgb *msg; + int num; + struct timeval tv; +}; + +#define DIPATEST 0 + +struct log_info_cat osmo_stream_client_test_cat[] = { + [DIPATEST] = { + .name = "DIPATEST", + .description = "STREAMCLIENT-mode test", + .color = "\033[1;35m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, +}; + +const struct log_info osmo_stream_client_test_log_info = { + .filter_fn = NULL, + .cat = osmo_stream_client_test_cat, + .num_cat = ARRAY_SIZE(osmo_stream_client_test_cat), +}; + +static struct osmo_stream_client_conn *conn; + +void sighandler(int foo) +{ + LOGP(DIPATEST, LOGL_NOTICE, "closing stream.\n"); + exit(EXIT_SUCCESS); +} + +static int connect_cb(struct osmo_stream_client_conn *conn) +{ + int *__num_msgs = osmo_stream_client_conn_get_data(conn); + int num_msgs = *__num_msgs, i; + + LOGP(DIPATEST, LOGL_NOTICE, "connected\n"); + + for (i=0; i<num_msgs; i++) { + struct msgb *msg; + struct msg_sent *msg_sent; + char *ptr; + int x; + + msg = osmo_ipa_msg_alloc(0); + if (msg == NULL) { + LOGP(DLINP, LOGL_ERROR, "cannot alloc msg\n"); + return -1; + } + ptr = (char *)msgb_put(msg, sizeof(int)); + x = htonl(i); + memcpy(ptr, &x, sizeof(int)); + + msg_sent = talloc_zero(NULL, struct msg_sent); + if (msg_sent == NULL) { + LOGP(DLINP, LOGL_ERROR, "can't alloc struct\n"); + return -1; + } + msg_sent->msg = msg; + gettimeofday(&msg_sent->tv, NULL); + msg_sent->num = i; + llist_add(&msg_sent->head, &msg_sent_list); + + osmo_ipa_msg_push_header(msg, IPAC_PROTO_OSMO); + + osmo_stream_client_conn_send(conn, msg); + + LOGP(DIPATEST, LOGL_DEBUG, "enqueueing msg %d of " + "%d bytes to be sent\n", i, msg->len); + } + return 0; +} + +static int read_cb(struct osmo_stream_client_conn *conn) +{ + struct msgb *msg; + struct osmo_fd *ofd = osmo_stream_client_conn_get_ofd(conn); + + LOGP(DIPATEST, LOGL_DEBUG, "received message from stream\n"); + + msg = osmo_ipa_msg_alloc(0); + if (msg == NULL) { + LOGP(DIPATEST, LOGL_ERROR, "cannot allocate message\n"); + return 0; + } + if (osmo_ipa_msg_recv(ofd->fd, msg) <= 0) { + LOGP(DIPATEST, LOGL_ERROR, "cannot receive message\n"); + return 0; + } + + int num; + struct msg_sent *cur, *tmp, *found = NULL; + + num = ntohl(*((int *)(msg->data + sizeof(struct ipa_head)))); + LOGP(DLINP, LOGL_DEBUG, "received msg number %d\n", num); + + llist_for_each_entry_safe(cur, tmp, &msg_sent_list, head) { + if (cur->num == num) { + llist_del(&cur->head); + found = cur; + break; + } + } + if (found) { + struct timeval tv, diff; + + gettimeofday(&tv, NULL); + timersub(&tv, &found->tv, &diff); + + LOGP(DLINP, LOGL_NOTICE, "message %d replied " + "in %lu.%.6lu\n", num, diff.tv_sec, diff.tv_usec); + talloc_free(found); + } else { + LOGP(DLINP, LOGL_ERROR, + "message %d not found!\n", num); + } + return 0; +} + +static void *tall_test; + +int main(int argc, char *argv[]) +{ + int num_msgs; + + signal(SIGINT, sighandler); + + if (argc != 2) { + printf("Usage: %s [num_msgs]\n", argv[0]); + exit(EXIT_FAILURE); + } + num_msgs = atoi(argv[1]); + + tall_test = talloc_named_const(NULL, 1, "osmo_stream_client_test"); + + osmo_init_logging(&osmo_stream_client_test_log_info); + log_set_log_level(osmo_stderr_target, LOGL_NOTICE); + + /* + * initialize stream client. + */ + + conn = osmo_stream_client_conn_create(tall_test); + if (conn == NULL) { + fprintf(stderr, "cannot create client\n"); + exit(EXIT_FAILURE); + } + osmo_stream_client_conn_set_addr(conn, "127.0.0.1"); + osmo_stream_client_conn_set_port(conn, 10000); + osmo_stream_client_conn_set_connect_cb(conn, connect_cb); + osmo_stream_client_conn_set_read_cb(conn, read_cb); + osmo_stream_client_conn_set_data(conn, &num_msgs); + + if (osmo_stream_client_conn_open(conn) < 0) { + fprintf(stderr, "cannot open client\n"); + exit(EXIT_FAILURE); + } + + LOGP(DIPATEST, LOGL_NOTICE, "Entering main loop\n"); + + while(1) { + osmo_select_main(0); + } +} diff --git a/examples/ipa-stream-server.c b/examples/ipa-stream-server.c new file mode 100644 index 0000000..5264dab --- /dev/null +++ b/examples/ipa-stream-server.c @@ -0,0 +1,121 @@ +/* IPA stream server example */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <osmocom/core/select.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/application.h> + +#include <osmocom/netif/stream.h> +#include <osmocom/netif/ipa.h> + +static void *tall_test; + +#define DSTREAMTEST 0 + +struct log_info_cat osmo_stream_server_test_cat[] = { + [DSTREAMTEST] = { + .name = "DSTREAMTEST", + .description = "STREAMSERVER-mode test", + .color = "\033[1;35m", + .enabled = 1, .loglevel = LOGL_NOTICE, + }, +}; + +const struct log_info osmo_stream_server_test_log_info = { + .filter_fn = NULL, + .cat = osmo_stream_server_test_cat, + .num_cat = ARRAY_SIZE(osmo_stream_server_test_cat), +}; + +static struct osmo_stream_server_link *server; +static struct osmo_stream_server_conn *conn; + +void sighandler(int foo) +{ + LOGP(DSTREAMTEST, LOGL_NOTICE, "closing STREAMSERVER.\n"); + exit(EXIT_SUCCESS); +} + +int read_cb(struct osmo_stream_server_conn *conn) +{ + struct msgb *msg; + struct osmo_fd *ofd = osmo_stream_server_conn_get_ofd(conn); + + LOGP(DSTREAMTEST, LOGL_DEBUG, "received message from stream\n"); + + msg = osmo_ipa_msg_alloc(0); + if (msg == NULL) { + LOGP(DSTREAMTEST, LOGL_ERROR, "cannot allocate message\n"); + return 0; + } + if (osmo_ipa_msg_recv(ofd->fd, msg) <= 0) { + LOGP(DSTREAMTEST, LOGL_ERROR, "cannot receive message\n"); + osmo_stream_server_conn_destroy(conn); + msgb_free(msg); + return 0; + } + osmo_stream_server_conn_send(conn, msg); + return 0; +} + +static int close_cb(struct osmo_stream_server_conn *dummy) +{ + conn = NULL; + return 0; +} + +static int accept_cb(struct osmo_stream_server_link *server, int fd) +{ + if (conn != NULL) { + LOGP(DSTREAMTEST, LOGL_ERROR, "Sorry, this example only " + "support one client simultaneously\n"); + return -1; + } + + conn = osmo_stream_server_conn_create(tall_test, server, fd, + read_cb, close_cb, NULL); + if (conn == NULL) { + LOGP(DSTREAMTEST, LOGL_ERROR, + "error while creating connection\n"); + return -1; + } + + return 0; +} + +int main(void) +{ + tall_test = talloc_named_const(NULL, 1, "osmo_stream_server_test"); + + osmo_init_logging(&osmo_stream_server_test_log_info); + log_set_log_level(osmo_stderr_target, LOGL_NOTICE); + + /* + * initialize stream server. + */ + + server = osmo_stream_server_link_create(tall_test); + if (server == NULL) { + fprintf(stderr, "cannot create client\n"); + exit(EXIT_FAILURE); + } + osmo_stream_server_link_set_addr(server, "127.0.0.1"); + osmo_stream_server_link_set_port(server, 10000); + osmo_stream_server_link_set_accept_cb(server, accept_cb); + + if (osmo_stream_server_link_open(server) < 0) { + fprintf(stderr, "cannot open client\n"); + exit(EXIT_FAILURE); + } + + LOGP(DSTREAMTEST, LOGL_NOTICE, "Entering main loop\n"); + + while(1) { + osmo_select_main(0); + } +} diff --git a/include/osmocom/netif/Makefile.am b/include/osmocom/netif/Makefile.am index afab204..4e63846 100644 --- a/include/osmocom/netif/Makefile.am +++ b/include/osmocom/netif/Makefile.am @@ -1,4 +1,5 @@ osmonetif_HEADERS = datagram.h \ + ipa.h \ stream.h osmonetifdir = $(includedir)/osmocom/netif diff --git a/include/osmocom/netif/ipa.h b/include/osmocom/netif/ipa.h new file mode 100644 index 0000000..5b53b3a --- /dev/null +++ b/include/osmocom/netif/ipa.h @@ -0,0 +1,52 @@ +#ifndef _OSMO_NETIF_IPA_H_ +#define _OSMO_NETIF_IPA_H_ + +struct ipa_head { + uint16_t len; /* network byte order */ + uint8_t proto; + uint8_t data[0]; +} __attribute__ ((packed)); + +/* IPA protocols. */ +#define IPAC_PROTO_RSL 0x00 +#define IPAC_PROTO_IPACCESS 0xfe +#define IPAC_PROTO_SCCP 0xfd +#define IPAC_PROTO_OML 0xff +#define IPAC_PROTO_OSMO 0xee /* OpenBSC extension. */ +#define IPAC_PROTO_MGCP_OLD 0xfc /* OpenBSC extension. */ + +struct ipa_head_ext { + uint8_t proto; + uint8_t data[0]; +} __attribute__ ((packed)); + +/* Protocol extensions. */ +#define IPAC_PROTO_EXT_CTRL 0x00 +#define IPAC_PROTO_EXT_MGCP 0x01 +#define IPAC_PROTO_EXT_LAC 0x02 + +/* Message types. */ +#define IPAC_MSGT_PING 0x00 +#define IPAC_MSGT_PONG 0x01 +#define IPAC_MSGT_ID_GET 0x04 +#define IPAC_MSGT_ID_RESP 0x05 +#define IPAC_MSGT_ID_ACK 0x06 +#define IPAC_MSGT_SCCP_OLD 0xff /* OpenBSC extension */ + +enum ipaccess_id_tags { + IPAC_IDTAG_SERNR = 0x00, + IPAC_IDTAG_UNITNAME = 0x01, + IPAC_IDTAG_LOCATION1 = 0x02, + IPAC_IDTAG_LOCATION2 = 0x03, + IPAC_IDTAG_EQUIPVERS = 0x04, + IPAC_IDTAG_SWVERSION = 0x05, + IPAC_IDTAG_IPADDR = 0x06, + IPAC_IDTAG_MACADDR = 0x07, + IPAC_IDTAG_UNIT = 0x08, +}; + +struct msgb *osmo_ipa_msg_alloc(int headroom); +void osmo_ipa_msg_push_header(struct msgb *msg, uint8_t proto); +int osmo_ipa_msg_recv(int fd, struct msgb *msg); + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index bf2d60a..c501a57 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,4 +9,5 @@ AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(COVERAG lib_LTLIBRARIES = libosmonetif.la libosmonetif_la_SOURCES = datagram.c \ + ipa.c \ stream.c diff --git a/src/ipa.c b/src/ipa.c new file mode 100644 index 0000000..335c830 --- /dev/null +++ b/src/ipa.c @@ -0,0 +1,73 @@ +#include <stdlib.h> +#include <arpa/inet.h> +#include <errno.h> + +#include <osmocom/core/logging.h> +#include <osmocom/core/msgb.h> +#include <osmocom/netif/ipa.h> + +#define IPA_ALLOC_SIZE 1200 + +struct msgb *osmo_ipa_msg_alloc(int headroom) +{ + struct msgb *msg; + + headroom += sizeof(struct ipa_head); + + msg = msgb_alloc_headroom(IPA_ALLOC_SIZE + headroom, headroom, "IPA"); + if (msg == NULL) { + LOGP(DLINP, LOGL_ERROR, "cannot allocate message\n"); + return NULL; + } + return msg; +} + +void osmo_ipa_msg_push_header(struct msgb *msg, uint8_t proto) +{ + struct ipa_head *hh; + + msg->l2h = msg->data; + hh = (struct ipa_head *) msgb_push(msg, sizeof(*hh)); + hh->proto = proto; + hh->len = htons(msgb_l2len(msg)); +} + +int osmo_ipa_msg_recv(int fd, struct msgb *msg) +{ + struct ipa_head *hh; + int len, ret; + + /* first read our 3-byte header */ + hh = (struct ipa_head *) msg->data; + ret = recv(fd, msg->data, sizeof(*hh), 0); + if (ret <= 0) { + return ret; + } else if (ret != sizeof(*hh)) { + LOGP(DLINP, LOGL_ERROR, "too small message received\n"); + return -EIO; + } + msgb_put(msg, ret); + + /* then read the length as specified in header */ + msg->l2h = msg->data + sizeof(*hh); + len = ntohs(hh->len); + + if (len < 0 || IPA_ALLOC_SIZE < len + sizeof(*hh)) { + LOGP(DLINP, LOGL_ERROR, "bad message length of %d bytes, " + "received %d bytes\n", len, ret); + msgb_free(msg); + return -EIO; + } + + ret = recv(fd, msg->l2h, len, 0); + if (ret <= 0) { + msgb_free(msg); + return ret; + } else if (ret < len) { + LOGP(DLINP, LOGL_ERROR, "trunked message received\n"); + msgb_free(msg); + return -EIO; + } + msgb_put(msg, ret); + return ret; +} |