pespin has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/libosmocore/+/34607?usp=email )


Change subject: socket: Introduce APIs 
osmo_sock_multiaddr_{add,del}_local_addr()
......................................................................

socket: Introduce APIs osmo_sock_multiaddr_{add,del}_local_addr()

These APIs are used to bind or unbind an active socket adding or
removing addresses from the existing set.

Related: OS#6077
Change-Id: Ifc6e7d643c2a0c53f479bfd0d5c36d08c0c01953
---
M TODO-RELEASE
M include/osmocom/core/socket.h
M src/core/libosmocore.map
M src/core/socket.c
4 files changed, 170 insertions(+), 1 deletion(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/07/34607/1

diff --git a/TODO-RELEASE b/TODO-RELEASE
index 8ccfa49..2f9903d 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -7,3 +7,4 @@
 # If any interfaces have been added since the last public release: c:r:a + 1.
 # If any interfaces have been removed or changed since the last public 
release: c:r:0.
 #library       what                    description / commit summary line
+core      ADD       osmo_sock_multiaddr_{add,del}_local_addr()
\ No newline at end of file
diff --git a/include/osmocom/core/socket.h b/include/osmocom/core/socket.h
index bbf828f..db55863 100644
--- a/include/osmocom/core/socket.h
+++ b/include/osmocom/core/socket.h
@@ -154,7 +154,6 @@
                   const char **remote_hosts, size_t remote_hosts_cnt, uint16_t 
remote_port,
                   unsigned int flags, struct osmo_sock_init2_multiaddr_pars 
*pars);

-
 int osmo_sock_init_osa(uint16_t type, uint8_t proto,
                    const struct osmo_sockaddr *local,
                    const struct osmo_sockaddr *remote,
@@ -191,6 +190,8 @@
 int osmo_sock_get_remote_ip(int fd, char *host, size_t len);
 int osmo_sock_get_remote_ip_port(int fd, char *port, size_t len);

+int osmo_sock_multiaddr_add_local_addr(int sfd, const char **addrs, size_t 
addrs_cnt);
+int osmo_sock_multiaddr_del_local_addr(int sfd, const char **addrs, size_t 
addrs_cnt);
 
 int osmo_sock_mcast_loop_set(int fd, bool enable);
 int osmo_sock_mcast_ttl_set(int fd, uint8_t ttl);
diff --git a/src/core/libosmocore.map b/src/core/libosmocore.map
index 30814c3..105a80a 100644
--- a/src/core/libosmocore.map
+++ b/src/core/libosmocore.map
@@ -431,6 +431,8 @@
 osmo_sock_mcast_loop_set;
 osmo_sock_mcast_subscribe;
 osmo_sock_mcast_ttl_set;
+osmo_sock_multiaddr_add_local_addr;
+çosmo_sock_multiaddr_del_local_addr;
 osmo_sock_set_dscp;
 osmo_sock_set_priority;
 osmo_sock_unix_init;
diff --git a/src/core/socket.c b/src/core/socket.c
index 024757f..325cd16 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1257,6 +1257,158 @@
        return osmo_sock_init(ss->sa_family, type, proto, host, port, flags);
 }

