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
This commit is contained in:
parent
16df182155
commit
600c5d79fd
|
@ -22,6 +22,8 @@
|
|||
#include <pj/types.h>
|
||||
#include <pj/pool.h>
|
||||
|
||||
struct ast_sockaddr;
|
||||
|
||||
/*!
|
||||
* \brief Retrieve a pjproject build option
|
||||
*
|
||||
|
@ -97,4 +99,28 @@ void ast_pjproject_caching_pool_init(pj_caching_pool *cp,
|
|||
*/
|
||||
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 */
|
||||
|
|
|
@ -110,6 +110,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;
|
||||
|
@ -471,6 +473,176 @@ void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
|
|||
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");
|
||||
|
@ -540,6 +712,9 @@ static int load_module(void)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -563,6 +738,9 @@ static int unload_module(void)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
global:
|
||||
LINKER_SYMBOL_PREFIXast_pjproject_*;
|
||||
LINKER_SYMBOL_PREFIXast_*;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue