From 718f754c07f6981cffc6ddb4934b1cb738889da8 Mon Sep 17 00:00:00 2001
From: frtabu <francois.taburet@nokia-bell-labs.com>
Date: Mon, 7 Jan 2019 19:36:24 +0100
Subject: [PATCH] modify tcp_bridge_oai.c to support remote connections, old
 behavior is maintained, define TCPBRIDGE environment variable to the enb ip
 address on ue side.

---
 targets/ARCH/tcp_bridge/tcp_bridge_oai.c | 387 +++++++++++++----------
 1 file changed, 224 insertions(+), 163 deletions(-)

diff --git a/targets/ARCH/tcp_bridge/tcp_bridge_oai.c b/targets/ARCH/tcp_bridge/tcp_bridge_oai.c
index 32fddb9c2dc..b06d327da24 100644
--- a/targets/ARCH/tcp_bridge/tcp_bridge_oai.c
+++ b/targets/ARCH/tcp_bridge/tcp_bridge_oai.c
@@ -8,33 +8,47 @@
 #include <unistd.h>
 #include <errno.h>
 
-int fullread(int fd, void *_buf, int count)
-{
+const int port = 4043;
+#define helpTxt "\
+\x1b[31m\
+tcp_bridge: error: you have to run one UE and one eNB\n\
+For this, export TCPBRIDGE=enb (eNB case) or \n\
+                 TCPBRIDGE=<an ip address> (UE case)\n\
+\x1b[m"
+
+int fullread(int fd, void *_buf, int count) {
   char *buf = _buf;
   int ret = 0;
   int l;
+
   while (count) {
     l = read(fd, buf, count);
+
     if (l <= 0) return -1;
+
     count -= l;
     buf += l;
     ret += l;
   }
+
   return ret;
 }
 
-int fullwrite(int fd, void *_buf, int count)
-{
+int fullwrite(int fd, void *_buf, int count) {
   char *buf = _buf;
   int ret = 0;
   int l;
+
   while (count) {
     l = write(fd, buf, count);
+
     if (l <= 0) return -1;
+
     count -= l;
     buf += l;
     ret += l;
   }
+
   return ret;
 }
 
@@ -44,157 +58,188 @@ typedef struct {
   int sock;
   int samples_per_subframe;
   uint64_t timestamp;
-  uint64_t next_tx_timestamp;
   int is_enb;
+  char *ip;
 } tcp_bridge_state_t;
 
-void verify_connection(int fd, int is_enb)
-{
+void verify_connection(int fd, int is_enb) {
   char c = is_enb;
+
   if (fullwrite(fd, &c, 1) != 1) exit(1);
+
   if (fullread(fd, &c, 1) != 1) exit(1);
+
   if (c == is_enb) {
-    printf("\x1b[31mtcp_bridge: error: you have to run one UE and one eNB"
-           " (did you run 'export ENODEB=1' in the eNB terminal?)\x1b[m\n");
+    printf(helpTxt);
     exit(1);
   }
 }
 
-int tcp_bridge_start(openair0_device *device)
-{
-  int port = 4043;
-  tcp_bridge_state_t *tcp_bridge = device->priv;
-  int try;
-  int max_try = 5;
-
-  int sock = socket(AF_INET, SOCK_STREAM, 0);
-  if (sock == -1) { perror("tcp_bridge: socket"); exit(1); }
-
-  int enable = 1;
-  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)))
-    { perror("tcp_bridge: SO_REUSEADDR"); exit(1); }
 
+int start_enb(tcp_bridge_state_t *tcp_bridge) {
   struct sockaddr_in addr = {
-    sin_family: AF_INET,
-    sin_port: htons(port),
-    sin_addr: { s_addr: INADDR_ANY }
+sin_family:
+    AF_INET,
+sin_port:
+    htons(port),
+sin_addr:
+    { s_addr: INADDR_ANY }
   };
 
-  if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
-    if (errno == EADDRINUSE) goto client_mode;
-    { perror("tcp_bridge: bind"); exit(1); }
+  if (bind(tcp_bridge->sock, (struct sockaddr *)&addr, sizeof(addr))) {
+    perror("tcp_bridge: bind");
+    exit(1);
   }
 
-  if (listen(sock, 5))
-    { perror("tcp_bridge: listen"); exit(1); }
+  if (listen(tcp_bridge->sock, 5)) {
+    perror("tcp_bridge: listen");
+    exit(1);
+  }
 
   printf("tcp_bridge: wait for connection on port %d\n", port);
-
   socklen_t len = sizeof(addr);
-  int sock2 = accept(sock, (struct sockaddr *)&addr, &len);
-  if (sock2 == -1)
-    { perror("tcp_bridge: accept"); exit(1); }
+  int sockServ = accept(tcp_bridge->sock, (struct sockaddr *)&addr, &len);
 
-  close(sock);
-
-  tcp_bridge->sock = sock2;
+  if ( sockServ == -1) {
+    perror("tcp_bridge: accept");
+    exit(1);
+  }
 
+  verify_connection(sockServ, tcp_bridge->is_enb);
   printf("tcp_bridge: connection established\n");
-
-  verify_connection(sock2, tcp_bridge->is_enb);
-
+  close(tcp_bridge->sock);
+  tcp_bridge->sock=sockServ;
   return 0;
+}
 
-client_mode:
-  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-
-  for (try = 0; try < max_try; try++) {
-    if (try != 0) sleep(1);
+int start_ue(tcp_bridge_state_t *tcp_bridge) {
+struct sockaddr_in addr = {sin_family:
+    AF_INET,
+sin_port:
+    htons(port),
+sin_addr:
+    { s_addr: INADDR_ANY }
+  };
+  addr.sin_addr.s_addr = inet_addr(tcp_bridge->ip);
 
-    printf("tcp_bridge: trying to connect to 127.0.0.1:%d (attempt %d/%d)\n",
-           port, try+1, max_try);
+  while(1) {
+    printf("tcp_bridge: trying to connect to %s:%d\n", tcp_bridge->ip, port);
 
-    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
+    if (connect(tcp_bridge->sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
+      verify_connection(tcp_bridge->sock, tcp_bridge->is_enb);
       printf("tcp_bridge: connection established\n");
-      tcp_bridge->sock = sock;
-      verify_connection(sock, tcp_bridge->is_enb);
       return 0;
     }
 
     perror("tcp_bridge");
+    sleep(1);
   }
 
-  printf("tcp_bridge: connection failed\n");
+  return 0;
+}
 
-  exit(1);
+int tcp_bridge_start(openair0_device *device) {
+  tcp_bridge_state_t *tcp_bridge = device->priv;
+  tcp_bridge->sock = socket(AF_INET, SOCK_STREAM, 0);
+
+  if (tcp_bridge->sock == -1) {
+    perror("tcp_bridge: socket");
+    exit(1);
+  }
+
+  int enable = 1;
+
+  if (setsockopt(tcp_bridge->sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int))) {
+    perror("tcp_bridge: SO_REUSEADDR");
+    exit(1);
+  }
+
+  if ( tcp_bridge->is_enb )
+    return start_enb(tcp_bridge);
+  else
+    return start_ue(tcp_bridge);
 }
 
-int tcp_bridge_request(openair0_device *device, void *msg, ssize_t msg_len) { abort(); return 0; }
-int tcp_bridge_reply(openair0_device *device, void *msg, ssize_t msg_len) { abort(); return 0; }
-int tcp_bridge_get_stats(openair0_device* device) { return 0; }
-int tcp_bridge_reset_stats(openair0_device* device) { return 0; }
+int tcp_bridge_request(openair0_device *device, void *msg, ssize_t msg_len) {
+  abort();
+  return 0;
+}
+int tcp_bridge_reply(openair0_device *device, void *msg, ssize_t msg_len) {
+  abort();
+  return 0;
+}
+int tcp_bridge_get_stats(openair0_device *device) {
+  return 0;
+}
+int tcp_bridge_reset_stats(openair0_device *device) {
+  return 0;
+}
 void tcp_bridge_end(openair0_device *device) {}
-int tcp_bridge_stop(openair0_device *device) { return 0; }
-int tcp_bridge_set_freq(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config) { return 0; }
-int tcp_bridge_set_gains(openair0_device* device, openair0_config_t *openair0_cfg) { return 0; }
+int tcp_bridge_stop(openair0_device *device) {
+  return 0;
+}
+int tcp_bridge_set_freq(openair0_device *device, openair0_config_t *openair0_cfg,int exmimo_dump_config) {
+  return 0;
+}
+int tcp_bridge_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) {
+  return 0;
+}
 
-int tcp_bridge_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags)
-{
-  if (cc != 1) { printf("tcp_bridge: only 1 antenna supported\n"); exit(1); }
-  tcp_bridge_state_t *t = device->priv;
-  /* deal with discontinuities in output (think: eNB in TDD mode) */
-  if (t->next_tx_timestamp && timestamp != t->next_tx_timestamp) {
-    uint32_t b[4096];
-    uint64_t to_send = timestamp - t->next_tx_timestamp;
-    memset(b, 0, 4096 * sizeof(uint32_t));
-    while (to_send) {
-      int len = to_send > 4096 ? 4096 : to_send;
-      int n = fullwrite(t->sock, b, len * 4);
-      if (n != len * 4) {
-        printf("tcp_bridge: write error ret %d error %s\n", n, strerror(errno));
-        abort();
-      }
-      to_send -= len;
-    }
+int tcp_bridge_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags) {
+  if (cc != 1) {
+    printf("tcp_bridge: only 1 antenna supported\n");
+    exit(1);
   }
+
+  tcp_bridge_state_t *t = device->priv;
   int n = fullwrite(t->sock, buff[0], nsamps * 4);
+
   if (n != nsamps * 4) {
     printf("tcp_bridge: write error ret %d (wanted %d) error %s\n", n, nsamps*4, strerror(errno));
     abort();
   }
-  t->next_tx_timestamp = timestamp + nsamps;
+
   return nsamps;
 }
 
-int tcp_bridge_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc)
-{
-  if (cc != 1) { printf("tcp_bridge: only 1 antenna supported\n"); exit(1); }
+int tcp_bridge_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
+  if (cc != 1) {
+    printf("tcp_bridge: only 1 antenna supported\n");
+    exit(1);
+  }
+
   tcp_bridge_state_t *t = device->priv;
   int n = fullread(t->sock, buff[0], nsamps * 4);
+
   if (n != nsamps * 4) {
     printf("tcp_bridge: read error ret %d nsamps*4 %d error %s\n", n, nsamps * 4, strerror(errno));
     abort();
   }
+
   *timestamp = t->timestamp;
   t->timestamp += nsamps;
   return nsamps;
 }
 
-int tcp_bridge_read_ue(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc)
-{
-  if (cc != 1) { printf("tcp_bridge: only 1 antenna supported\n"); exit(1); }
+int tcp_bridge_read_ue(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
+  if (cc != 1) {
+    printf("tcp_bridge: only 1 antenna supported\n");
+    exit(1);
+  }
+
   tcp_bridge_state_t *t = device->priv;
   int n;
 
   /* In synch mode, UE does not write, but we need to
-   * send something to the eNodeB.
-   * We know that UE is in synch mode when it reads
-   * 10 subframes at a time.
-   */
+     send something to the eNodeB.
+     We know that UE is in synch mode when it reads
+     10 subframes at a time.
+  */
   if (nsamps == t->samples_per_subframe * 10) {
     uint32_t b[nsamps];
     memset(b, 0, nsamps * 4);
     n = fullwrite(t->sock, b, nsamps * 4);
+
     if (n != nsamps * 4) {
       printf("tcp_bridge: write error ret %d error %s\n", n, strerror(errno));
       abort();
@@ -205,96 +250,106 @@ int tcp_bridge_read_ue(openair0_device *device, openair0_timestamp *timestamp, v
 }
 
 /* To startup proper communcation between eNB and UE,
- * we need to understand that:
- * - eNodeB starts reading subframe 0
- * - then eNodeB starts sending subframe 4
- * and then repeats read/write for each subframe.
- * The UE:
- * - reads 10 subframes at a time until it is synchronized
- * - then reads subframe n and writes subframe n+2
- * We also want to enforce that the subframe 0 is read
- * at the beginning of the UE RX buffer, not in the middle
- * of it.
- * So it means:
- * - for the eNodeB: let it run as in normal mode (as with a B210)
- * - for the UE, on its very first read:
- *   - we want this read to get data from subframe 0
- *     but the first write of eNodeB is subframe 4
- *     so we first need to read and ignore 6 subframes
- *   - the UE will start its TX only at the subframe 2
- *     corresponding to the subframe 0 it just read,
- *     so we need to write 12 subframes before anything
- *     (the function tcp_bridge_read_ue takes care to
- *     insert dummy TX data during the synch phase)
- *
- * Here is a drawing of the beginning of things to make
- * this logic clearer.
- *
- * We see that eNB starts RX at subframe 0, starts TX at subfram 4,
- * and that UE starts RX at subframe 10 and TX at subframe 12.
- *
- * We understand that the UE has to transmit 12 empty
- * subframes for the eNodeB to start its processing.
- *
- * And because the eNodeB starts its TX at subframe 4 and we
- * want the UE to start its RX at subframe 10, we need to
- * read and ignore 6 subframes in the UE.
- *
- *          -------------------------------------------------------------------------
- * eNB RX:  | *0* | 1 | 2 | 3 |  4  | 5 | 6 | 7 | 8 | 9 |  10  | 11 |  12  | 13 | 14 ...
- *          -------------------------------------------------------------------------
- *
- *          -------------------------------------------------------------------------
- * eNB TX:  |  0  | 1 | 2 | 3 | *4* | 5 | 6 | 7 | 8 | 9 |  10  | 11 |  12  | 13 | 14 ...
- *          -------------------------------------------------------------------------
- *
- *          -------------------------------------------------------------------------
- * UE RX:   |  0  | 1 | 2 | 3 |  4  | 5 | 6 | 7 | 8 | 9 | *10* | 11 |  12  | 13 | 14 ...
- *          -------------------------------------------------------------------------
- *
- *          -------------------------------------------------------------------------
- * UE TX:   |  0  | 1 | 2 | 3 |  4  | 5 | 6 | 7 | 8 | 9 |  10  | 11 | *12* | 13 | 14 ...
- *          -------------------------------------------------------------------------
- *
- * As a final note, we do TX before RX to ensure that the eNB will
- * get some data and send us something so there is no deadlock
- * at the beginning of things. Hopefully the kernel buffers for
- * the sockets are big enough so that the first (big) TX can
- * return to user mode before the buffers are full. If this
- * is wrong in some environment, we will need to work by smaller
- * units of data at a time.
- */
-int tcp_bridge_ue_first_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc)
-{
-  if (cc != 1) { printf("tcp_bridge: only 1 antenna supported\n"); exit(1); }
-  tcp_bridge_state_t *t = device->priv;
+   we need to understand that:
+   - eNodeB starts reading subframe 0
+   - then eNodeB starts sending subframe 4
+   and then repeats read/write for each subframe.
+   The UE:
+   - reads 10 subframes at a time until it is synchronized
+   - then reads subframe n and writes subframe n+2
+   We also want to enforce that the subframe 0 is read
+   at the beginning of the UE RX buffer, not in the middle
+   of it.
+   So it means:
+   - for the eNodeB: let it run as in normal mode (as with a B210)
+   - for the UE, on its very first read:
+     - we want this read to get data from subframe 0
+       but the first write of eNodeB is subframe 4
+       so we first need to read and ignore 6 subframes
+     - the UE will start its TX only at the subframe 2
+       corresponding to the subframe 0 it just read,
+       so we need to write 12 subframes before anything
+       (the function tcp_bridge_read_ue takes care to
+       insert dummy TX data during the synch phase)
+
+   Here is a drawing of the beginning of things to make
+   this logic clearer.
+
+   We see that eNB starts RX at subframe 0, starts TX at subfram 4,
+   and that UE starts RX at subframe 10 and TX at subframe 12.
+
+   We understand that the UE has to transmit 12 empty
+   subframes for the eNodeB to start its processing.
+
+   And because the eNodeB starts its TX at subframe 4 and we
+   want the UE to start its RX at subframe 10, we need to
+   read and ignore 6 subframes in the UE.
+
+            -------------------------------------------------------------------------
+   eNB RX:  | *0* | 1 | 2 | 3 |  4  | 5 | 6 | 7 | 8 | 9 |  10  | 11 |  12  | 13 | 14 ...
+            -------------------------------------------------------------------------
+
+            -------------------------------------------------------------------------
+   eNB TX:  |  0  | 1 | 2 | 3 | *4* | 5 | 6 | 7 | 8 | 9 |  10  | 11 |  12  | 13 | 14 ...
+            -------------------------------------------------------------------------
+
+            -------------------------------------------------------------------------
+   UE RX:   |  0  | 1 | 2 | 3 |  4  | 5 | 6 | 7 | 8 | 9 | *10* | 11 |  12  | 13 | 14 ...
+            -------------------------------------------------------------------------
+
+            -------------------------------------------------------------------------
+   UE TX:   |  0  | 1 | 2 | 3 |  4  | 5 | 6 | 7 | 8 | 9 |  10  | 11 | *12* | 13 | 14 ...
+            -------------------------------------------------------------------------
+
+   As a final note, we do TX before RX to ensure that the eNB will
+   get some data and send us something so there is no deadlock
+   at the beginning of things. Hopefully the kernel buffers for
+   the sockets are big enough so that the first (big) TX can
+   return to user mode before the buffers are full. If this
+   is wrong in some environment, we will need to work by smaller
+   units of data at a time.
+*/
+int tcp_bridge_ue_first_read(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc) {
+  if (cc != 1) {
+    printf("tcp_bridge: only 1 antenna supported\n");
+    exit(1);
+  }
 
+  tcp_bridge_state_t *t = device->priv;
   uint32_t b[t->samples_per_subframe * 12];
   memset(b, 0, t->samples_per_subframe * 12 * 4);
   int n = fullwrite(t->sock, b, t->samples_per_subframe * 12 * 4);
+
   if (n != t->samples_per_subframe * 12 * 4) {
     printf("tcp_bridge: write error ret %d error %s\n", n, strerror(errno));
     abort();
   }
+
   n = fullread(t->sock, b, t->samples_per_subframe * 6 * 4);
+
   if (n != t->samples_per_subframe * 6 * 4) {
     printf("tcp_bridge: read error ret %d error %s\n", n, strerror(errno));
     abort();
   }
 
   device->trx_read_func = tcp_bridge_read_ue;
-
   return tcp_bridge_read_ue(device, timestamp, buff, nsamps, cc);
 }
 
 __attribute__((__visibility__("default")))
-int device_init(openair0_device* device, openair0_config_t *openair0_cfg)
-{
-  tcp_bridge_state_t *tcp_bridge = (tcp_bridge_state_t*)malloc(sizeof(tcp_bridge_state_t));
-  memset(tcp_bridge, 0, sizeof(tcp_bridge_state_t));
-
-  tcp_bridge->is_enb = getenv("ENODEB") != NULL;
+int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
+  tcp_bridge_state_t *tcp_bridge = (tcp_bridge_state_t *)calloc(sizeof(tcp_bridge_state_t),1);
+
+  if ((tcp_bridge->ip=getenv("TCPBRIDGE")) == NULL ) {
+    /* for compatibility, we test the ENB environment variable */
+    if ((tcp_bridge->ip=getenv("ENODEB")) != NULL ) {
+      tcp_bridge->ip=strdup("enb");
+    } else {
+      tcp_bridge->ip=strdup("127.0.0.1");
+    }
+  }
 
+  tcp_bridge->is_enb = strncasecmp(tcp_bridge->ip,"enb",3) == 0;
   printf("tcp_bridge: running as %s\n", tcp_bridge->is_enb ? "eNB" : "UE");
 
   /* only 25, 50 or 100 PRBs handled for the moment */
@@ -323,15 +378,21 @@ int device_init(openair0_device* device, openair0_config_t *openair0_cfg)
   device->priv = tcp_bridge;
 
   switch ((int)openair0_cfg[0].sample_rate) {
-  case 30720000: tcp_bridge->samples_per_subframe = 30720; break;
-  case 15360000: tcp_bridge->samples_per_subframe = 15360; break;
-  case 7680000:  tcp_bridge->samples_per_subframe = 7680; break;
+    case 30720000:
+      tcp_bridge->samples_per_subframe = 30720;
+      break;
+
+    case 15360000:
+      tcp_bridge->samples_per_subframe = 15360;
+      break;
+
+    case 7680000:
+      tcp_bridge->samples_per_subframe = 7680;
+      break;
   }
 
   /* let's pretend to be a b2x0 */
   device->type = USRP_B200_DEV;
-
   device->openair0_cfg=&openair0_cfg[0];
-
   return 0;
 }
-- 
GitLab