[Asterisk-code-review] res pjproject: Add utility functions to convert between sock... (asterisk[13])

Joshua Colp asteriskteam at digium.com
Fri Sep 7 04:47:27 CDT 2018


Joshua Colp has submitted this change and it was merged. ( https://gerrit.asterisk.org/10013 )

Change subject: res_pjproject: Add utility functions to convert between socket structures
......................................................................

res_pjproject: Add utility functions to convert between socket structures

Currently, to convert from a pj_sockaddr to an ast_sockaddr, the address
needs to be rendered to a string and then parsed into the correct
structure. This also involves a call to getaddrinfo(3). The same is true
for the inverse operation.

Instead, because we know the internal structure of both ast_sockaddr and
pj_sockaddr, we can translate directly between the two without the
need for an intermediate string.

Change-Id: If0fc4bba9643f755604c6ffbb0d7cc46020bc761
---
M include/asterisk/res_pjproject.h
M res/res_pjproject.c
M res/res_pjproject.exports.in
3 files changed, 205 insertions(+), 1 deletion(-)

Approvals:
  Richard Mudgett: Looks good to me, but someone else must approve
  Michael L. Young: Looks good to me, but someone else must approve
  Kevin Harwell: Looks good to me, approved
  Joshua Colp: Approved for Submit



diff --git a/include/asterisk/res_pjproject.h b/include/asterisk/res_pjproject.h
index 27a2096..844698a 100644
--- a/include/asterisk/res_pjproject.h
+++ b/include/asterisk/res_pjproject.h
@@ -22,6 +22,8 @@
 #include <pj/types.h>
 #include <pj/pool.h>
 
+struct ast_sockaddr;
+
 /*! \brief Determines whether the res_pjproject module is loaded */
 #define CHECK_PJPROJECT_MODULE_LOADED()                 \
 	do {                                                \
@@ -119,4 +121,28 @@
  */
 void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp);
 
+/*!
+ * \brief Fill a pj_sockaddr from an ast_sockaddr
+ * \since 13.24.0
+ *
+ * \param addr The source address to copy
+ * \param pjaddr The target address to receive the copied address
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sockaddr_to_pj_sockaddr(const struct ast_sockaddr *addr, pj_sockaddr *pjaddr);
+
+/*!
+ * \brief Fill an ast_sockaddr from a pj_sockaddr
+ * \since 13.24.0
+ *
+ * \param addr The target address to receive the copied address
+ * \param pjaddr The source address to copy
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sockaddr_from_pj_sockaddr(struct ast_sockaddr *addr, const pj_sockaddr *pjaddr);
+
 #endif /* _RES_PJPROJECT_H */
diff --git a/res/res_pjproject.c b/res/res_pjproject.c
index 603a9a1..ec5e4b6 100644
--- a/res/res_pjproject.c
+++ b/res/res_pjproject.c
@@ -112,6 +112,8 @@
 #include "asterisk/res_pjproject.h"
 #include "asterisk/vector.h"
 #include "asterisk/sorcery.h"
+#include "asterisk/test.h"
+#include "asterisk/netsock2.h"
 
 static struct ast_sorcery *pjproject_sorcery;
 static pj_log_func *log_cb_orig;
@@ -483,6 +485,176 @@
 	pj_caching_pool_destroy(cp);
 }
 
