Revert various debian related changes
[osmocom-bb.git] / src / gsmtap_util.c
index 5da4369..c8c26c6 100644 (file)
@@ -1,6 +1,6 @@
-/* GSMTAP output for Osmocom Layer2 (will only work on the host PC) */
+/* GSMTAP support code in libmsomcore */
 /*
- * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010-2011 by Harald Welte <laforge@gnumonks.org>
  *
  * All Rights Reserved
  *
 
 #include "../config.h"
 
-#ifdef HAVE_SYS_SELECT_H
+#include <osmocom/core/gsmtap_util.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/gsmtap.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/rsl.h>
 
-#include <osmocore/gsmtap_util.h>
-#include <osmocore/logging.h>
-#include <osmocore/protocol/gsm_04_08.h>
-#include <osmocore/gsmtap.h>
-#include <osmocore/msgb.h>
-#include <osmocore/rsl.h>
-#include <osmocore/select.h>
+#include <sys/types.h>
 
 #include <arpa/inet.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
 
 #include <stdio.h>
 #include <unistd.h>
@@ -42,9 +42,6 @@
 #include <string.h>
 #include <errno.h>
 
-static struct bsc_fd gsmtap_bfd = { .fd = -1 };
-static LLIST_HEAD(gsmtap_txqueue);
-
 uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id)
 {
        uint8_t ret = GSMTAP_CHANNEL_UNKNOWN;
@@ -81,21 +78,17 @@ uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id)
 }
 
 /* receive a message from L1/L2 and put it in GSMTAP */
-int gsmtap_sendmsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, uint8_t ss,
-                  uint32_t fn, int8_t signal_dbm, uint8_t snr,
-                  const uint8_t *data, unsigned int len)
+struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type,
+                           uint8_t ss, uint32_t fn, int8_t signal_dbm,
+                           uint8_t snr, const uint8_t *data, unsigned int len)
 {
        struct msgb *msg;
        struct gsmtap_hdr *gh;
        uint8_t *dst;
 
-       /* gsmtap was never initialized, so don't try to send anything */
-       if (gsmtap_bfd.fd == -1)
-               return 0;
-
        msg = msgb_alloc(sizeof(*gh) + len, "gsmtap_tx");
        if (!msg)
-               return -ENOMEM;
+               return NULL;
 
        gh = (struct gsmtap_hdr *) msgb_put(msg, sizeof(*gh));
 
@@ -114,72 +107,174 @@ int gsmtap_sendmsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, uint8_t ss,
        dst = msgb_put(msg, len);
        memcpy(dst, data, len);
 
-       msgb_enqueue(&gsmtap_txqueue, msg);
-       gsmtap_bfd.when |= BSC_FD_WRITE;
+       return msg;
+}
 
-       return 0;
+#ifdef HAVE_SYS_SOCKET_H
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/* Open a GSMTAP source (sending) socket, conncet it to host/port and
+ * return resulting fd */
+int gsmtap_source_init_fd(const char *host, uint16_t port)
+{
+       if (port == 0)
+               port = GSMTAP_UDP_PORT;
+       if (host == NULL)
+               host = "localhost";
+
+       return osmo_sock_init(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, host, port,
+                               OSMO_SOCK_F_CONNECT);
 }
 
