#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;
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");
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;
}
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;
}