diff options
author | Pau Espin Pedrol <pespin@sysmocom.de> | 2023-09-29 19:21:10 +0200 |
---|---|---|
committer | Pau Espin Pedrol <pespin@sysmocom.de> | 2023-10-03 18:38:02 +0200 |
commit | 64ba9edf173cc16f9d94c94a423a8b7a5904efaf (patch) | |
tree | 922a6cf2fccbab08ad752d76e31dffff575b9140 | |
parent | osmo_io: Clean up code (diff) | |
download | libosmocore-64ba9edf173cc16f9d94c94a423a8b7a5904efaf.tar.xz libosmocore-64ba9edf173cc16f9d94c94a423a8b7a5904efaf.zip |
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
-rw-r--r-- | TODO-RELEASE | 1 | ||||
-rw-r--r-- | include/osmocom/core/socket.h | 3 | ||||
-rw-r--r-- | src/core/libosmocore.map | 2 | ||||
-rw-r--r-- | src/core/socket.c | 152 |
4 files changed, 157 insertions, 1 deletions
diff --git a/TODO-RELEASE b/TODO-RELEASE index 8ccfa491..2f9903d0 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 bbf828f8..db55863c 100644 --- a/include/osmocom/core/socket.h +++ b/include/osmocom/core/socket.h @@ -154,7 +154,6 @@ int osmo_sock_init2_multiaddr2(uint16_t family, uint16_t type, uint8_t proto, 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_local_ip_port(int fd, char *port, size_t len); 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 30814c34..105a80a1 100644 --- a/src/core/libosmocore.map +++ b/src/core/libosmocore.map @@ -431,6 +431,8 @@ osmo_sock_mcast_iface_set; 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 024757fb..2de31311 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1257,6 +1257,158 @@ int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type, 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]; + 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; + char strbuf[512]; + 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]; + 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; + char strbuf[512]; + 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) { |