<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/19724">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">socket: multiaddr: Support IPv4 + IPv6 addresses in SCTP associations<br><br>The function is improved to support AF_INET:v4->v4, AF_INET6:v6->v6 and<br>AF_UNSPEC:v4+v6->v4+v6.<br>Unit tests for the function are added to make sure function behaves<br>correctly in several scenarios.<br><br>Change-Id: I36d8ab85d92bba4d6adb83bc1875eb61094ed2ef<br>---<br>M src/socket.c<br>M tests/socket/socket_test.c<br>M tests/socket/socket_test.err<br>M tests/socket/socket_test.ok<br>4 files changed, 294 insertions(+), 66 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/24/19724/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/socket.c b/src/socket.c</span><br><span>index d92c670..57ff843 100644</span><br><span>--- a/src/socket.c</span><br><span>+++ b/src/socket.c</span><br><span>@@ -79,7 +79,7 @@</span><br><span>             hints.ai_socktype = type;</span><br><span>            hints.ai_protocol = proto;</span><br><span>   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+     hints.ai_flags = AI_ADDRCONFIG;</span><br><span>      if (passive)</span><br><span>                 hints.ai_flags |= AI_PASSIVE;</span><br><span> </span><br><span>@@ -428,24 +428,62 @@</span><br><span> </span><br><span> #ifdef HAVE_LIBSCTP</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Check whether there's an IPv6 Addr as first option of any addrinfo item in the addrinfo set */</span><br><span style="color: hsl(120, 100%, 40%);">+static void addrinfo_has_v4v6addr(const struct addrinfo **result, int result_count, bool *has_v4, bool *has_v6) {</span><br><span style="color: hsl(120, 100%, 40%);">+    size_t host_idx;</span><br><span style="color: hsl(120, 100%, 40%);">+      *has_v4 = false;</span><br><span style="color: hsl(120, 100%, 40%);">+      *has_v6 = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for (host_idx = 0; host_idx < result_count; host_idx++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (result[host_idx]->ai_family == AF_INET)</span><br><span style="color: hsl(120, 100%, 40%);">+                        *has_v4 = true;</span><br><span style="color: hsl(120, 100%, 40%);">+               else if (result[host_idx]->ai_family == AF_INET6)</span><br><span style="color: hsl(120, 100%, 40%);">+                  *has_v6 = true;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int socket_helper_multiaddr(uint16_t family, uint16_t type, uint8_t proto, unsigned int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int sfd, on = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    sfd = socket(family, type, proto);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (sfd == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLGLOBAL, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "unable to create socket: %s\n", strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+          return sfd;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (flags & OSMO_SOCK_F_NONBLOCK) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (ioctl(sfd, FIONBIO, (unsigned char *)&on) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOGP(DLGLOBAL, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "cannot set this socket unblocking: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                          strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+                     close(sfd);</span><br><span style="color: hsl(120, 100%, 40%);">+                   sfd = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return sfd;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> /* Build array of addresses taking first addrinfo result of the requested family</span><br><span style="color: hsl(0, 100%, 40%);">- * for each host in hosts. addrs4 or addrs6 are filled based on family type. */</span><br><span style="color: hsl(120, 100%, 40%);">+ * for each host in addrs_buf. */</span><br><span> static int addrinfo_to_sockaddr(uint16_t family, const struct addrinfo **result,</span><br><span>                                 const char **hosts, int host_cont,</span><br><span style="color: hsl(0, 100%, 40%);">-                              struct sockaddr_in *addrs4, struct sockaddr_in6 *addrs6) {</span><br><span style="color: hsl(0, 100%, 40%);">-      size_t host_idx;</span><br><span style="color: hsl(120, 100%, 40%);">+                              uint8_t *addrs_buf, size_t addrs_buf_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+   size_t host_idx, offset = 0;</span><br><span>         const struct addrinfo *rp;</span><br><span style="color: hsl(0, 100%, 40%);">-      OSMO_ASSERT(family == AF_INET || family == AF_INET6);</span><br><span> </span><br><span>    for (host_idx = 0; host_idx < host_cont; host_idx++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Addresses are ordered based on RFC 3484, see man getaddrinfo */</span><br><span>           for (rp = result[host_idx]; rp != NULL; rp = rp->ai_next) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  if (rp->ai_family != family)</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (family != AF_UNSPEC && rp->ai_family != family)</span><br><span>                               continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (family == AF_INET)</span><br><span style="color: hsl(0, 100%, 40%);">-                          memcpy(&addrs4[host_idx], rp->ai_addr, sizeof(addrs4[host_idx]));</span><br><span style="color: hsl(0, 100%, 40%);">-                        else</span><br><span style="color: hsl(0, 100%, 40%);">-                            memcpy(&addrs6[host_idx], rp->ai_addr, sizeof(addrs6[host_idx]));</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (offset + rp->ai_addrlen > addrs_buf_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          LOGP(DLGLOBAL, LOGL_ERROR, "output buffer to small: %zu\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                              addrs_buf_len);</span><br><span style="color: hsl(120, 100%, 40%);">+                          return -ENOSPC;</span><br><span style="color: hsl(120, 100%, 40%);">+                       }</span><br><span style="color: hsl(120, 100%, 40%);">+                     memcpy(addrs_buf + offset, rp->ai_addr, rp->ai_addrlen);</span><br><span style="color: hsl(120, 100%, 40%);">+                        offset += rp->ai_addrlen;</span><br><span>                         break;</span><br><span>               }</span><br><span>            if (!rp) { /* No addr could be bound for this host! */</span><br><span>@@ -486,25 +524,20 @@</span><br><span>       struct addrinfo *res_loc[OSMO_SOCK_MAX_ADDRS], *res_rem[OSMO_SOCK_MAX_ADDRS];</span><br><span>        int sfd = -1, rc, on = 1;</span><br><span>    int i;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct sockaddr_in addrs4[OSMO_SOCK_MAX_ADDRS];</span><br><span style="color: hsl(0, 100%, 40%);">- struct sockaddr_in6 addrs6[OSMO_SOCK_MAX_ADDRS];</span><br><span style="color: hsl(0, 100%, 40%);">-        struct sockaddr *addrs;</span><br><span style="color: hsl(120, 100%, 40%);">+       bool loc_has_v4addr, rem_has_v4addr;</span><br><span style="color: hsl(120, 100%, 40%);">+  bool loc_has_v6addr, rem_has_v6addr;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct sockaddr_in6 addrs_buf[OSMO_SOCK_MAX_ADDRS];</span><br><span>  char strbuf[512];</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* updated later in case of AF_UNSPEC */</span><br><span style="color: hsl(120, 100%, 40%);">+      loc_has_v4addr = rem_has_v4addr = (family == AF_INET);</span><br><span style="color: hsl(120, 100%, 40%);">+        loc_has_v6addr = rem_has_v6addr = (family == AF_INET6);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    /* TODO: So far this function is only aimed for SCTP, but could be</span><br><span>      reused in the future for other protocols with multi-addr support */</span><br><span>       if (proto != IPPROTO_SCTP)</span><br><span>           return -ENOTSUP;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    /* TODO: Let's not support AF_UNSPEC for now. sctp_bindx() actually</span><br><span style="color: hsl(0, 100%, 40%);">-    supports binding both types of addresses on a AF_INET6 soscket, but</span><br><span style="color: hsl(0, 100%, 40%);">-     that would mean we could get both AF_INET and AF_INET6 addresses for</span><br><span style="color: hsl(0, 100%, 40%);">-    each host, and makes complexity of this function increase a lot since</span><br><span style="color: hsl(0, 100%, 40%);">-           we'd need to find out which subsets to use, use v4v6 mapped socket,</span><br><span style="color: hsl(0, 100%, 40%);">-         etc. */</span><br><span style="color: hsl(0, 100%, 40%);">-      if (family == AF_UNSPEC)</span><br><span style="color: hsl(0, 100%, 40%);">-                return -ENOTSUP;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>     if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) == 0) {</span><br><span>           LOGP(DLGLOBAL, LOGL_ERROR, "invalid: you have to specify either "</span><br><span>                  "BIND or CONNECT flags\n");</span><br><span>@@ -523,6 +556,10 @@</span><br><span>                                                local_hosts_cnt, local_port, true);</span><br><span>           if (rc < 0)</span><br><span>                       return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Figure out if there's any IPV4 or IPv6 addr in the set */</span><br><span style="color: hsl(120, 100%, 40%);">+              if (family == AF_UNSPEC)</span><br><span style="color: hsl(120, 100%, 40%);">+                      addrinfo_has_v4v6addr((const struct addrinfo **)res_loc, local_hosts_cnt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           &loc_has_v4addr, &loc_has_v6addr);</span><br><span>     }</span><br><span>    /* figure out remote side of socket */</span><br><span>       if (flags & OSMO_SOCK_F_CONNECT) {</span><br><span>@@ -530,22 +567,27 @@</span><br><span>                                              remote_hosts_cnt, remote_port, false);</span><br><span>                if (rc < 0)</span><br><span>                       return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Figure out if there's any IPv4 or IPv6  addr in the set */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (family == AF_UNSPEC)</span><br><span style="color: hsl(120, 100%, 40%);">+                      addrinfo_has_v4v6addr((const struct addrinfo **)res_rem, remote_hosts_cnt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          &rem_has_v4addr, &rem_has_v6addr);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* figure out local side of socket */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (((flags & OSMO_SOCK_F_BIND) && (flags & OSMO_SOCK_F_CONNECT)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+      (loc_has_v4addr != rem_has_v4addr || loc_has_v6addr != rem_has_v6addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DLGLOBAL, LOGL_ERROR, "invalid v4 vs v6 in local vs remote addresses\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+         goto ret_freeaddrinfo;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   sfd = socket_helper_multiaddr(loc_has_v6addr ? AF_INET6 : AF_INET,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  type, proto, flags);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (sfd < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = sfd;</span><br><span style="color: hsl(120, 100%, 40%);">+             goto ret_freeaddrinfo;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  if (flags & OSMO_SOCK_F_BIND) {</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             /* Since addrinfo_helper sets ai_family, socktype and</span><br><span style="color: hsl(0, 100%, 40%);">-              ai_protocol in hints, we know all results will use same</span><br><span style="color: hsl(0, 100%, 40%);">-                 values, so simply pick the first one and pass it to create</span><br><span style="color: hsl(0, 100%, 40%);">-              the socket:</span><br><span style="color: hsl(0, 100%, 40%);">-          */</span><br><span style="color: hsl(0, 100%, 40%);">-              sfd = socket_helper(res_loc[0], flags);</span><br><span style="color: hsl(0, 100%, 40%);">-         if (sfd < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       rc = sfd;</span><br><span style="color: hsl(0, 100%, 40%);">-                       goto ret_freeaddrinfo;</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>            /* Since so far we only allow IPPROTO_SCTP in this function,</span><br><span>                    no need to check below for "proto != IPPROTO_UDP || flags & OSMO_SOCK_F_UDP_REUSEADDR" */</span><br><span>           rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,</span><br><span>@@ -560,21 +602,20 @@</span><br><span>                       goto ret_close;</span><br><span>              }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           /* Build array of addresses taking first of same family for each host.</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Build array of addresses taking first entry for each host.</span><br><span>                   TODO: Ideally we should use backtracking storing last used</span><br><span>                   indexes and trying next combination if connect() fails .*/</span><br><span style="color: hsl(120, 100%, 40%);">+         /* We could alternatively use v4v6 mapped addresses and call sctp_bindx once with an array od sockaddr_in6 */</span><br><span>                rc = addrinfo_to_sockaddr(family, (const struct addrinfo **)res_loc,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      local_hosts, local_hosts_cnt, addrs4, addrs6);</span><br><span style="color: hsl(120, 100%, 40%);">+                                        local_hosts, local_hosts_cnt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         (uint8_t*)addrs_buf, sizeof(addrs_buf));</span><br><span>           if (rc < 0) {</span><br><span>                     rc = -ENODEV;</span><br><span>                        goto ret_close;</span><br><span>              }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           if (family == AF_INET)</span><br><span style="color: hsl(0, 100%, 40%);">-                  addrs = (struct sockaddr *)addrs4;</span><br><span style="color: hsl(0, 100%, 40%);">-              else</span><br><span style="color: hsl(0, 100%, 40%);">-                    addrs = (struct sockaddr *)addrs6;</span><br><span style="color: hsl(0, 100%, 40%);">-              if (sctp_bindx(sfd, addrs, local_hosts_cnt, SCTP_BINDX_ADD_ADDR) == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = sctp_bindx(sfd, (struct sockaddr *)addrs_buf, local_hosts_cnt, SCTP_BINDX_ADD_ADDR);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc == -1) {</span><br><span>                      multiaddr_snprintf(strbuf, sizeof(strbuf), local_hosts, local_hosts_cnt);</span><br><span>                    LOGP(DLGLOBAL, LOGL_NOTICE, "unable to bind socket: %s:%u: %s\n",</span><br><span>                       strbuf, local_port, strerror(errno));</span><br><span>@@ -583,40 +624,19 @@</span><br><span>           }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Reached this point, if OSMO_SOCK_F_BIND then sfd is valid (>=0) or it</span><br><span style="color: hsl(0, 100%, 40%);">-        was already closed and func returned. If OSMO_SOCK_F_BIND is not</span><br><span style="color: hsl(0, 100%, 40%);">-        set, then sfd = -1 */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        /* figure out remote side of socket */</span><br><span>       if (flags & OSMO_SOCK_F_CONNECT) {</span><br><span style="color: hsl(0, 100%, 40%);">-          if (sfd < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       /* Since addrinfo_helper sets ai_family, socktype and</span><br><span style="color: hsl(0, 100%, 40%);">-                      ai_protocol in hints, we know all results will use same</span><br><span style="color: hsl(0, 100%, 40%);">-                         values, so simply pick the first one and pass it to create</span><br><span style="color: hsl(0, 100%, 40%);">-                      the socket:</span><br><span style="color: hsl(0, 100%, 40%);">-                  */</span><br><span style="color: hsl(0, 100%, 40%);">-                      sfd = socket_helper(res_rem[0], flags);</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (sfd < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                               rc = sfd;</span><br><span style="color: hsl(0, 100%, 40%);">-                               goto ret_freeaddrinfo;</span><br><span style="color: hsl(0, 100%, 40%);">-                  }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>            /* Build array of addresses taking first of same family for each host.</span><br><span>                  TODO: Ideally we should use backtracking storing last used</span><br><span>                   indexes and trying next combination if connect() fails .*/</span><br><span>                rc = addrinfo_to_sockaddr(family, (const struct addrinfo **)res_rem,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      remote_hosts, remote_hosts_cnt, addrs4, addrs6);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      remote_hosts, remote_hosts_cnt,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       (uint8_t*)addrs_buf, sizeof(addrs_buf));</span><br><span>           if (rc < 0) {</span><br><span>                     rc = -ENODEV;</span><br><span>                        goto ret_close;</span><br><span>              }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           if (family == AF_INET)</span><br><span style="color: hsl(0, 100%, 40%);">-                  addrs = (struct sockaddr *)addrs4;</span><br><span style="color: hsl(0, 100%, 40%);">-              else</span><br><span style="color: hsl(0, 100%, 40%);">-                    addrs = (struct sockaddr *)addrs6;</span><br><span style="color: hsl(0, 100%, 40%);">-              rc = sctp_connectx(sfd, addrs, remote_hosts_cnt, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = sctp_connectx(sfd, (struct sockaddr *)addrs_buf, remote_hosts_cnt, NULL);</span><br><span>               if (rc != 0 && errno != EINPROGRESS) {</span><br><span>                       multiaddr_snprintf(strbuf, sizeof(strbuf), remote_hosts, remote_hosts_cnt);</span><br><span>                  LOGP(DLGLOBAL, LOGL_ERROR, "unable to connect socket: %s:%u: %s\n",</span><br><span>diff --git a/tests/socket/socket_test.c b/tests/socket/socket_test.c</span><br><span>index e68243c..1d4253c 100644</span><br><span>--- a/tests/socket/socket_test.c</span><br><span>+++ b/tests/socket/socket_test.c</span><br><span>@@ -23,6 +23,7 @@</span><br><span> #include <unistd.h></span><br><span> #include <string.h></span><br><span> #include <fcntl.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span> </span><br><span> #include <sys/socket.h></span><br><span> #include <arpa/inet.h></span><br><span>@@ -32,6 +33,7 @@</span><br><span> #include <osmocom/core/utils.h></span><br><span> #include <osmocom/core/socket.h></span><br><span> #include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bits.h></span><br><span> </span><br><span> #include "../config.h"</span><br><span> </span><br><span>@@ -146,6 +148,175 @@</span><br><span>   return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_LIBSCTP</span><br><span style="color: hsl(120, 100%, 40%);">+static uint16_t sock_get_local_port(int fd, bool is_v6) {</span><br><span style="color: hsl(120, 100%, 40%);">+    struct sockaddr_storage sa;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct sockaddr_in *sin = (struct sockaddr_in *)&sa;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;</span><br><span style="color: hsl(120, 100%, 40%);">+   socklen_t len = sizeof(sa);</span><br><span style="color: hsl(120, 100%, 40%);">+   int local_port;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(getsockname(fd, (struct sockaddr*)&sa, &len) == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       if(!is_v6)</span><br><span style="color: hsl(120, 100%, 40%);">+            local_port = osmo_load16be(&sin->sin_port);</span><br><span style="color: hsl(120, 100%, 40%);">+    else</span><br><span style="color: hsl(120, 100%, 40%);">+          local_port = osmo_load16be(&sin6->sin6_port);</span><br><span style="color: hsl(120, 100%, 40%);">+  //printf("Checking osmo_sock_init2_multiaddr() port: %" PRIu16 "\n", listen_port_v4);</span><br><span style="color: hsl(120, 100%, 40%);">+     return local_port;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Test API osmo_sock_init2_multiaddr with 1 local/remote address */</span><br><span style="color: hsl(120, 100%, 40%);">+static int test_sockinit2_multiaddr(const char **addrv4_loc, const char **addrv6_loc,</span><br><span style="color: hsl(120, 100%, 40%);">+                              const char **addrv4_rem, const char **addrv6_rem,</span><br><span style="color: hsl(120, 100%, 40%);">+                             size_t addrv4_size, size_t addrv6_size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int fd, rc;</span><br><span style="color: hsl(120, 100%, 40%);">+   int listen_fd_v4, listen_fd_v6;</span><br><span style="color: hsl(120, 100%, 40%);">+       int listen_port_v4, listen_port_v6;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("Checking osmo_sock_init2_multiaddr() with bind to a random local SCTP IPv4 port\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      listen_fd_v4 = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 addrv4_loc, addrv4_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   NULL, 0, 0, OSMO_SOCK_F_BIND);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(listen_fd_v4 >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* expect it to be blocking */</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = fcntl(listen_fd_v4, F_GETFL);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!(rc & O_NONBLOCK));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        listen_port_v4 = sock_get_local_port(listen_fd_v4, false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("Checking osmo_sock_init2_multiaddr() with bind to a random local SCTP IPv6 port\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      listen_fd_v6 = osmo_sock_init2_multiaddr(AF_INET6, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                addrv6_loc, addrv6_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   NULL, 0, 0, OSMO_SOCK_F_BIND);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(listen_fd_v6 >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    /* expect it to be blocking */</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = fcntl(listen_fd_v6, F_GETFL);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(!(rc & O_NONBLOCK));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        listen_port_v6 = sock_get_local_port(listen_fd_v6, true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   printf("Checking osmo_sock_init2_multiaddr() for OSMO_SOCK_F_NONBLOCK\n");</span><br><span style="color: hsl(120, 100%, 40%);">+  fd = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   addrv4_loc, addrv4_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   NULL, 0, 0, OSMO_SOCK_F_BIND|OSMO_SOCK_F_NONBLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(fd >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      /* expect it to be blocking */</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = fcntl(fd, F_GETFL);</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(rc & O_NONBLOCK);</span><br><span style="color: hsl(120, 100%, 40%);">+     close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("Checking osmo_sock_init2_multiaddr() for invalid flags\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ fd = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   addrv4_loc, addrv4_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   NULL, 0, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(fd < 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("Checking osmo_sock_init2_multiaddr() for combined BIND + CONNECT\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       fd = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   addrv4_rem, addrv4_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   addrv4_rem, addrv4_size, listen_port_v4,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(fd >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) must fail on mixed IPv4 & IPv6\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 addrv4_rem, addrv4_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   addrv6_rem, addrv6_size, listen_port_v6,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(fd < 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) must fail on mixed IPv6 & IPv4\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 addrv6_rem, addrv6_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   addrv4_rem, addrv4_size, listen_port_v4,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(fd < 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv4\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 addrv4_rem, addrv4_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   addrv4_rem, addrv4_size, listen_port_v4,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(fd >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv6\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 addrv6_rem, addrv6_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   addrv6_rem, addrv6_size, listen_port_v6,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(fd >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    close(listen_fd_v4);</span><br><span style="color: hsl(120, 100%, 40%);">+  close(listen_fd_v6);</span><br><span style="color: hsl(120, 100%, 40%);">+  printf("Done\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Test API osmo_sock_init2_multiaddr with 1 local/remote address */</span><br><span style="color: hsl(120, 100%, 40%);">+static int test_sockinit2_multiaddr_simple(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *addrv4_loc[] = { "0.0.0.0" };</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *addrv6_loc[] = { "::" };</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *addrv4_rem[] = { "127.0.0.1" };</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *addrv6_rem[] = { "::1" };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return test_sockinit2_multiaddr(addrv4_loc, addrv6_loc,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       addrv4_rem, addrv6_rem, 1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Test API osmo_sock_init2_multiaddr with several local/remote address */</span><br><span style="color: hsl(120, 100%, 40%);">+static int test_sockinit2_multiaddr_several(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *addrv4_localhost[] = { "127.0.0.1", "127.0.0.2" };</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *addrv6_localhost[] = { "::1" };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return test_sockinit2_multiaddr(addrv4_localhost, addrv6_localhost,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   addrv4_localhost, addrv6_localhost, 2, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Test API osmo_sock_init2_multiaddr with several local/remote address, using both ipv4+v6 */</span><br><span style="color: hsl(120, 100%, 40%);">+static int test_sockinit2_multiaddr_mixed(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *addr_localhost[] = { "127.0.0.1", "127.0.0.2", "::1" };</span><br><span style="color: hsl(120, 100%, 40%);">+     size_t addr_size = ARRAY_SIZE(addr_localhost);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      int listen_fd, listen_port, fd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_INET IPv4+v6 fails\n");</span><br><span style="color: hsl(120, 100%, 40%);">+    listen_fd = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    addr_localhost, addr_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 NULL, 0, 0, OSMO_SOCK_F_BIND);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(listen_fd < 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_INET6 IPv4+v6 fails\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   listen_fd = osmo_sock_init2_multiaddr(AF_INET6, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   addr_localhost, addr_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 NULL, 0, 0, OSMO_SOCK_F_BIND);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(listen_fd < 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_UNSPEC IPv4+v6 succeeds\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       listen_fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  addr_localhost, addr_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 NULL, 0, 0, OSMO_SOCK_F_BIND);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(listen_fd >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     listen_port = sock_get_local_port(listen_fd, true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv4\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 addr_localhost, addr_size, 0,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 addr_localhost, addr_size, listen_port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(fd >= 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  close(listen_fd);</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* ifdef HAVE_LIBSCTP */</span><br><span> </span><br><span> const struct log_info_cat default_categories[] = {</span><br><span> };</span><br><span>@@ -164,6 +335,11 @@</span><br><span> </span><br><span>     test_sockinit();</span><br><span>     test_sockinit2();</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_LIBSCTP</span><br><span style="color: hsl(120, 100%, 40%);">+        test_sockinit2_multiaddr_simple();</span><br><span style="color: hsl(120, 100%, 40%);">+    test_sockinit2_multiaddr_several();</span><br><span style="color: hsl(120, 100%, 40%);">+   test_sockinit2_multiaddr_mixed();</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* ifdef HAVE_LIBSCTP */</span><br><span> </span><br><span>       return EXIT_SUCCESS;</span><br><span> }</span><br><span>diff --git a/tests/socket/socket_test.err b/tests/socket/socket_test.err</span><br><span>index 0f0f8da..a240196 100644</span><br><span>--- a/tests/socket/socket_test.err</span><br><span>+++ b/tests/socket/socket_test.err</span><br><span>@@ -2,3 +2,11 @@</span><br><span> invalid: you have to specify either BIND or CONNECT flags</span><br><span> Unable to find a common protocol (IPv4 or IPv6) for local host: 127.0.0.1 and remote host: ::1.</span><br><span> Unable to find a common protocol (IPv4 or IPv6) for local host: ::1 and remote host: 127.0.0.1.</span><br><span style="color: hsl(120, 100%, 40%);">+invalid: you have to specify either BIND or CONNECT flags</span><br><span style="color: hsl(120, 100%, 40%);">+invalid v4 vs v6 in local vs remote addresses</span><br><span style="color: hsl(120, 100%, 40%);">+invalid v4 vs v6 in local vs remote addresses</span><br><span style="color: hsl(120, 100%, 40%);">+invalid: you have to specify either BIND or CONNECT flags</span><br><span style="color: hsl(120, 100%, 40%);">+invalid v4 vs v6 in local vs remote addresses</span><br><span style="color: hsl(120, 100%, 40%);">+invalid v4 vs v6 in local vs remote addresses</span><br><span style="color: hsl(120, 100%, 40%);">+getaddrinfo returned NULL: ::1:0: Transport endpoint is not connected</span><br><span style="color: hsl(120, 100%, 40%);">+getaddrinfo returned NULL: 127.0.0.1:0: Transport endpoint is not connected</span><br><span>diff --git a/tests/socket/socket_test.ok b/tests/socket/socket_test.ok</span><br><span>index 4265be8..959fa84 100644</span><br><span>--- a/tests/socket/socket_test.ok</span><br><span>+++ b/tests/socket/socket_test.ok</span><br><span>@@ -9,3 +9,27 @@</span><br><span> Checking osmo_sock_init2(AF_UNSPEC) must fail on mixed IPv6 & IPv4</span><br><span> Checking osmo_sock_init2(AF_UNSPEC) BIND + CONNECT on IPv4</span><br><span> Checking osmo_sock_init2(AF_UNSPEC) BIND + CONNECT on IPv6</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr() with bind to a random local SCTP IPv4 port</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr() with bind to a random local SCTP IPv6 port</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr() for OSMO_SOCK_F_NONBLOCK</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr() for invalid flags</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr() for combined BIND + CONNECT</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) must fail on mixed IPv4 & IPv6</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) must fail on mixed IPv6 & IPv4</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv4</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv6</span><br><span style="color: hsl(120, 100%, 40%);">+Done</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr() with bind to a random local SCTP IPv4 port</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr() with bind to a random local SCTP IPv6 port</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr() for OSMO_SOCK_F_NONBLOCK</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr() for invalid flags</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr() for combined BIND + CONNECT</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) must fail on mixed IPv4 & IPv6</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) must fail on mixed IPv6 & IPv4</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv4</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv6</span><br><span style="color: hsl(120, 100%, 40%);">+Done</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_INET IPv4+v6 fails</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_INET6 IPv4+v6 fails</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_UNSPEC IPv4+v6 succeeds</span><br><span style="color: hsl(120, 100%, 40%);">+Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv4</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/19724">change 19724</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/libosmocore/+/19724"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I36d8ab85d92bba4d6adb83bc1875eb61094ed2ef </div>
<div style="display:none"> Gerrit-Change-Number: 19724 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>