+int ast_sockaddr_to_pj_sockaddr(const struct ast_sockaddr *addr, pj_sockaddr *pjaddr)
+{
+	if (addr->ss.ss_family == AF_INET) {
+		struct sockaddr_in *sin = (struct sockaddr_in *) &addr->ss;
+		pjaddr->ipv4.sin_family = pj_AF_INET();
+		pjaddr->ipv4.sin_addr   = sin->sin_addr;
+		pjaddr->ipv4.sin_port   = sin->sin_port;
+	} else if (addr->ss.ss_family == AF_INET6) {
+		struct sockaddr_in6 *sin = (struct sockaddr_in6 *) &addr->ss;
+		pjaddr->ipv6.sin6_family   = pj_AF_INET6();
+		pjaddr->ipv6.sin6_port     = sin->sin6_port;
+		pjaddr->ipv6.sin6_flowinfo = sin->sin6_flowinfo;
+		pjaddr->ipv6.sin6_scope_id = sin->sin6_scope_id;
+		memcpy(&pjaddr->ipv6.sin6_addr, &sin->sin6_addr, sizeof(pjaddr->ipv6.sin6_addr));
+	} else {
+		memset(pjaddr, 0, sizeof(*pjaddr));
+		return -1;
+	}
+	return 0;
+}
+
+int ast_sockaddr_from_pj_sockaddr(struct ast_sockaddr *addr, const pj_sockaddr *pjaddr)
+{
+	if (pjaddr->addr.sa_family == pj_AF_INET()) {
+		struct sockaddr_in *sin = (struct sockaddr_in *) &addr->ss;
+		sin->sin_family = AF_INET;
+		sin->sin_addr   = pjaddr->ipv4.sin_addr;
+		sin->sin_port   = pjaddr->ipv4.sin_port;
+		addr->len = sizeof(struct sockaddr_in);
+	} else if (pjaddr->addr.sa_family == pj_AF_INET6()) {
+		struct sockaddr_in6 *sin = (struct sockaddr_in6 *) &addr->ss;
+		sin->sin6_family   = AF_INET6;
+		sin->sin6_port     = pjaddr->ipv6.sin6_port;
+		sin->sin6_flowinfo = pjaddr->ipv6.sin6_flowinfo;
+		sin->sin6_scope_id = pjaddr->ipv6.sin6_scope_id;
+		memcpy(&sin->sin6_addr, &pjaddr->ipv6.sin6_addr, sizeof(sin->sin6_addr));
+		addr->len = sizeof(struct sockaddr_in6);
+	} else {
+		memset(addr, 0, sizeof(*addr));
+		return -1;
+	}
+	return 0;
+}
+
+#ifdef TEST_FRAMEWORK
+static void fill_with_garbage(void *x, ssize_t len)
+{
+	unsigned char *w = x;
+	while (len > 0) {
+		int r = ast_random();
+		memcpy(w, &r, len > sizeof(r) ? sizeof(r) : len);
+		w += sizeof(r);
+		len -= sizeof(r);
+	}
+}
+
+AST_TEST_DEFINE(ast_sockaddr_to_pj_sockaddr_test)
+{
+	char *candidates[] = {
+		"127.0.0.1:5555",
+		"[::]:4444",
+		"192.168.0.100:0",
+		"[fec0::1:80]:0",
+		"[fec0::1]:80",
+		NULL,
+	}, **candidate = candidates;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "ast_sockaddr_to_pj_sockaddr_test";
+		info->category = "/res/res_pjproject/";
+		info->summary = "Validate conversions from an ast_sockaddr to a pj_sockaddr";
+		info->description = "This test converts an ast_sockaddr to a pj_sockaddr and validates\n"
+			"that the two evaluate to the same string when formatted.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	while (*candidate) {
+		struct ast_sockaddr addr = {{0,}};
+		pj_sockaddr pjaddr;
+		char buffer[512];
+
+		fill_with_garbage(&pjaddr, sizeof(pj_sockaddr));
+
+		if (!ast_sockaddr_parse(&addr, *candidate, 0)) {
+			ast_test_status_update(test, "Failed to parse candidate IP: %s\n", *candidate);
+			return AST_TEST_FAIL;
+		}
+
+		if (ast_sockaddr_to_pj_sockaddr(&addr, &pjaddr)) {
+			ast_test_status_update(test, "Failed to convert ast_sockaddr to pj_sockaddr: %s\n", *candidate);
+			return AST_TEST_FAIL;
+		}
+
+		pj_sockaddr_print(&pjaddr, buffer, sizeof(buffer), 1 | 2);
+
+		if (strcmp(*candidate, buffer)) {
+			ast_test_status_update(test, "Converted sockaddrs do not match: \"%s\" and \"%s\"\n",
+				*candidate,
+				buffer);
+			return AST_TEST_FAIL;
+		}
+
+		candidate++;
+	}
+
+	return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(ast_sockaddr_from_pj_sockaddr_test)
+{
+	char *candidates[] = {
+		"127.0.0.1:5555",
+		"[::]:4444",
+		"192.168.0.100:0",
+		"[fec0::1:80]:0",
+		"[fec0::1]:80",
+		NULL,
+	}, **candidate = candidates;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "ast_sockaddr_from_pj_sockaddr_test";
+		info->category = "/res/res_pjproject/";
+		info->summary = "Validate conversions from a pj_sockaddr to an ast_sockaddr";
+		info->description = "This test converts a pj_sockaddr to an ast_sockaddr and validates\n"
+			"that the two evaluate to the same string when formatted.";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	while (*candidate) {
+		struct ast_sockaddr addr = {{0,}};
+		pj_sockaddr pjaddr;
+		pj_str_t t;
+		char buffer[512];
+
+		fill_with_garbage(&addr, sizeof(addr));
+
+		pj_strset(&t, *candidate, strlen(*candidate));
+
+		if (pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &t, &pjaddr) != PJ_SUCCESS) {
+			ast_test_status_update(test, "Failed to parse candidate IP: %s\n", *candidate);
+			return AST_TEST_FAIL;
+		}
+
+		if (ast_sockaddr_from_pj_sockaddr(&addr, &pjaddr)) {
+			ast_test_status_update(test, "Failed to convert pj_sockaddr to ast_sockaddr: %s\n", *candidate);
+			return AST_TEST_FAIL;
+		}
+
+		snprintf(buffer, sizeof(buffer), "%s", ast_sockaddr_stringify(&addr));
+
+		if (strcmp(*candidate, buffer)) {
+			ast_test_status_update(test, "Converted sockaddrs do not match: \"%s\" and \"%s\"\n",
+				*candidate,
+				buffer);
+			return AST_TEST_FAIL;
+		}
+
+		candidate++;
+	}
+
+	return AST_TEST_PASS;
+}
+#endif
+
 static int load_module(void)
 {
 	ast_debug(3, "Starting PJPROJECT logging to Asterisk logger\n");
@@ -552,6 +724,9 @@
 
 	ast_cli_register_multiple(pjproject_cli, ARRAY_LEN(pjproject_cli));
 
+	AST_TEST_REGISTER(ast_sockaddr_to_pj_sockaddr_test);
+	AST_TEST_REGISTER(ast_sockaddr_from_pj_sockaddr_test);
+
 	return AST_MODULE_LOAD_SUCCESS;
 }
 
