socket: Introduce API osmo_sock_multiaddr_get_name_buf()
An extra osmo_multiaddr_ip_and_port_snprintf() API is introduced which
is used by osmo_sock_multiaddr_get_name_buf() but which will also be
used by other app uers willing to use
osmo_sock_multiaddr_get_ip_and_port() according to its needs (eg. only
printing the local side).
Related: SYS#6636
Change-Id: I48950754ed6f61ee5ffa04a447fab8903f10acc0
diff --git a/src/core/libosmocore.map b/src/core/libosmocore.map
index ffbbd2f..e7daced 100644
--- a/src/core/libosmocore.map
+++ b/src/core/libosmocore.map
@@ -298,6 +298,7 @@
osmo_macaddr_parse;
osmo_mnl_destroy;
osmo_mnl_init;
+osmo_multiaddr_ip_and_port_snprintf;
osmo_netdev_add_addr;
osmo_netdev_add_route;
osmo_netdev_alloc;
@@ -437,6 +438,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_set_dscp;
osmo_sock_set_priority;
osmo_sock_unix_init;
diff --git a/src/core/socket.c b/src/core/socket.c
index 51703ef..c600732 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -2018,6 +2018,112 @@
return talloc_asprintf(ctx, "(%s)", str);
}
+/*! Format multiple IP addresses and/or port number into a combined string buffer
+ * \param[out] str Destination string buffer.
+ * \param[in] str_len sizeof(str).
+ * \param[out] ip Pointer to memory holding ip_cnt 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 printed in when not NULL).
+ * \return String length as returned by snprintf(), or negative on error.
+ *
+ * This API expectes an ip array as the one filled in by
+ * osmo_sock_multiaddr_get_ip_and_port(), and hence it's a good companion for
+ * that API.
+ */
+int osmo_multiaddr_ip_and_port_snprintf(char *str, size_t str_len,
+ const char *ip, size_t ip_cnt, size_t ip_len,
+ const char *portbuf)
+{
+ struct osmo_strbuf sb = { .buf = str, .len = str_len };
+ bool is_v6 = false;
+ unsigned int i;
+
+ if (ip_cnt == 0) {
+ OSMO_STRBUF_PRINTF(sb, "NULL:%s", portbuf);
+ return sb.chars_needed;
+ }
+ if (ip_cnt > 1)
+ OSMO_STRBUF_PRINTF(sb, "(");
+ else if ((is_v6 = !!strchr(&ip[0], ':'))) /* IPv6, add [] to separate from port. */
+ OSMO_STRBUF_PRINTF(sb, "[");
+
+ for (i = 0; i < ip_cnt - 1; i++)
+ OSMO_STRBUF_PRINTF(sb, "%s|", &ip[i * ip_len]);
+ OSMO_STRBUF_PRINTF(sb, "%s", &ip[i * ip_len]);
+
+ if (ip_cnt > 1)
+ OSMO_STRBUF_PRINTF(sb, ")");
+ else if (is_v6)
+ OSMO_STRBUF_PRINTF(sb, "]");
+ if (portbuf)
+ OSMO_STRBUF_PRINTF(sb, ":%s", portbuf);
+
+ return sb.chars_needed;
+}
+
+/*! Get address/port information on socket in provided string buffer, like "r=1.2.3.4:5<->l=6.7.8.9:10".
+ * This does not include braces like osmo_sock_get_name().
+ * \param[out] str Destination string buffer.
+ * \param[in] str_len sizeof(str).
+ * \param[in] fd File descriptor of socket.
+ * \param[in] fd IPPROTO of the socket, eg: IPPROTO_SCTP.
+ * \return String length as returned by snprintf(), or negative on error.
+ */
+int osmo_sock_multiaddr_get_name_buf(char *str, size_t str_len, int fd, int sk_proto)
+{
+ char hostbuf[OSMO_SOCK_MAX_ADDRS][INET6_ADDRSTRLEN];
+ size_t num_hostbuf = ARRAY_SIZE(hostbuf);
+ char portbuf[6];
+ struct osmo_strbuf sb = { .buf = str, .len = str_len };
+
+ if (fd < 0) {
+ osmo_strlcpy(str, "<error-bad-fd>", str_len);
+ return sb.chars_needed;
+ }
+
+ switch (sk_proto) {
+ case IPPROTO_SCTP:
+ break; /* continue below */
+ default:
+ return osmo_sock_get_name_buf(str, str_len, fd);
+ }
+
+ /* get remote */
+ OSMO_STRBUF_PRINTF(sb, "r=");
+ if (osmo_sock_multiaddr_get_ip_and_port(fd, sk_proto, &hostbuf[0][0], &num_hostbuf,
+ sizeof(hostbuf[0]), portbuf, sizeof(portbuf), false) != 0) {
+ OSMO_STRBUF_PRINTF(sb, "NULL");
+ } else {
+ const bool need_more_bufs = num_hostbuf > ARRAY_SIZE(hostbuf);
+ if (need_more_bufs)
+ num_hostbuf = ARRAY_SIZE(hostbuf);
+ OSMO_STRBUF_APPEND(sb, osmo_multiaddr_ip_and_port_snprintf,
+ &hostbuf[0][0], num_hostbuf, sizeof(hostbuf[0]), portbuf);
+ if (need_more_bufs)
+ OSMO_STRBUF_PRINTF(sb, "<need-more-bufs!>");
+ }
+
+ OSMO_STRBUF_PRINTF(sb, "<->l=");
+
+ /* get local */
+ num_hostbuf = ARRAY_SIZE(hostbuf);
+ if (osmo_sock_multiaddr_get_ip_and_port(fd, sk_proto, &hostbuf[0][0], &num_hostbuf,
+ sizeof(hostbuf[0]), portbuf, sizeof(portbuf), true) != 0) {
+ OSMO_STRBUF_PRINTF(sb, "NULL");
+ } else {
+ const bool need_more_bufs = num_hostbuf > ARRAY_SIZE(hostbuf);
+ if (need_more_bufs)
+ num_hostbuf = ARRAY_SIZE(hostbuf);
+ OSMO_STRBUF_APPEND(sb, osmo_multiaddr_ip_and_port_snprintf,
+ &hostbuf[0][0], num_hostbuf, sizeof(hostbuf[0]), portbuf);
+ if (need_more_bufs)
+ OSMO_STRBUF_PRINTF(sb, "<need-more-bufs!>");
+ }
+
+ return sb.chars_needed;
+}
+
/*! Get address/port information on socket in provided string buffer, like "r=1.2.3.4:5<->l=6.7.8.9:10".
* This does not include braces like osmo_sock_get_name().
* \param[out] str Destination string buffer.