+/*! Add addresses to the multi-address (SCTP) socket active binding set
+ *  \param[in] sfd The multi-address (SCTP) socket
+ *  \param[in] addrs array of char pointers (strings), each containing local 
host name or IP address in string form
+ *  \param[in] addrs_cnt length of addrs_hosts (in items)
+ *  \returns 0 on success; negative on error
+ *
+ * This function only supports SCTP sockets so far, and hence it should be
+ * called only on socket file descriptions referencing that kind of sockets.
+ */
+int osmo_sock_multiaddr_add_local_addr(int sfd, const char **addrs, size_t 
addrs_cnt)
+{
+       struct osmo_sockaddr osa;
+       socklen_t slen = sizeof(osa);
+       uint16_t sfd_family;
+       uint16_t type = SOCK_STREAM ;/* Fixme: we assume fd is SOCK_STREAM */
+       uint8_t proto = IPPROTO_SCTP; /* Fixme: we assume fd is IPPROTO_SCTP */
+       struct addrinfo *res[OSMO_SOCK_MAX_ADDRS];
+       uint16_t port;
+       struct sockaddr_in6 addrs_buf[OSMO_SOCK_MAX_ADDRS];
+       char strbuf[512];
+       unsigned int i;
+       int rc;
+       bool res_has_v4addr = false, res_has_v6addr = false;
+
+       rc = getsockname(sfd, &osa.u.sa, &slen);
+       if (rc < 0)
+               return rc; /* TODO: log error? */
+       sfd_family = osa.u.sa.sa_family;
+       port = osmo_sockaddr_port(&osa.u.sa);
+
+       if (sfd_family != AF_INET && sfd_family != AF_INET6)
+               return -EINVAL;
+
+       rc = addrinfo_helper_multi(res, AF_UNSPEC, type, proto, addrs,
+                                  addrs_cnt, port, true);
+       if (rc < 0)
+               return -EINVAL;
+
+       addrinfo_has_v4v6addr((const struct addrinfo **)res, addrs_cnt,
+                             &res_has_v4addr, &res_has_v6addr);
+       if (sfd_family == AF_INET && !res_has_v4addr) {
+               rc = -EINVAL;
+               goto ret_free;
+       }
+
+       uint16_t new_addr_family;
+       if (sfd_family == AF_INET)
+               new_addr_family = AF_INET;
+       else if (sfd_family == AF_INET6 && !res_has_v4addr)
+               new_addr_family = AF_INET6;
+       else
+               new_addr_family = AF_UNSPEC;
+       rc = addrinfo_to_sockaddr(new_addr_family, (const struct addrinfo 
**)res,
+                                 addrs, addrs_cnt,
+                                 (uint8_t *)addrs_buf, sizeof(addrs_buf));
+       if (rc < 0) {
+               rc = -ENODEV;
+               goto ret_free;
+       }
+
+       rc = sctp_bindx(sfd, (struct sockaddr *)addrs_buf, addrs_cnt, 
SCTP_BINDX_ADD_ADDR);
+       if (rc == -1) {
+               int err = errno;
+               multiaddr_snprintf(strbuf, sizeof(strbuf), addrs, addrs_cnt);
+               LOGP(DLGLOBAL, LOGL_NOTICE, "Unable to bind socket to new 
addresses: %s:%u: %s\n",
+                       strbuf, port, strerror(err));
+               rc = -ENODEV;
+               goto ret_free;
+       }
+
+ret_free:
+       for (i = 0; i < addrs_cnt; i++)
+               freeaddrinfo(res[i]);
+       return rc;
+}
+
+/*! Remove addresses from the multi-address (SCTP) socket active binding set
+ *  \param[in] sfd The multi-address (SCTP) socket
+ *  \param[in] addrs array of char pointers (strings), each containing local 
host name or IP address in string form
+ *  \param[in] addrs_cnt length of addrs_hosts (in items)
+ *  \returns 0 on success; negative on error
+ *
+ * This function only supports SCTP sockets so far, and hence it should be
+ * called only on socket file descriptions referencing that kind of sockets.
+ */
+int osmo_sock_multiaddr_del_local_addr(int sfd, const char **addrs, size_t 
addrs_cnt)
+{
+       struct osmo_sockaddr osa;
+       socklen_t slen = sizeof(osa);
+       uint16_t sfd_family;
+       uint16_t type = SOCK_STREAM ;/* Fixme: we assume fd is SOCK_STREAM */
+       uint8_t proto = IPPROTO_SCTP; /* Fixme: we assume fd is IPPROTO_SCTP */
+       struct addrinfo *res[OSMO_SOCK_MAX_ADDRS];
+       uint16_t port;
+       struct sockaddr_in6 addrs_buf[OSMO_SOCK_MAX_ADDRS];
+       char strbuf[512];
+       unsigned int i;
+       int rc;
+       bool res_has_v4addr = false, res_has_v6addr = false;
+
+       rc = getsockname(sfd, &osa.u.sa, &slen);
+       if (rc < 0)
+               return rc; /* TODO: log error? */
+       sfd_family = osa.u.sa.sa_family;
+       port = osmo_sockaddr_port(&osa.u.sa);
+
+       if (sfd_family != AF_INET && sfd_family != AF_INET6)
+               return -EINVAL;
+
+       rc = addrinfo_helper_multi(res, AF_UNSPEC, type, proto, addrs,
+                                  addrs_cnt, port, true);
+       if (rc < 0)
+               return -EINVAL;
+
+       addrinfo_has_v4v6addr((const struct addrinfo **)res, addrs_cnt,
+                             &res_has_v4addr, &res_has_v6addr);
+       if (sfd_family == AF_INET && !res_has_v4addr) {
+               rc = -EINVAL;
+               goto ret_free;
+       }
+
+       uint16_t del_addr_family;
+       if (sfd_family == AF_INET)
+               del_addr_family = AF_INET;
+       else if (sfd_family == AF_INET6 && !res_has_v4addr)
+               del_addr_family = AF_INET6;
+       else
+               del_addr_family = AF_UNSPEC;
+       rc = addrinfo_to_sockaddr(del_addr_family, (const struct addrinfo 
**)res,
+                                 addrs, addrs_cnt,
+                                 (uint8_t *)addrs_buf, sizeof(addrs_buf));
+       if (rc < 0) {
+               rc = -ENODEV;
+               goto ret_free;
+       }
+
+       rc = sctp_bindx(sfd, (struct sockaddr *)addrs_buf, addrs_cnt, 
SCTP_BINDX_REM_ADDR);
+       if (rc == -1) {
+               int err = errno;
+               multiaddr_snprintf(strbuf, sizeof(strbuf), addrs, addrs_cnt);
+               LOGP(DLGLOBAL, LOGL_NOTICE, "Unable to unbind socket from 
addresses: %s:%u: %s\n",
+                       strbuf, port, strerror(err));
+               rc = -ENODEV;
+               goto ret_free;
+       }
+
+ret_free:
+       for (i = 0; i < addrs_cnt; i++)
+               freeaddrinfo(res[i]);
+       return rc;
+}
+
 static int sockaddr_equal(const struct sockaddr *a,
                          const struct sockaddr *b, unsigned int len)
 {

--
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/34607?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Ifc6e7d643c2a0c53f479bfd0d5c36d08c0c01953
Gerrit-Change-Number: 34607
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <[email protected]>
Gerrit-MessageType: newchange

Reply via email to