aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2023-12-08 14:58:51 +0100
committerPau Espin Pedrol <pespin@sysmocom.de>2023-12-11 11:11:16 +0100
commit19f27bb55108dec7d3c4079bc68eac86acfc1993 (patch)
tree5e4b4a3b4339579f64c92bffdda225c0ee8c1315
parent9c603e64bf553ac282af8534a2d7592f719d092f (diff)
socket: Introduce API osmo_sock_sctp_get_peer_addr_info()pespin/multiaddr
This is a convenience helper to reetrieve the whole set of remote addresses and call getsockopt() on them, making it easy for users to analyse the full set of remote addresses of a socket simply providing an fd. Related: SYS#6636 Change-Id: I3e1c84526b006baff435bbbca49dc6cf7d201cf5
-rw-r--r--TODO-RELEASE1
-rw-r--r--include/osmocom/core/socket.h3
-rw-r--r--src/core/libosmocore.map1
-rw-r--r--src/core/socket.c77
4 files changed, 82 insertions, 0 deletions
diff --git a/TODO-RELEASE b/TODO-RELEASE
index 316c0eca..9f5240f5 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -9,6 +9,7 @@
#library what description / commit summary line
core ADD osmo_sock_multiaddr_{add,del}_local_addr()
core ADD osmo_sock_multiaddr_get_ip_and_port(), osmo_multiaddr_ip_and_port_snprintf(), osmo_sock_multiaddr_get_name_buf()
+core ADD osmo_sock_sctp_get_peer_addr_info()
core ADD gsmtap_inst_fd2() core, DEPRECATE gsmtap_inst_fd()
isdn ABI change add states and flags for external T200 handling
gsm ABI change add T200 timer states to lapdm_datalink
diff --git a/include/osmocom/core/socket.h b/include/osmocom/core/socket.h
index dd145562..0f4a8bd7 100644
--- a/include/osmocom/core/socket.h
+++ b/include/osmocom/core/socket.h
@@ -22,6 +22,7 @@
struct sockaddr_in;
struct sockaddr;
struct osmo_fd;
+struct sctp_paddrinfo;
struct osmo_sockaddr {
union {
@@ -211,5 +212,7 @@ int osmo_sock_local_ip(char *local_ip, const char *remote_ip);
int osmo_sock_set_dscp(int fd, uint8_t dscp);
int osmo_sock_set_priority(int fd, int prio);
+int osmo_sock_sctp_get_peer_addr_info(int fd, struct sctp_paddrinfo *pinfo, size_t *pinfo_cnt);
+
#endif /* (!EMBEDDED) */
/*! @} */
diff --git a/src/core/libosmocore.map b/src/core/libosmocore.map
index e7daced7..b66e37d6 100644
--- a/src/core/libosmocore.map
+++ b/src/core/libosmocore.map
@@ -439,6 +439,7 @@ osmo_sock_multiaddr_add_local_addr;
osmo_sock_multiaddr_del_local_addr;
osmo_sock_multiaddr_get_ip_and_port;
osmo_sock_multiaddr_get_name_buf;
+osmo_sock_sctp_get_peer_addr_info;
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 5b7489d2..c4970886 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2653,6 +2653,83 @@ int osmo_sock_set_priority(int fd, int prio)
return setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio));
}
+#ifdef HAVE_LIBSCTP
+/*! Fill in array of struct sctp_paddrinfo with each of the remote addresses of an SCTP socket
+ * \param[in] fd file descriptor of SCTP socket
+ * \param[out] pinfo Pointer to memory holding an array of struct sctp_paddrinfo (pinfo_cnt length).
+ * \param[in,out] pinfo_cnt length of pinfo array (in elements). On return it contains the number of addresses found.
+ * \returns 0 on success; negative otherwise
+ *
+ * Upon return, pinfo_cnt can be set to a higher value than the one set by the
+ * caller. This can be used by the caller to find out the required array length
+ * and then obtaining by calling the function twice. Only up to pinfo_cnt addresses
+ * are filled in, as per the value provided by the caller.
+ *
+ * Usage example retrieving struct sctp_paddrinfo for all (up to OSMO_SOCK_MAX_ADDRS, 32) remote IP addresses:
+ * struct sctp_paddrinfo pinfo[OSMO_SOCK_MAX_ADDRS];
+ * size_t pinfo_cnt = ARRAY_SIZE(pinfo);
+ * rc = osmo_sock_sctp_get_peer_addr_info(fd, &pinfo[0], &num_hostbuf, pinfo_cnt);
+ * if (rc < 0)
+ * goto error;
+ * if (pinfo_cnt > ARRAY_SIZE(hostbuf))
+ * goto not_enough_buffers;
+ */
+int osmo_sock_sctp_get_peer_addr_info(int fd, struct sctp_paddrinfo *pinfo, size_t *pinfo_cnt)
+{
+ struct sockaddr *addrs = NULL;
+ unsigned int n_addrs, i;
+ void *addr_buf;
+ int rc;
+ socklen_t optlen;
+
+ rc = sctp_getpaddrs(fd, 0, &addrs);
+
+ if (rc < 0)
+ return rc;
+ if (rc == 0)
+ return -ENOTCONN;
+
+ n_addrs = rc;
+ addr_buf = (void *)addrs;
+ for (i = 0; i < n_addrs; i++) {
+ struct sockaddr *sa_addr = (struct sockaddr *)addr_buf;
+ size_t addrlen;
+
+ switch (sa_addr->sa_family) {
+ case AF_INET:
+ addrlen = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ addrlen = sizeof(struct sockaddr_in6);
+ break;
+ default:
+ rc = -EINVAL;
+ goto free_addrs_ret;
+ }
+
+ if (i >= *pinfo_cnt) {
+ addr_buf += addrlen;
+ continue;
+ }
+
+ memset(&pinfo[i], 0, sizeof(pinfo[0]));
+ memcpy(&pinfo[i].spinfo_address, sa_addr, addrlen);
+ optlen = sizeof(pinfo[0]);
+ rc = getsockopt(fd, SOL_SCTP, SCTP_GET_PEER_ADDR_INFO, &pinfo[i], &optlen);
+ if (rc < 0)
+ goto free_addrs_ret;
+
+ addr_buf += addrlen;
+ }
+
+ *pinfo_cnt = n_addrs;
+ rc = 0;
+free_addrs_ret:
+ sctp_freepaddrs(addrs);
+ return rc;
+}
+#endif
+
#endif /* HAVE_SYS_SOCKET_H */
/*! @} */