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 #library what description / commit summary line
core ADD osmo_sock_multiaddr_{add,del}_local_addr() 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_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() core ADD gsmtap_inst_fd2() core, DEPRECATE gsmtap_inst_fd()
isdn ABI change add states and flags for external T200 handling isdn ABI change add states and flags for external T200 handling
gsm ABI change add T200 timer states to lapdm_datalink gsm ABI change add T200 timer states to lapdm_datalink

View File

@ -22,6 +22,7 @@
struct sockaddr_in; struct sockaddr_in;
struct sockaddr; struct sockaddr;
struct osmo_fd; struct osmo_fd;
struct sctp_paddrinfo;
struct osmo_sockaddr { struct osmo_sockaddr {
union { 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_dscp(int fd, uint8_t dscp);
int osmo_sock_set_priority(int fd, int prio); 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) */ #endif /* (!EMBEDDED) */
/*! @} */ /*! @} */

View File

@ -439,6 +439,7 @@ osmo_sock_multiaddr_add_local_addr;
osmo_sock_multiaddr_del_local_addr; osmo_sock_multiaddr_del_local_addr;
osmo_sock_multiaddr_get_ip_and_port; osmo_sock_multiaddr_get_ip_and_port;
osmo_sock_multiaddr_get_name_buf; osmo_sock_multiaddr_get_name_buf;
osmo_sock_sctp_get_peer_addr_info;
osmo_sock_set_dscp; osmo_sock_set_dscp;
osmo_sock_set_priority; osmo_sock_set_priority;
osmo_sock_unix_init; 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)); 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 */ #endif /* HAVE_SYS_SOCKET_H */
/*! @} */ /*! @} */