@@ -575,6 +750,9 @@
 
 	ast_sorcery_unref(pjproject_sorcery);
 
+	AST_TEST_UNREGISTER(ast_sockaddr_to_pj_sockaddr_test);
+	AST_TEST_UNREGISTER(ast_sockaddr_from_pj_sockaddr_test);
+
 	return 0;
 }
 
diff --git a/res/res_pjproject.exports.in b/res/res_pjproject.exports.in
index f1821a6..c823197 100644
--- a/res/res_pjproject.exports.in
+++ b/res/res_pjproject.exports.in
@@ -1,6 +1,6 @@
 {
 	global:
-		LINKER_SYMBOL_PREFIXast_pjproject_*;
+		LINKER_SYMBOL_PREFIXast_*;
 	local:
 		*;
 };

-- 
To view, visit https://gerrit.asterisk.org/10013
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 13
Gerrit-MessageType: merged
Gerrit-Change-Id: If0fc4bba9643f755604c6ffbb0d7cc46020bc761
Gerrit-Change-Number: 10013
Gerrit-PatchSet: 6
Gerrit-Owner: Sean Bright <sean.bright at gmail.com>
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Jaco Kroon <jaco at uls.co.za>
Gerrit-Reviewer: Jenkins2
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Kevin Harwell <kharwell at digium.com>
Gerrit-Reviewer: Michael L. Young <elgueromexicano at gmail.com>
Gerrit-Reviewer: Richard Mudgett <rmudgett at digium.com>
Gerrit-Reviewer: Sean Bright <sean.bright at gmail.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20180907/b96b69f5/attachment-0001.html>


More information about the asterisk-code-review mailing list