aboutsummaryrefslogtreecommitdiffstats
path: root/tests/virtsock/mcast_sock.c
diff options
context:
space:
mode:
authorSebastian Stumpf <sebastian.stumpf87@googlemail.com>2017-01-08 16:31:50 +0100
committerSebastian Stumpf <sebastian.stumpf87@googlemail.com>2017-01-08 16:31:50 +0100
commita8b7c8aa05bf7292c6ed289f22f961d9ec397fc1 (patch)
tree6b1d32a5de81a1c731d96e0c299343cdf384771b /tests/virtsock/mcast_sock.c
parent17eb1a45b446d631449143a52b503978e6661637 (diff)
VIRT-PHY: Added functionality to cooperate with osmocom-bb virt-phy.
This patch improves the virtual physical layer designed to replace the air interface. The purpose is to get rid of the hardware requirements and be able to start testing and implementing layer 2 communication functionality on one machine. Multicast sockets are used to enable bidirectional communication between the BTS and the MS process. The GSMTAP protocol designed for wireshark capturing is used to encapsulate the payload on the virtual physical layer. * Working mcast socket communication and extraction of its functionality. * Fixed OML and RSL startup sequences. * Icludes tests for mcast socket and virtual UM. * Ecapsulation and parsing methods to and from GSMTAP messages. * Basic handlers for file descriptor callbacks from incoming mcast messages. * Multiplexing to different channels based on GSMTAP header channel type.
Diffstat (limited to 'tests/virtsock/mcast_sock.c')
-rw-r--r--tests/virtsock/mcast_sock.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/tests/virtsock/mcast_sock.c b/tests/virtsock/mcast_sock.c
new file mode 100644
index 00000000..4ca562a0
--- /dev/null
+++ b/tests/virtsock/mcast_sock.c
@@ -0,0 +1,220 @@
+#include <netinet/in.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <bits/sockaddr.h>
+
+#include "mcast_sock.h"
+
+struct mcast_server_sock *mcast_server_sock_setup(char* tx_mcast_group,
+ int tx_mcast_port,
+ int loopback)
+{
+ struct mcast_server_sock *serv_sock = malloc(
+ sizeof(struct mcast_server_sock));
+ struct sockaddr_in *tx_mcast_sock_conf = malloc(
+ sizeof(struct sockaddr_in));
+
+ // setup mcast server socket
+ serv_sock->sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (serv_sock->sd == -1) {
+ perror("Failed to create Multicast Socket.\n");
+ return NULL;
+ }
+ memset(tx_mcast_sock_conf, 0, sizeof(*tx_mcast_sock_conf));
+ tx_mcast_sock_conf->sin_family = AF_INET;
+ tx_mcast_sock_conf->sin_addr.s_addr = inet_addr(tx_mcast_group);
+ tx_mcast_sock_conf->sin_port = htons(tx_mcast_port);
+ serv_sock->sock_conf = tx_mcast_sock_conf;
+
+ // disable loopback
+ if (loopback) {
+ char loop = 0;
+ if (setsockopt(serv_sock->sd, IPPROTO_IP,
+ IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) {
+ perror("Failed to disable loopback.\n");
+ return NULL;
+ }
+ }
+
+// // setup rx unix domain socket
+// serv_sock->sd = socket(AF_LOCAL, SOCK_STREAM, IPPROTO_UDP);
+// if (serv_sock->sd < 0) {
+// perror("Failed to create Unix Domain Socket.\n");
+// return NULL;
+// }
+// rx_sock_conf->sun_family = AF_LOCAL;
+// strcpy(rx_sock_conf->sun_path, rx_unix_path);
+// unlink(rx_sock_conf->sun_path);
+//
+// if (bind(serv_sock->sd, (struct sockaddr *)&rx_sock_conf,
+// sizeof(rx_sock_conf)) != 0) {
+// perror("Failed to bind the unix domain socket. '%s'\n",
+// rx_sock_conf->sun_path);
+// return NULL;
+// }
+//
+// if (listen(serv_sock->sd, 0) != 0) {
+// perror("Failed to listen.\n");
+// return NULL;
+// }
+ return serv_sock;
+}
+
+struct mcast_client_sock *mcast_client_sock_setup(char* mcast_group,
+ int mcast_port)
+{
+ struct mcast_client_sock *client_sock = malloc(
+ sizeof(struct mcast_client_sock));
+ struct sockaddr_in *rx_sock_conf = malloc(sizeof(struct sockaddr_in));
+
+ struct ip_mreq *group_conf = malloc(sizeof(struct ip_mreq));
+ int rc, opt = 1;
+
+ // setup mcast client socket
+ client_sock->sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (client_sock->sd == -1) {
+ return NULL;
+ }
+
+ memset(rx_sock_conf, 0, sizeof(*rx_sock_conf));
+ rx_sock_conf->sin_family = AF_INET;
+ // INADDR_ANY -> don't specify an interface, let OS choose the proper one
+ rx_sock_conf->sin_addr.s_addr = htonl(INADDR_ANY);
+ rx_sock_conf->sin_port = htons(mcast_port);
+ client_sock->sock_conf = rx_sock_conf;
+
+ /* let multiple processes use the same port */
+ rc = setsockopt(client_sock->sd,
+ SOL_SOCKET,
+ SO_REUSEADDR, &opt, sizeof(opt));
+ if (rc < 0) {
+ return NULL;
+ }
+ rc = bind(client_sock->sd, (struct sockaddr *)client_sock->sock_conf,
+ sizeof(*client_sock->sock_conf));
+ if (rc < 0) {
+ return NULL;
+ }
+
+ /* configure broadcast on this machine */
+ opt = 1;
+ rc = setsockopt(client_sock->sd,
+ IPPROTO_IP,
+ IP_MULTICAST_LOOP, &opt, sizeof(opt));
+ if (rc < 0) {
+ return NULL;
+ }
+
+ /* configure the broadcast group */
+ group_conf->imr_multiaddr.s_addr = inet_addr(mcast_group);
+ group_conf->imr_interface.s_addr = htonl(INADDR_ANY);
+ if (group_conf->imr_multiaddr.s_addr == -1) {
+ return NULL;
+ }
+ client_sock->mcast_group = group_conf;
+
+ /* join the broadcast group */
+ rc = setsockopt(client_sock->sd,
+ IPPROTO_IP,
+ IP_ADD_MEMBERSHIP, client_sock->mcast_group,
+ sizeof(*client_sock->mcast_group));
+ if (rc < 0) {
+ return NULL;
+ }
+
+// // setup tx unix domain socket
+// client_sock->tx_sd = socket(AF_LOCAL, SOCK_STREAM, IPPROTO_UDP);
+// if (client_sock->tx_sd < 0) {
+// perror("Failed to create Unix Domain Socket.\n");
+// return NULL;
+// }
+// tx_sock_conf.sun_family = AF_LOCAL;
+// strcpy(tx_sock_conf.sun_path, tx_unix_path);
+// unlink(tx_sock_conf.sun_path);
+//
+// if (bind(client_sock->tx_sd, (struct sockaddr *)&tx_sock_conf,
+// sizeof(tx_sock_conf)) != 0) {
+// perror("Failed to bind the unix domain socket. '%s'\n",
+// tx_sock_conf.sun_path);
+// return NULL;
+// }
+//
+// if ((client_sock->tx_sd, (struct sockaddr *)&tx_sock_conf, sizeof(tx_sock_conf))
+// != 0) {
+// perror("Failed to listen.\n");
+// return NULL;
+// }
+
+ return client_sock;
+}
+
+struct mcast_bidir_sock *mcast_bidir_sock_setup(char* tx_mcast_group,
+ int tx_mcast_port,
+ char* rx_mcast_group,
+ int rx_mcast_port)
+{
+ struct mcast_bidir_sock *bidir_sock = malloc(
+ sizeof(struct mcast_bidir_sock));
+ bidir_sock->rx_sock = mcast_client_sock_setup(rx_mcast_group,
+ rx_mcast_port);
+ bidir_sock->tx_sock = mcast_server_sock_setup(tx_mcast_group,
+ tx_mcast_port, 0);
+ if (!bidir_sock->rx_sock || !bidir_sock->tx_sock) {
+ return NULL;
+ }
+ return bidir_sock;
+
+}
+
+int mcast_client_sock_rx(struct mcast_client_sock *client_sock, void* buf,
+ int buf_len)
+{
+ return recv(client_sock->sd, buf, buf_len, 0);
+}
+
+int mcast_server_sock_tx(struct mcast_server_sock *serv_sock, void* data,
+ int data_len)
+{
+ return sendto(serv_sock->sd, data, data_len, 0,
+ (struct sockaddr *)serv_sock->sock_conf,
+ sizeof(*serv_sock->sock_conf));
+}
+
+int mcast_bidir_sock_tx(struct mcast_bidir_sock *bidir_sock, void* data,
+ int data_len)
+{
+ return mcast_server_sock_tx(bidir_sock->tx_sock, data, data_len);
+}
+int mcast_bidir_sock_rx(struct mcast_bidir_sock *bidir_sock, void* buf,
+ int buf_len)
+{
+ return mcast_client_sock_rx(bidir_sock->rx_sock, buf, buf_len);
+}
+
+int mcast_client_sock_close(struct mcast_client_sock *client_sock)
+{
+ free(client_sock->mcast_group);
+ free(client_sock->sock_conf);
+ free(client_sock);
+ return setsockopt(client_sock->sd,
+ IPPROTO_IP,
+ IP_DROP_MEMBERSHIP, client_sock->mcast_group,
+ sizeof(*client_sock->mcast_group))
+ + close(client_sock->sd);
+
+}
+int mcast_server_sock_close(struct mcast_server_sock *serv_sock)
+{
+ free(serv_sock->sock_conf);
+ free(serv_sock);
+ return close(serv_sock->sd) + close(serv_sock->sd);
+}
+
+int mcast_bidir_sock_close(struct mcast_bidir_sock *bidir_sock)
+{
+ free(bidir_sock);
+ return mcast_client_sock_close(bidir_sock->rx_sock)
+ + mcast_server_sock_close(bidir_sock->tx_sock);
+
+}