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
This commit is contained in:
Pau Espin 2023-12-08 14:58:51 +01:00
parent 9c603e64bf
commit 19f27bb551
4 changed files with 82 additions and 0 deletions

View File

@ -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

View File

@ -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) */
/*! @} */

View File

@ -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;

View File

@ -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 */
/*! @} */