pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmocore/+/35276?usp=email )
Change subject: socket: Introduce API osmo_sock_sctp_get_peer_addr_info() ......................................................................
socket: Introduce API osmo_sock_sctp_get_peer_addr_info()
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 --- M TODO-RELEASE M include/osmocom/core/socket.h M src/core/socket.c 3 files changed, 121 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/76/35276/1
diff --git a/TODO-RELEASE b/TODO-RELEASE index 316c0ec..9f5240f 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 dd14556..cd9547a 100644 --- a/include/osmocom/core/socket.h +++ b/include/osmocom/core/socket.h @@ -211,5 +211,7 @@ 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/socket.c b/src/core/socket.c index c600732..70b1885 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2653,6 +2653,109 @@ return setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)); }
+/*! Get multiple IP addresses and/or port number on socket in separate string buffers + * \param[in] fd file descriptor of socket. + * \param[out] ip_proto IPPROTO of the socket, eg: IPPROTO_SCTP. + * \param[out] ip Pointer to memory holding consecutive buffers of size ip_len. + * \param[out] ip_cnt length ip array pointer. on return it contains the number of addresses found. + * \param[in] ip_len length of each of the string buffer in the the ip array. + * \param[out] port number (will be filled in when not NULL). + * \param[in] port_len length of the port buffer. + * \param[in] local (true) or remote (false) name will get looked at. + * \returns 0 on success; negative otherwise. + * + * Upon return, ip_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 ip_cnt addresses + * are filed in, as per the value provided by the caller. + * + * Usage example retrieving all (up to OSMO_SOCK_MAX_ADDRS, 32) bound IP addresses and bound port: + * char hostbuf[OSMO_SOCK_MAX_ADDRS][INET6_ADDRSTRLEN]; + * size_t num_hostbuf = ARRAY_SIZE(hostbuf); + * char portbuf[6]; + * rc = osmo_sock_multiaddr_get_ip_and_port(fd, IPPROTO_SCTP, &hostbuf[0][0], &num_hostbuf, + * sizeof(hostbuf[0]), portbuf, sizeof(portbuf), true); + * if (rc < 0) + * goto error; + * if (num_hostbuf > ARRAY_SIZE(hostbuf)) + * goto not_enough_buffers; + */ + +/*! 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[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_paddringo 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 /* HAVE_SYS_SOCKET_H */
/*! @} */