<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/15781">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">socket: Introduce API osmo_sock_init2_multiaddr()<br><br>This API will be used by libosmo-netif's osmo_stream for SCTP sockets,<br>which in turn will be used by libosmo-sccp to support multi-homed<br>connections.<br><br>Related: OS#3608<br>Change-Id: Ic8681d9e093216c99c6bca4be81c31ef83688ed1<br>---<br>M configure.ac<br>M debian/control<br>M include/osmocom/core/socket.h<br>M src/Makefile.am<br>M src/socket.c<br>5 files changed, 307 insertions(+), 2 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configure.ac b/configure.ac</span><br><span>index 39d232b..2f12d86 100644</span><br><span>--- a/configure.ac</span><br><span>+++ b/configure.ac</span><br><span>@@ -100,6 +100,17 @@</span><br><span> </span><br><span> AC_CHECK_FUNCS(clock_gettime localtime_r)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+old_LIBS=$LIBS</span><br><span style="color: hsl(120, 100%, 40%);">+AC_SEARCH_LIBS([sctp_bindx], [sctp], [</span><br><span style="color: hsl(120, 100%, 40%);">+   AC_DEFINE(HAVE_LIBSCTP, 1, [Define 1 to enable SCTP support])</span><br><span style="color: hsl(120, 100%, 40%);">+ AC_SUBST(HAVE_LIBSCTP, [1])</span><br><span style="color: hsl(120, 100%, 40%);">+   if test -n "$ac_lib"; then</span><br><span style="color: hsl(120, 100%, 40%);">+          AC_SUBST(LIBSCTP_LIBS, [-l$ac_lib])</span><br><span style="color: hsl(120, 100%, 40%);">+   fi</span><br><span style="color: hsl(120, 100%, 40%);">+    ], [</span><br><span style="color: hsl(120, 100%, 40%);">+  AC_MSG_WARN([sctp_bindx not found in searched libs])])</span><br><span style="color: hsl(120, 100%, 40%);">+LIBS=$old_LIBS</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> AC_DEFUN([CHECK_TM_INCLUDES_TM_GMTOFF], [</span><br><span>   AC_CACHE_CHECK(</span><br><span>     [whether struct tm has tm_gmtoff member],</span><br><span>diff --git a/debian/control b/debian/control</span><br><span>index 07163da..6c9cfae 100644</span><br><span>--- a/debian/control</span><br><span>+++ b/debian/control</span><br><span>@@ -15,6 +15,7 @@</span><br><span>                libpcsclite-dev,</span><br><span>                pkg-config,</span><br><span>                libtalloc-dev,</span><br><span style="color: hsl(120, 100%, 40%);">+               libsctp-dev,</span><br><span>                python (>= 2.7.6)</span><br><span> Standards-Version: 3.9.8</span><br><span> Vcs-Git: git://git.osmocom.org/libosmocore.git</span><br><span>diff --git a/include/osmocom/core/socket.h b/include/osmocom/core/socket.h</span><br><span>index 37b1eae..e26ca0d 100644</span><br><span>--- a/include/osmocom/core/socket.h</span><br><span>+++ b/include/osmocom/core/socket.h</span><br><span>@@ -36,6 +36,9 @@</span><br><span> /*! use SO_REUSEADDR on UDP ports (required for multicast) */</span><br><span> #define OSMO_SOCK_F_UDP_REUSEADDR (1 << 5)</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! maximum number of local or remote addresses supported by an osmo_sock instance */</span><br><span style="color: hsl(120, 100%, 40%);">+#define OSMO_SOCK_MAX_ADDRS 32</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,</span><br><span>                    const char *host, uint16_t port, unsigned int flags);</span><br><span> </span><br><span>@@ -43,6 +46,10 @@</span><br><span>               const char *local_host, uint16_t local_port,</span><br><span>                 const char *remote_host, uint16_t remote_port, unsigned int flags);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_sock_init2_multiaddr(uint16_t family, uint16_t type, uint8_t proto,</span><br><span style="color: hsl(120, 100%, 40%);">+                 const char **local_hosts, size_t local_hosts_cnt, uint16_t local_port,</span><br><span style="color: hsl(120, 100%, 40%);">+                const char **remote_hosts, size_t remote_hosts_cnt, uint16_t remote_port, unsigned int flags);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto,</span><br><span>                  const char *host, uint16_t port, unsigned int flags);</span><br><span> </span><br><span>diff --git a/src/Makefile.am b/src/Makefile.am</span><br><span>index 5f5f017..9943281 100644</span><br><span>--- a/src/Makefile.am</span><br><span>+++ b/src/Makefile.am</span><br><span>@@ -4,7 +4,7 @@</span><br><span> LIBVERSION=14:0:2</span><br><span> </span><br><span> AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include</span><br><span style="color: hsl(0, 100%, 40%);">-AM_CFLAGS = -Wall $(TALLOC_CFLAGS) $(PTHREAD_CFLAGS)</span><br><span style="color: hsl(120, 100%, 40%);">+AM_CFLAGS = -Wall $(TALLOC_CFLAGS) $(PTHREAD_CFLAGS) $(LIBSCTP_CFLAGS)</span><br><span> </span><br><span> if ENABLE_PSEUDOTALLOC</span><br><span> AM_CPPFLAGS += -I$(top_srcdir)/src/pseudotalloc</span><br><span>@@ -12,7 +12,7 @@</span><br><span> </span><br><span> lib_LTLIBRARIES = libosmocore.la</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-libosmocore_la_LIBADD = $(BACKTRACE_LIB) $(TALLOC_LIBS) $(LIBRARY_RT) $(PTHREAD_LIBS)</span><br><span style="color: hsl(120, 100%, 40%);">+libosmocore_la_LIBADD = $(BACKTRACE_LIB) $(TALLOC_LIBS) $(LIBRARY_RT) $(PTHREAD_LIBS) $(LIBSCTP_LIBS)</span><br><span> libosmocore_la_SOURCES = context.c timer.c timer_gettimeofday.c timer_clockgettime.c \</span><br><span>                   select.c signal.c msgb.c bits.c \</span><br><span>                    bitvec.c bitcomp.c counter.c fsm.c \</span><br><span>diff --git a/src/socket.c b/src/socket.c</span><br><span>index ef3bb58..542c76e 100644</span><br><span>--- a/src/socket.c</span><br><span>+++ b/src/socket.c</span><br><span>@@ -53,6 +53,10 @@</span><br><span> #include <netdb.h></span><br><span> #include <ifaddrs.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef HAVE_LIBSCTP</span><br><span style="color: hsl(120, 100%, 40%);">+#include <netinet/sctp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct addrinfo *addrinfo_helper(uint16_t family, uint16_t type, uint8_t proto,</span><br><span>                                      const char *host, uint16_t port, bool passive)</span><br><span> {</span><br><span>@@ -96,6 +100,34 @@</span><br><span>    return result;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! Retrieve an array of addrinfo with specified hints, one for each host in the hosts array.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] addrinfo array of addrinfo pointers, will be filled by the function on success.</span><br><span style="color: hsl(120, 100%, 40%);">+ *             Its size must be at least the one of hosts.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] family Socket family like AF_INET, AF_INET6.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] hosts array of char pointers (strings) containing the addresses to query.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] host_cnt length of the hosts array (in items).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] port port number in host byte order.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] passive whether to include the AI_PASSIVE flag in getaddrinfo() hints.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 is returned on success together with a filled addrinfo array; negative on error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int addrinfo_helper_multi(struct addrinfo **addrinfo, uint16_t family, uint16_t type, uint8_t proto,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  const char **hosts, size_t host_cnt, uint16_t port, bool passive)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int i, j;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; i < host_cnt; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           addrinfo[i] = addrinfo_helper(family, type, proto, hosts[i], port, passive);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (!addrinfo[i]) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   for (j = 0; j < i; j++)</span><br><span style="color: hsl(120, 100%, 40%);">+                            freeaddrinfo(addrinfo[j]);</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -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 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int socket_helper(const struct addrinfo *rp, unsigned int flags)</span><br><span> {</span><br><span>       int sfd, on = 1;</span><br><span>@@ -118,6 +150,37 @@</span><br><span>      return sfd;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Fill buf with a string representation of the address set, in the form:</span><br><span style="color: hsl(120, 100%, 40%);">+ * buf_len == 0: "()"</span><br><span style="color: hsl(120, 100%, 40%);">+ * buf_len == 1: "hostA"</span><br><span style="color: hsl(120, 100%, 40%);">+ * buf_len >= 2: (hostA|hostB|...|...)</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int multiaddr_snprintf(char* buf, size_t buf_len, const char **hosts, size_t host_cnt)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int len = 0, offset = 0, rem = buf_len;</span><br><span style="color: hsl(120, 100%, 40%);">+       int ret, i;</span><br><span style="color: hsl(120, 100%, 40%);">+   char *after;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (buf_len < 3)</span><br><span style="color: hsl(120, 100%, 40%);">+           return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (host_cnt != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ret = snprintf(buf, rem, "(");</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ret < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return ret;</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_SNPRINTF_RET(ret, rem, offset, len);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < host_cnt; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (host_cnt == 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                    after = "";</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  after = (i == (host_cnt - 1)) ? ")" : "|";</span><br><span style="color: hsl(120, 100%, 40%);">+                ret = snprintf(buf + offset, rem, "%s%s", hosts[i] ? : "0.0.0.0", after);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_SNPRINTF_RET(ret, rem, offset, len);</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 len;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span> static int osmo_sock_init_tail(int fd, uint16_t type, unsigned int flags)</span><br><span> {</span><br><span>@@ -294,6 +357,229 @@</span><br><span>         return sfd;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Build array of addresses taking first addrinfo result of the requested family</span><br><span style="color: hsl(120, 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%);">+static int addrinfo_to_sockaddr(uint16_t family, const struct addrinfo **result,</span><br><span style="color: hsl(120, 100%, 40%);">+                            const char **hosts, int host_cont,</span><br><span style="color: hsl(120, 100%, 40%);">+                            struct sockaddr_in *addrs4, struct sockaddr_in6 *addrs6) {</span><br><span style="color: hsl(120, 100%, 40%);">+    size_t host_idx;</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct addrinfo *rp;</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(family == AF_INET || family == AF_INET6);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       for (host_idx = 0; host_idx < host_cont; host_idx++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             for (rp = result[host_idx]; rp != NULL; rp = rp->ai_next) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (rp->ai_family != family)</span><br><span style="color: hsl(120, 100%, 40%);">+                               continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (family == AF_INET)</span><br><span style="color: hsl(120, 100%, 40%);">+                                memcpy(&addrs4[host_idx], rp->ai_addr, sizeof(addrs4[host_idx]));</span><br><span style="color: hsl(120, 100%, 40%);">+                      else</span><br><span style="color: hsl(120, 100%, 40%);">+                          memcpy(&addrs6[host_idx], rp->ai_addr, sizeof(addrs6[host_idx]));</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!rp) { /* No addr could be bound for this host! */</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOGP(DLGLOBAL, LOGL_ERROR, "No suitable remote address found for host: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            hosts[host_idx]);</span><br><span style="color: hsl(120, 100%, 40%);">+                        return -ENODEV;</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 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%);">+/*! Initialize a socket (including bind and/or connect) with multiple local or remote addresses.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] local_hosts array of char pointers (strings), each containing local host name or IP address in string form</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] local_hosts_cnt length of local_hosts (in items)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] local_port local port number in host byte order</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] remote_host array of char pointers (strings), each containing remote host name or IP address in string form</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] remote_hosts_cnt length of remote_hosts (in items)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] remote_port remote port number in host byte order</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] flags flags like \ref OSMO_SOCK_F_CONNECT</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns socket file descriptor on success; negative on error</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This function is similar to \ref osmo_sock_init2(), but can be passed an</span><br><span style="color: hsl(120, 100%, 40%);">+ * array of local or remote addresses for protocols supporting multiple</span><br><span style="color: hsl(120, 100%, 40%);">+ * addresses per socket, like SCTP (currently only one supported). This function</span><br><span style="color: hsl(120, 100%, 40%);">+ * should not be used by protocols not supporting this kind of features, but</span><br><span style="color: hsl(120, 100%, 40%);">+ * rather \ref osmo_sock_init2() should be used instead.</span><br><span style="color: hsl(120, 100%, 40%);">+ * See \ref osmo_sock_init2() for more information on flags and general behavior.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_sock_init2_multiaddr(uint16_t family, uint16_t type, uint8_t proto,</span><br><span style="color: hsl(120, 100%, 40%);">+                  const char **local_hosts, size_t local_hosts_cnt, uint16_t local_port,</span><br><span style="color: hsl(120, 100%, 40%);">+                const char **remote_hosts, size_t remote_hosts_cnt, uint16_t remote_port,</span><br><span style="color: hsl(120, 100%, 40%);">+             unsigned int flags)</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%);">+   struct addrinfo *result[OSMO_SOCK_MAX_ADDRS];</span><br><span style="color: hsl(120, 100%, 40%);">+ int sfd = -1, rc, on = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct sockaddr_in addrs4[OSMO_SOCK_MAX_ADDRS];</span><br><span style="color: hsl(120, 100%, 40%);">+       struct sockaddr_in6 addrs6[OSMO_SOCK_MAX_ADDRS];</span><br><span style="color: hsl(120, 100%, 40%);">+      struct sockaddr *addrs;</span><br><span style="color: hsl(120, 100%, 40%);">+       char strbuf[512];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* TODO: So far this function is only aimed for SCTP, but could be</span><br><span style="color: hsl(120, 100%, 40%);">+       reused in the future for other protocols with multi-addr support */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (proto != IPPROTO_SCTP)</span><br><span style="color: hsl(120, 100%, 40%);">+            return -ENOTSUP;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* TODO: Let's not support AF_UNSPEC for now. sctp_bindx() actually</span><br><span style="color: hsl(120, 100%, 40%);">+          supports binding both types of addresses on a AF_INET6 soscket, but</span><br><span style="color: hsl(120, 100%, 40%);">+           that would mean we could get both AF_INET and AF_INET6 addresses for</span><br><span style="color: hsl(120, 100%, 40%);">+          each host, and makes complexity of this function increase a lot since</span><br><span style="color: hsl(120, 100%, 40%);">+         we'd need to find out which subsets to use, use v4v6 mapped socket,</span><br><span style="color: hsl(120, 100%, 40%);">+       etc. */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (family == AF_UNSPEC)</span><br><span style="color: hsl(120, 100%, 40%);">+              return -ENOTSUP;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLGLOBAL, LOGL_ERROR, "invalid: you have to specify either "</span><br><span style="color: hsl(120, 100%, 40%);">+                   "BIND or CONNECT flags\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return -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%);">+   if (((flags & OSMO_SOCK_F_BIND) && !local_hosts_cnt) ||</span><br><span style="color: hsl(120, 100%, 40%);">+       ((flags & OSMO_SOCK_F_CONNECT) && !remote_hosts_cnt) ||</span><br><span style="color: hsl(120, 100%, 40%);">+           local_hosts_cnt > OSMO_SOCK_MAX_ADDRS ||</span><br><span style="color: hsl(120, 100%, 40%);">+           remote_hosts_cnt > OSMO_SOCK_MAX_ADDRS)</span><br><span style="color: hsl(120, 100%, 40%);">+                return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* figure out local side of socket */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (flags & OSMO_SOCK_F_BIND) {</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = addrinfo_helper_multi(result, family, type, proto, local_hosts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         local_hosts_cnt, local_port, true);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Since addrinfo_helper sets ai_family, socktype and</span><br><span style="color: hsl(120, 100%, 40%);">+            ai_protocol in hints, we know all results will use same</span><br><span style="color: hsl(120, 100%, 40%);">+               values, so simply pick the first one and pass it to create</span><br><span style="color: hsl(120, 100%, 40%);">+            the socket:</span><br><span style="color: hsl(120, 100%, 40%);">+                */</span><br><span style="color: hsl(120, 100%, 40%);">+            sfd = socket_helper(result[0], flags);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (sfd < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     for (i = 0; i < local_hosts_cnt; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                              freeaddrinfo(result[i]);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (proto != IPPROTO_UDP || flags & OSMO_SOCK_F_UDP_REUSEADDR) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        &on, sizeof(on));</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              multiaddr_snprintf(strbuf, sizeof(strbuf), local_hosts, local_hosts_cnt);</span><br><span style="color: hsl(120, 100%, 40%);">+                             LOGP(DLGLOBAL, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 "cannot setsockopt socket:"</span><br><span style="color: hsl(120, 100%, 40%);">+                                 " %s:%u: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                     strbuf, local_port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+                                for (i = 0; i < local_hosts_cnt; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                                      freeaddrinfo(result[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                              close(sfd);</span><br><span style="color: hsl(120, 100%, 40%);">+                           return rc;</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%);">+           /* Build array of addresses taking first of same family for each host.</span><br><span style="color: hsl(120, 100%, 40%);">+                   TODO: Ideally we should use backtracking storing last used</span><br><span style="color: hsl(120, 100%, 40%);">+            indexes and trying next combination if connect() fails .*/</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = addrinfo_to_sockaddr(family, (const struct addrinfo **)result,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     local_hosts, local_hosts_cnt, addrs4, addrs6);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      for (i = 0; i < local_hosts_cnt; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                              freeaddrinfo(result[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                      close(sfd);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -ENODEV;</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%);">+           if (family == AF_INET)</span><br><span style="color: hsl(120, 100%, 40%);">+                        addrs = (struct sockaddr *)addrs4;</span><br><span style="color: hsl(120, 100%, 40%);">+            else</span><br><span style="color: hsl(120, 100%, 40%);">+                  addrs = (struct sockaddr *)addrs6;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (sctp_bindx(sfd, addrs, local_hosts_cnt, SCTP_BINDX_ADD_ADDR) == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     multiaddr_snprintf(strbuf, sizeof(strbuf), local_hosts, local_hosts_cnt);</span><br><span style="color: hsl(120, 100%, 40%);">+                     LOGP(DLGLOBAL, LOGL_NOTICE, "unable to bind socket: %s:%u: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        strbuf, local_port, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+                    for (i = 0; i < local_hosts_cnt; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                           freeaddrinfo(result[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                 close(sfd);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -ENODEV;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             for (i = 0; i < local_hosts_cnt; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                      freeaddrinfo(result[i]);</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%);">+   /* Reached this point, if OSMO_SOCK_F_BIND then sfd is valid (>=0) or it</span><br><span style="color: hsl(120, 100%, 40%);">+      was already closed and func returned. If OSMO_SOCK_F_BIND is not</span><br><span style="color: hsl(120, 100%, 40%);">+      set, then sfd = -1 */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* figure out remote side of socket */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (flags & OSMO_SOCK_F_CONNECT) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = addrinfo_helper_multi(result, family, type, proto, remote_hosts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        remote_hosts_cnt, remote_port, false);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (sfd >= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                              close(sfd);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -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%);">+           if (sfd < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* Since addrinfo_helper sets ai_family, socktype and</span><br><span style="color: hsl(120, 100%, 40%);">+                    ai_protocol in hints, we know all results will use same</span><br><span style="color: hsl(120, 100%, 40%);">+                       values, so simply pick the first one and pass it to create</span><br><span style="color: hsl(120, 100%, 40%);">+                    the socket:</span><br><span style="color: hsl(120, 100%, 40%);">+                        */</span><br><span style="color: hsl(120, 100%, 40%);">+                    sfd = socket_helper(result[0], flags);</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (sfd < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             for (i = 0; i < remote_hosts_cnt; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                                     freeaddrinfo(result[i]);</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%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Build array of addresses taking first of same family for each host.</span><br><span style="color: hsl(120, 100%, 40%);">+                   TODO: Ideally we should use backtracking storing last used</span><br><span style="color: hsl(120, 100%, 40%);">+            indexes and trying next combination if connect() fails .*/</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = addrinfo_to_sockaddr(family, (const struct addrinfo **)result,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     remote_hosts, remote_hosts_cnt, addrs4, addrs6);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      for (i = 0; i < remote_hosts_cnt; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                             freeaddrinfo(result[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                      close(sfd);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -ENODEV;</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%);">+           if (family == AF_INET)</span><br><span style="color: hsl(120, 100%, 40%);">+                        addrs = (struct sockaddr *)addrs4;</span><br><span style="color: hsl(120, 100%, 40%);">+            else</span><br><span style="color: hsl(120, 100%, 40%);">+                  addrs = (struct sockaddr *)addrs6;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = sctp_connectx(sfd, addrs, remote_hosts_cnt, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (rc != 0 && errno != EINPROGRESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        multiaddr_snprintf(strbuf, sizeof(strbuf), remote_hosts, remote_hosts_cnt);</span><br><span style="color: hsl(120, 100%, 40%);">+                   LOGP(DLGLOBAL, LOGL_ERROR, "unable to connect socket: %s:%u: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         strbuf, remote_port, strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+                        for (i = 0; i < remote_hosts_cnt; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                             freeaddrinfo(result[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                      close(sfd);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -ENODEV;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             for (i = 0; i < remote_hosts_cnt; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                     freeaddrinfo(result[i]);</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%);">+   rc = osmo_sock_init_tail(sfd, type, flags);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              close(sfd);</span><br><span style="color: hsl(120, 100%, 40%);">+           sfd = -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%);">+   return sfd;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* HAVE_LIBSCTP */</span><br><span> </span><br><span> /*! Initialize a socket (including bind/connect)</span><br><span>  *  \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/15781">change 15781</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/+/15781"/><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: Ic8681d9e093216c99c6bca4be81c31ef83688ed1 </div>
<div style="display:none"> Gerrit-Change-Number: 15781 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: daniel <dwillmann@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-Reviewer: lynxis lazus <lynxis@fe80.eu> </div>
<div style="display:none"> Gerrit-Reviewer: osmith <osmith@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>