-/* Callback from select layer if we can write to the socket */
-static int gsmtap_fd_cb(struct bsc_fd *fd, unsigned int flags)
+int gsmtap_source_add_sink_fd(int gsmtap_fd)
 {
-       struct msgb *msg;
+       struct sockaddr_storage ss;
+       socklen_t ss_len = sizeof(ss);
        int rc;
 
-       if (!(flags & BSC_FD_WRITE))
-               return 0;
+       rc = getpeername(gsmtap_fd, (struct sockaddr *)&ss, &ss_len);
+       if (rc < 0)
+               return rc;
 
-       msg = msgb_dequeue(&gsmtap_txqueue);
-       if (!msg) {
-               /* no more messages in the queue, disable READ cb */
-               gsmtap_bfd.when = 0;
-               return 0;
+       if (osmo_sockaddr_is_local((struct sockaddr *)&ss, ss_len) == 1) {
+               rc = osmo_sock_init_sa((struct sockaddr *)&ss, SOCK_DGRAM,
+                                       IPPROTO_UDP, OSMO_SOCK_F_BIND);
+               if (rc >= 0)
+                       return rc;
        }
-       rc = write(gsmtap_bfd.fd, msg->data, msg->len);
+
+       return -ENODEV;
+}
+
+int gsmtap_sendmsg(struct gsmtap_inst *gti, struct msgb *msg)
+{
+       if (!gti)
+               return -ENODEV;
+
+       if (gti->ofd_wq_mode)
+               return osmo_wqueue_enqueue(&gti->wq, msg);
+       else {
+               /* try immediate send and return error if any */
+               int rc;
+
+               rc = write(gsmtap_inst_fd(gti), msg->data, msg->len);
+               if (rc <= 0) {
+                       return rc;
+               } else if (rc >= msg->len) {
+                       msgb_free(msg);
+                       return 0;
+               } else {
+                       /* short write */
+                       return -EIO;
+               }
+       }
+}
+
+/* receive a message from L1/L2 and put it in GSMTAP */
+int gsmtap_send(struct gsmtap_inst *gti, uint16_t arfcn, uint8_t ts,
+               uint8_t chan_type, uint8_t ss, uint32_t fn,
+               int8_t signal_dbm, uint8_t snr, const uint8_t *data,
+               unsigned int len)
+{
+       struct msgb *msg;
+
+       if (!gti)
+               return -ENODEV;
+
+       msg = gsmtap_makemsg(arfcn, ts, chan_type, ss, fn, signal_dbm,
+                            snr, data, len);
+       if (!msg)
+               return -ENOMEM;
+
+       return gsmtap_sendmsg(gti, msg);
+}
+
+/* Callback from select layer if we can write to the socket */
+static int gsmtap_wq_w_cb(struct osmo_fd *ofd, struct msgb *msg)
+{
+       int rc;
+
+       rc = write(ofd->fd, msg->data, msg->len);
        if (rc < 0) {
                perror("writing msgb to gsmtap fd");
-               msgb_free(msg);
                return rc;
        }
        if (rc != msg->len) {
                perror("short write to gsmtap fd");
-               msgb_free(msg);
                return -EIO;
        }
 
-       msgb_free(msg);
        return 0;
 }
 
-int gsmtap_init(uint32_t dst_ip)
+/* Callback from select layer if we can read from the sink socket */
+static int gsmtap_sink_fd_cb(struct osmo_fd *fd, unsigned int flags)
 {
        int rc;
-       struct sockaddr_in sin;
+       uint8_t buf[4096];
 
-       sin.sin_family = AF_INET;
-       sin.sin_port = htons(GSMTAP_UDP_PORT);
-       sin.sin_addr.s_addr = htonl(dst_ip);
+       if (!(flags & BSC_FD_READ))
+               return 0;
 
-       /* FIXME: create socket */
-       rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       rc = read(fd->fd, buf, sizeof(buf));
        if (rc < 0) {
-               perror("creating UDP socket");
+               perror("reading from gsmtap sink fd");
                return rc;
        }
-       gsmtap_bfd.fd = rc;
-       rc = connect(rc, (struct sockaddr *)&sin, sizeof(sin));
-       if (rc < 0) {
-               perror("connecting UDP socket");
-               close(gsmtap_bfd.fd);
-               gsmtap_bfd.fd = 0;
-               return rc;
+       /* simply discard any data arriving on the socket */
+
+       return 0;
+}
+
+/* Add a local sink to an existing GSMTAP source instance */
+int gsmtap_source_add_sink(struct gsmtap_inst *gti)
+{
+       int fd;
+
+       fd = gsmtap_source_add_sink_fd(gsmtap_inst_fd(gti));
+       if (fd < 0)
+               return fd;
+
+       if (gti->ofd_wq_mode) {
+               struct osmo_fd *sink_ofd;
+
+               sink_ofd = &gti->sink_ofd;
+               sink_ofd->fd = fd;
+               sink_ofd->when = BSC_FD_READ;
+               sink_ofd->cb = gsmtap_sink_fd_cb;
+
+               osmo_fd_register(sink_ofd);
        }
 
-       gsmtap_bfd.when = BSC_FD_WRITE;
-       gsmtap_bfd.cb = gsmtap_fd_cb;
-       gsmtap_bfd.data = NULL;
+       return fd;
+}
+
+/* like gsmtap_init2() but integrated with libosmocore select.c */
+struct gsmtap_inst *gsmtap_source_init(const char *host, uint16_t port,
+                                       int ofd_wq_mode)
+{
+       struct gsmtap_inst *gti;
+       int fd;
+
+       fd = gsmtap_source_init_fd(host, port);
+       if (fd < 0)
+               return NULL;
+
+       gti = talloc_zero(NULL, struct gsmtap_inst);
+       gti->ofd_wq_mode = ofd_wq_mode;
+       gti->wq.bfd.fd = fd;
+       gti->sink_ofd.fd = -1;
+
+       if (ofd_wq_mode) {
+               osmo_wqueue_init(&gti->wq, 64);
+               gti->wq.write_cb = &gsmtap_wq_w_cb;
+
+               osmo_fd_register(&gti->wq.bfd);
+       }
 
-       return bsc_register_fd(&gsmtap_bfd);
+       return gti;
 }
 
-#endif /* HAVE_SYS_SELECT_H */
+#endif /* HAVE_SYS_SOCKET_H */