Fixed #2032: NAT64 support for IPv4 interoperability

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@5636 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Sauw Ming 2017-08-02 02:51:59 +00:00
parent 494f58b07d
commit e34fa7ed5e
22 changed files with 499 additions and 177 deletions

View File

@ -210,6 +210,11 @@ typedef struct pjstun_setting
* insert magic cookie (specified in RFC 5389) in the transaction ID.
*/
pj_bool_t use_stun2;
/**
* Address family of the STUN servers.
*/
int af;
/**
* Host name or IP address string of the first STUN server.

View File

@ -63,7 +63,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr2(pj_pool_factory *pf,
unsigned srv_cnt;
const pj_str_t *srv1, *srv2;
int port1, port2;
pj_sockaddr_in srv_addr[2];
pj_sockaddr srv_addr[2];
int i, send_cnt = 0, nfds;
pj_pool_t *pool;
struct query_rec {
@ -116,20 +116,19 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr2(pj_pool_factory *pf,
TRACE_((THIS_FILE, " Binding request created."));
/* Resolve servers. */
status = pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1);
status = pj_sockaddr_init(opt->af, &srv_addr[0], srv1, (pj_uint16_t)port1);
if (status != PJ_SUCCESS)
goto on_error;
srv_cnt = 1;
if (srv2 && port2) {
status = pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2);
status = pj_sockaddr_init(opt->af, &srv_addr[1], srv2,
(pj_uint16_t)port2);
if (status != PJ_SUCCESS)
goto on_error;
if (srv_addr[1].sin_addr.s_addr != srv_addr[0].sin_addr.s_addr &&
srv_addr[1].sin_port != srv_addr[0].sin_port)
{
if (pj_sockaddr_cmp(&srv_addr[1], &srv_addr[0]) != 0) {
srv_cnt++;
}
}
@ -181,7 +180,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr2(pj_pool_factory *pf,
sent_len = out_msg_len;
status = pj_sock_sendto(sock[i], out_msg, &sent_len, 0,
(pj_sockaddr_t*)&srv_addr[j],
sizeof(pj_sockaddr_in));
pj_sockaddr_get_len(&srv_addr[j]));
}
}
@ -221,7 +220,7 @@ PJ_DEF(pj_status_t) pjstun_get_mapped_addr2(pj_pool_factory *pf,
int sock_idx, srv_idx;
pj_ssize_t len;
pjstun_msg msg;
pj_sockaddr_in addr;
pj_sockaddr addr;
int addrlen = sizeof(addr);
pjstun_mapped_addr_attr *attr;
char recv_buf[128];

View File

@ -933,6 +933,24 @@ PJ_DECL(void) pj_sockaddr_copy_addr(pj_sockaddr *dst,
*/
PJ_DECL(void) pj_sockaddr_cp(pj_sockaddr_t *dst, const pj_sockaddr_t *src);
/*
* If the source's and desired address family matches, copy the address,
* otherwise synthesize a new address with the desired address family,
* from the source address. This can be useful to generate an IPv4-mapped
* IPv6 address.
*
* @param dst_af Desired address family.
* @param dst Destination socket address, invalid if synthesis is
* required and failed.
* @param src Source socket address.
*
* @return PJ_SUCCESS on success, or the error status
* if synthesis is required and failed.
*/
PJ_DECL(pj_status_t) pj_sockaddr_synthesize(int dst_af,
pj_sockaddr_t *dst,
const pj_sockaddr_t *src);
/**
* Get the IP address of an IPv4 socket address.
* The address is returned as 32bit value in host byte order.

View File

@ -415,6 +415,40 @@ PJ_DEF(void) pj_sockaddr_cp(pj_sockaddr_t *dst, const pj_sockaddr_t *src)
pj_memcpy(dst, src, pj_sockaddr_get_len(src));
}
/*
* Synthesize address.
*/
PJ_DEF(pj_status_t) pj_sockaddr_synthesize(int dst_af,
pj_sockaddr_t *dst,
const pj_sockaddr_t *src)
{
char ip_addr_buf[PJ_INET6_ADDRSTRLEN];
unsigned int count = 1;
pj_addrinfo ai[1];
pj_str_t ip_addr;
pj_status_t status;
/* Validate arguments */
PJ_ASSERT_RETURN(src && dst, PJ_EINVAL);
if (dst_af == ((const pj_sockaddr *)src)->addr.sa_family) {
pj_sockaddr_cp(dst, src);
return PJ_SUCCESS;
}
pj_sockaddr_print(src, ip_addr_buf, sizeof(ip_addr_buf), 0);
ip_addr = pj_str(ip_addr_buf);
/* Try to synthesize address using pj_getaddrinfo(). */
status = pj_getaddrinfo(dst_af, &ip_addr, &count, ai);
if (status == PJ_SUCCESS && count > 0) {
pj_sockaddr_cp(dst, &ai[0].ai_addr);
pj_sockaddr_set_port(dst, pj_sockaddr_get_port(src));
}
return status;
}
/*
* Set port number of pj_sockaddr_in
*/

View File

@ -652,6 +652,9 @@ static pj_status_t transport_attach( pjmedia_transport *tp,
{
struct transport_udp *udp = (struct transport_udp*) tp;
const pj_sockaddr *rtcp_addr;
pj_sockaddr sock_addr, remote_addr, remote_rtcp;
int rem_addr_len;
pj_status_t status;
/* Validate arguments */
PJ_ASSERT_RETURN(tp && rem_addr && addr_len, PJ_EINVAL);
@ -667,19 +670,39 @@ static pj_status_t transport_attach( pjmedia_transport *tp,
/* "Attach" the application: */
rem_addr_len = sizeof(pj_sockaddr);
pj_sock_getsockname(udp->rtp_sock, &sock_addr, &rem_addr_len);
/* Synthesize address, if necessary. */
status = pj_sockaddr_synthesize(sock_addr.addr.sa_family,
&remote_addr, rem_addr);
if (status != PJ_SUCCESS) {
pj_perror(3, tp->name, status, "Failed to synthesize the correct"
"IP address for RTP");
}
rem_addr_len = pj_sockaddr_get_len(&remote_addr);
/* Copy remote RTP address */
pj_memcpy(&udp->rem_rtp_addr, rem_addr, addr_len);
pj_memcpy(&udp->rem_rtp_addr, &remote_addr, rem_addr_len);
/* Copy remote RTP address, if one is specified. */
rtcp_addr = (const pj_sockaddr*) rem_rtcp;
if (rtcp_addr && pj_sockaddr_has_addr(rtcp_addr)) {
pj_memcpy(&udp->rem_rtcp_addr, rem_rtcp, addr_len);
pj_status_t status;
status = pj_sockaddr_synthesize(sock_addr.addr.sa_family,
&remote_rtcp, rem_rtcp);
if (status != PJ_SUCCESS) {
pj_perror(3, tp->name, status, "Failed to synthesize the correct"
"IP address for RTCP");
}
pj_memcpy(&udp->rem_rtcp_addr, &remote_rtcp, rem_addr_len);
} else {
unsigned rtcp_port;
/* Otherwise guess the RTCP address from the RTP address */
pj_memcpy(&udp->rem_rtcp_addr, rem_addr, addr_len);
pj_memcpy(&udp->rem_rtcp_addr, &udp->rem_rtp_addr, rem_addr_len);
rtcp_port = pj_sockaddr_get_port(&udp->rem_rtp_addr) + 1;
pj_sockaddr_set_port(&udp->rem_rtcp_addr, (pj_uint16_t)rtcp_port);
}
@ -690,7 +713,7 @@ static pj_status_t transport_attach( pjmedia_transport *tp,
udp->user_data = user_data;
/* Save address length */
udp->addr_len = addr_len;
udp->addr_len = rem_addr_len;
/* Last, mark transport as attached */
//udp->attached = PJ_TRUE;

View File

@ -2185,6 +2185,7 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
pj_ice_sess_cand *lcand;
pj_ice_sess_checklist *clist;
pj_stun_xor_mapped_addr_attr *xaddr;
const pj_sockaddr_t *source_addr = src_addr;
unsigned i;
PJ_UNUSED_ARG(stun_sess);
@ -2286,8 +2287,26 @@ static void on_stun_request_complete(pj_stun_session *stun_sess,
* the response match the source IP address and port that the Binding
* Request was sent from.
*/
if (pj_sockaddr_cmp(&check->rcand->addr, (const pj_sockaddr*)src_addr)!=0)
if (check->rcand->addr.addr.sa_family == pj_AF_INET() &&
((pj_sockaddr *)src_addr)->addr.sa_family == pj_AF_INET6())
{
/* If the address family is different, we need to check
* whether the two addresses are equivalent (i.e. the IPv6
* is synthesized from IPv4).
*/
pj_sockaddr synth_addr;
pj_status_t status;
status = pj_sockaddr_synthesize(pj_AF_INET6(), &synth_addr,
&check->rcand->addr);
if (status == PJ_SUCCESS &&
pj_sockaddr_cmp(&synth_addr, src_addr) == 0)
{
source_addr = &check->rcand->addr;
}
}
if (pj_sockaddr_cmp(&check->rcand->addr, source_addr) != 0) {
status = PJNATH_EICEINSRCADDR;
LOG4((ice->obj_name,
"Check %s%s: connectivity check FAILED: source address mismatch",
@ -2474,6 +2493,8 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
pj_stun_uint64_attr *role_attr;
pj_stun_tx_data *tdata;
pj_ice_rx_check *rcheck, tmp_rcheck;
const pj_sockaddr_t *source_addr = src_addr;
unsigned source_addr_len = src_addr_len;
pj_status_t status;
PJ_UNUSED_ARG(pkt);
@ -2587,10 +2608,54 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
return status;
}
if (((pj_sockaddr *)src_addr)->addr.sa_family == pj_AF_INET6()) {
unsigned i;
unsigned transport_id = ((pj_ice_msg_data*)token)->transport_id;
pj_ice_sess_cand *lcand = NULL;
for (i = 0; i < ice->clist.count; ++i) {
pj_ice_sess_check *c = &ice->clist.checks[i];
if (c->lcand->comp_id == sd->comp_id &&
c->lcand->transport_id == transport_id)
{
lcand = c->lcand;
break;
}
}
if (lcand != NULL && lcand->addr.addr.sa_family == pj_AF_INET()) {
/* We are behind NAT64, so src_addr is a synthesized IPv6
* address. Instead of putting this synth IPv6 address as
* the XOR-MAPPED-ADDRESS, we need to find its original
* IPv4 address.
*/
for (i = 0; i < ice->rcand_cnt; ++i) {
pj_status_t status;
pj_sockaddr synth_addr;
if (ice->rcand[i].addr.addr.sa_family != pj_AF_INET())
continue;
status = pj_sockaddr_synthesize(pj_AF_INET6(), &synth_addr,
&ice->rcand[i].addr);
if (status == PJ_SUCCESS &&
pj_sockaddr_cmp(src_addr, &synth_addr) == 0)
{
/* We find the original IPv4 address. */
source_addr = &ice->rcand[i].addr;
source_addr_len = pj_sockaddr_get_len(source_addr);
break;
}
}
}
}
/* Add XOR-MAPPED-ADDRESS attribute */
status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
PJ_TRUE, src_addr, src_addr_len);
PJ_TRUE, source_addr,
source_addr_len);
/* Create a msg_data to be associated with this response */
msg_data = PJ_POOL_ZALLOC_T(tdata->pool, pj_ice_msg_data);
@ -2619,8 +2684,8 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
/* Init rcheck */
rcheck->comp_id = sd->comp_id;
rcheck->transport_id = ((pj_ice_msg_data*)token)->transport_id;
rcheck->src_addr_len = src_addr_len;
pj_sockaddr_cp(&rcheck->src_addr, src_addr);
rcheck->src_addr_len = source_addr_len;
pj_sockaddr_cp(&rcheck->src_addr, source_addr);
rcheck->use_candidate = (uc_attr != NULL);
rcheck->priority = prio_attr->value;
rcheck->role_attr = role_attr;

View File

@ -168,6 +168,11 @@ typedef struct pj_ice_strans_comp
unsigned cand_cnt; /**< # of candidates/aliaes. */
pj_ice_sess_cand cand_list[PJ_ICE_ST_MAX_CAND]; /**< Cand array */
pj_bool_t ipv4_mapped; /**< Is IPv6 addr mapped to IPv4?*/
pj_sockaddr dst_addr; /**< Destination address */
pj_sockaddr synth_addr; /**< Synthesized dest address */
unsigned synth_addr_len;/**< Synthesized dest addr len */
unsigned default_cand; /**< Default candidate. */
} pj_ice_strans_comp;
@ -654,7 +659,8 @@ static pj_status_t add_stun_and_host(pj_ice_strans *ice_st,
* address family
*/
if (comp->ice_st->cfg.af != pj_AF_UNSPEC() &&
comp->cand_list[comp->default_cand].addr.addr.sa_family !=
addr->addr.sa_family == comp->ice_st->cfg.af &&
comp->cand_list[comp->default_cand].base_addr.addr.sa_family !=
ice_st->cfg.af)
{
comp->default_cand = (unsigned)(cand - comp->cand_list);
@ -1134,6 +1140,15 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
/* Must have address */
pj_assert(pj_sockaddr_has_addr(&cand->addr));
/* Skip if we are mapped to IPv4 address and this candidate
* is not IPv4.
*/
if (comp->ipv4_mapped &&
cand->addr.addr.sa_family != pj_AF_INET())
{
continue;
}
/* Add the candidate */
status = pj_ice_sess_add_cand(ice_st->ice, comp->comp_id,
cand->transport_id, cand->type,
@ -1500,9 +1515,33 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st,
return (status==PJ_SUCCESS||status==PJ_EPENDING) ?
PJ_SUCCESS : status;
} else {
const pj_sockaddr_t *dest_addr;
unsigned dest_addr_len;
if (comp->ipv4_mapped) {
if (comp->synth_addr_len == 0 ||
pj_sockaddr_cmp(&comp->dst_addr, dst_addr) != 0)
{
status = pj_sockaddr_synthesize(pj_AF_INET6(),
&comp->synth_addr,
dst_addr);
if (status != PJ_SUCCESS)
return status;
pj_sockaddr_cp(&comp->dst_addr, dst_addr);
comp->synth_addr_len = pj_sockaddr_get_len(
&comp->synth_addr);
}
dest_addr = &comp->synth_addr;
dest_addr_len = comp->synth_addr_len;
} else {
dest_addr = dst_addr;
dest_addr_len = dst_addr_len;
}
status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, data,
(unsigned)data_len, 0, dst_addr,
dst_addr_len);
(unsigned)data_len, 0, dest_addr,
dest_addr_len);
return (status==PJ_SUCCESS||status==PJ_EPENDING) ?
PJ_SUCCESS : status;
}
@ -1649,9 +1688,31 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
status = PJ_EINVALIDOP;
}
} else if (tp_typ == TP_STUN) {
const pj_sockaddr_t *dest_addr;
unsigned dest_addr_len;
if (comp->ipv4_mapped) {
if (comp->synth_addr_len == 0 ||
pj_sockaddr_cmp(&comp->dst_addr, dst_addr) != 0)
{
status = pj_sockaddr_synthesize(pj_AF_INET6(),
&comp->synth_addr, dst_addr);
if (status != PJ_SUCCESS)
return status;
pj_sockaddr_cp(&comp->dst_addr, dst_addr);
comp->synth_addr_len = pj_sockaddr_get_len(&comp->synth_addr);
}
dest_addr = &comp->synth_addr;
dest_addr_len = comp->synth_addr_len;
} else {
dest_addr = dst_addr;
dest_addr_len = dst_addr_len;
}
status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL,
pkt, (unsigned)size, 0,
dst_addr, dst_addr_len);
dest_addr, dest_addr_len);
} else {
pj_assert(!"Invalid transport ID");
status = PJ_EINVALIDOP;
@ -1819,6 +1880,41 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock,
"srflx address changed";
pj_bool_t dup = PJ_FALSE;
if (info.mapped_addr.addr.sa_family == pj_AF_INET() &&
cand->base_addr.addr.sa_family == pj_AF_INET6())
{
/* We get an IPv4 mapped address for our IPv6
* host address.
*/
comp->ipv4_mapped = PJ_TRUE;
/* Find other host candidates with the same (IPv6)
* address, and replace it with the new (IPv4)
* mapped address.
*/
for (i = 0; i < comp->cand_cnt; ++i) {
pj_sockaddr *a1, *a2;
if (comp->cand_list[i].type != PJ_ICE_CAND_TYPE_HOST)
continue;
a1 = &comp->cand_list[i].addr;
a2 = &cand->base_addr;
if (pj_memcmp(pj_sockaddr_get_addr(a1),
pj_sockaddr_get_addr(a2),
pj_sockaddr_get_addr_len(a1)) == 0)
{
pj_uint16_t port = pj_sockaddr_get_port(a1);
pj_sockaddr_cp(a1, &info.mapped_addr);
if (port != pj_sockaddr_get_port(a2))
pj_sockaddr_set_port(a1, port);
pj_sockaddr_cp(&comp->cand_list[i].base_addr, a1);
}
}
pj_sockaddr_cp(&cand->base_addr, &info.mapped_addr);
pj_sockaddr_cp(&cand->rel_addr, &info.mapped_addr);
}
/* Eliminate the srflx candidate if the address is
* equal to other (host) candidates.
*/

View File

@ -88,6 +88,7 @@ typedef struct nat_detect_session
pj_ioqueue_key_t *key;
pj_sockaddr server;
pj_sockaddr *cur_server;
pj_sockaddr cur_addr;
pj_stun_session *stun_sess;
pj_ioqueue_op_key_t read_op, write_op;
@ -854,11 +855,17 @@ static pj_status_t send_test(nat_detect_session *sess,
if (status != PJ_SUCCESS)
goto on_error;
/* Configure alternate address */
if (alt_addr)
sess->cur_server = (pj_sockaddr*) alt_addr;
else
/* Configure alternate address, synthesize it if necessary */
if (alt_addr) {
status = pj_sockaddr_synthesize(sess->server.addr.sa_family,
&sess->cur_addr, alt_addr);
if (status != PJ_SUCCESS)
goto on_error;
sess->cur_server = &sess->cur_addr;
} else {
sess->cur_server = &sess->server;
}
PJ_LOG(5,(sess->pool->obj_name,
"Performing %s to %s:%d",

View File

@ -677,7 +677,7 @@ PJ_DEF(pj_status_t) pj_turn_session_set_server( pj_turn_session *sess,
pj_sockaddr *addr = &sess->srv_addr_list[i];
pj_memcpy(addr, &ai[i].ai_addr, sizeof(pj_sockaddr));
addr->addr.sa_family = sess->af;
addr->ipv4.sin_port = pj_htons(sess->default_port);
pj_sockaddr_set_port(addr, sess->default_port);
}
sess->srv_addr = &sess->srv_addr_list[0];

View File

@ -153,6 +153,8 @@ typedef enum pjsua_sip_timer_use {PJSUA_SIP_TIMER_INACTIVE, PJSUA_SIP_TIMER_OPTI
typedef enum pjsua_ipv6_use {PJSUA_IPV6_DISABLED, PJSUA_IPV6_ENABLED} pjsua_ipv6_use;
typedef enum pjsua_nat64_opt {PJSUA_NAT64_DISABLED, PJSUA_NAT64_ENABLED} pjsua_nat64_opt;
typedef enum pjsua_buddy_status {PJSUA_BUDDY_STATUS_UNKNOWN, PJSUA_BUDDY_STATUS_ONLINE, PJSUA_BUDDY_STATUS_OFFLINE} pjsua_buddy_status;
typedef enum pjsua_call_media_status {PJSUA_CALL_MEDIA_NONE, PJSUA_CALL_MEDIA_ACTIVE, PJSUA_CALL_MEDIA_LOCAL_HOLD, PJSUA_CALL_MEDIA_REMOTE_HOLD, PJSUA_CALL_MEDIA_ERROR} pjsua_call_media_status;

View File

@ -33,4 +33,4 @@ pjsip-simple/evsub.h pjsip_evsub_state
pjsip-ua/sip_inv.h pjsip_inv_state
pjsua-lib/pjsua.h pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag pjsua_snd_dev_mode
pjsua-lib/pjsua.h pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_nat64_opt pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag pjsua_snd_dev_mode

View File

@ -1594,6 +1594,15 @@ typedef struct pjsua_config
*/
pj_str_t stun_srv[8];
/**
* This specifies if the library should try to do an IPv6 resolution of
* the STUN servers if the IPv4 resolution fails. It can be useful
* in an IPv6-only environment, including on NAT64.
*
* Default: PJ_FALSE
*/
pj_bool_t stun_try_ipv6;
/**
* This specifies if the library should ignore failure with the
* STUN servers. If this is set to PJ_FALSE, the library will refuse to
@ -2909,6 +2918,23 @@ typedef enum pjsua_ipv6_use
} pjsua_ipv6_use;
/**
* Specify NAT64 options to be used in account config.
*/
typedef enum pjsua_nat64_opt
{
/**
* NAT64 is not used.
*/
PJSUA_NAT64_DISABLED,
/**
* NAT64 is enabled.
*/
PJSUA_NAT64_ENABLED
} pjsua_nat64_opt;
/**
* This structure describes account configuration to be specified when
* adding a new account with #pjsua_acc_add(). Application MUST initialize
@ -3346,6 +3372,13 @@ typedef struct pjsua_acc_config
*/
pjsua_transport_config rtp_cfg;
/**
* Specify NAT64 options.
*
* Default: PJSUA_NAT64_DISABLED
*/
pjsua_nat64_opt nat64_opt;
/**
* Specify whether IPv6 should be used on media.
*/

View File

@ -374,6 +374,7 @@ typedef struct pjsua_stun_resolve
pj_status_t status; /**< Session status */
pj_sockaddr addr; /**< Result */
pj_stun_sock *stun_sock; /**< Testing STUN sock */
int af; /**< Address family */
pj_bool_t async_wait;/**< Async resolution
of STUN entry */
} pjsua_stun_resolve;

View File

@ -468,6 +468,13 @@ struct AccountNatConfig : public PersistentObject
*/
pjsua_stun_use mediaStunUse;
/**
* Specify NAT64 options.
*
* Default: PJSUA_NAT64_DISABLED
*/
pjsua_nat64_opt nat64Opt;
/**
* Enable ICE for the media transport.
*

View File

@ -390,6 +390,15 @@ struct UaConfig : public PersistentObject
*/
StringVector stunServer;
/**
* This specifies if the library should try to do an IPv6 resolution of
* the STUN servers if the IPv4 resolution fails. It can be useful
* in an IPv6-only environment, including on NAT64.
*
* Default: FALSE
*/
bool stunTryIpv6;
/**
* This specifies if the library startup should ignore failure with the
* STUN servers. If this is set to PJ_FALSE, the library will refuse to

View File

@ -700,7 +700,7 @@ static pj_status_t transport_attach( pjsip_endpoint *endpt,
{
pj_pool_t *pool;
struct udp_transport *tp;
const char *format, *ipv6_quoteb, *ipv6_quotee;
const char *format, *ipv6_quoteb = "", *ipv6_quotee = "";
unsigned i;
pj_status_t status;
@ -709,12 +709,18 @@ static pj_status_t transport_attach( pjsip_endpoint *endpt,
/* Object name. */
if (type & PJSIP_TRANSPORT_IPV6) {
pj_in6_addr dummy6;
format = "udpv6%p";
ipv6_quoteb = "[";
ipv6_quotee = "]";
/* We don't need to add quote if the transport type is IPv6, but
* actually translated to IPv4.
*/
if (pj_inet_pton(pj_AF_INET6(), &a_name->host, &dummy6)==PJ_SUCCESS) {
ipv6_quoteb = "[";
ipv6_quotee = "]";
}
} else {
format = "udp%p";
ipv6_quoteb = ipv6_quotee = "";
}
/* Create pool. */

View File

@ -1219,7 +1219,8 @@ static void stateless_send_transport_cb( void *token,
* request.
*/
if (tdata->via_addr.host.slen > 0 &&
(tdata->via_tp == (void *)stateless_data->cur_transport ||
(!tdata->via_tp ||
tdata->via_tp == (void *)stateless_data->cur_transport ||
tdata->msg->line.req.method.id == PJSIP_CANCEL_METHOD))
{
via->sent_by = tdata->via_addr;

View File

@ -32,6 +32,7 @@ enum
};
static int get_ip_addr_ver(const pj_str_t *host);
static void schedule_reregistration(pjsua_acc *acc);
static void keep_alive_timer_cb(pj_timer_heap_t *th, pj_timer_entry *te);
@ -547,7 +548,7 @@ PJ_DEF(pj_status_t) pjsua_acc_add_local( pjsua_transport_id tid,
--cfg.priority;
/* Enclose IPv6 address in square brackets */
if (t->type & PJSIP_TRANSPORT_IPV6) {
if (get_ip_addr_ver(&t->local_name.host) == 6) {
beginquote = "[";
endquote = "]";
} else {
@ -1325,6 +1326,7 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
acc->cfg.rtp_cfg.bound_addr = b_addr;
}
acc->cfg.nat64_opt = cfg->nat64_opt;
acc->cfg.ipv6_media_use = cfg->ipv6_media_use;
/* STUN and Media customization */
@ -1696,9 +1698,12 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc,
if (status == PJ_SUCCESS) {
/* Compare the addresses as sockaddr according to the ticket above,
* but only if they have the same family (ipv4 vs ipv4, or
* ipv6 vs ipv6)
* ipv6 vs ipv6).
* Checking for the same address family is currently disabled,
* since it can be useful in cases such as when on NAT64,
* in order to get the IPv4-mapped address from IPv6.
*/
matched = (contact_addr.addr.sa_family != recv_addr.addr.sa_family) ||
matched = //(contact_addr.addr.sa_family != recv_addr.addr.sa_family)||
(uri->port == rport &&
pj_sockaddr_cmp(&contact_addr, &recv_addr)==0);
} else {
@ -3114,6 +3119,7 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id,
pjsip_tpselector tp_sel;
pjsip_tpmgr *tpmgr;
pjsip_tpmgr_fla2_param tfla2_prm;
pj_bool_t update_addr = PJ_TRUE;
PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL);
acc = &pjsua_var.acc[acc_id];
@ -3183,6 +3189,25 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id,
addr->host = tfla2_prm.ret_addr;
addr->port = tfla2_prm.ret_port;
/* If we are behind NAT64, use the Contact and Via address from
* the UDP6 transport, which should be obtained from STUN.
*/
if (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED) {
pjsip_tpmgr_fla2_param tfla2_prm2 = tfla2_prm;
tfla2_prm2.tp_type = PJSIP_TRANSPORT_UDP6;
tfla2_prm2.tp_sel = NULL;
tfla2_prm2.local_if = (!pjsua_sip_acc_is_using_stun(acc_id));
status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &tfla2_prm2);
if (status == PJ_SUCCESS) {
update_addr = PJ_FALSE;
addr->host = tfla2_prm2.ret_addr;
pj_strdup(acc->pool, &acc->via_addr.host, &addr->host);
acc->via_addr.port = addr->port;
acc->via_tp = (pjsip_transport *)tfla2_prm.ret_tp;
}
}
/* For TCP/TLS, acc may request to specify source port */
if (acc->cfg.contact_use_src_port) {
pjsip_host_info dinfo;
@ -3276,8 +3301,12 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id,
}
if (status == PJ_SUCCESS) {
/* Got the local transport address */
pj_strdup(pool, &addr->host, &tp->local_name.host);
/* Got the local transport address, don't update if
* we are on NAT64 and already obtained the address
* from STUN above.
*/
if (update_addr)
pj_strdup(pool, &addr->host, &tp->local_name.host);
addr->port = tp->local_name.port;
}

View File

@ -1297,9 +1297,14 @@ static pj_bool_t test_stun_on_status(pj_stun_sock *stun_sock,
stun_resolve_add_ref(sess);
++sess->idx;
if (sess->idx >= sess->count)
sess->status = status;
if (pjsua_var.ua_cfg.stun_try_ipv6 && sess->af == pj_AF_INET()) {
sess->af = pj_AF_INET6();
} else {
++sess->idx;
sess->af = pj_AF_INET();
if (sess->idx >= sess->count)
sess->status = status;
}
resolve_stun_entry(sess);
@ -1339,7 +1344,10 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess)
pj_status_t status = PJ_EUNKNOWN;
/* Loop while we have entry to try */
for (; sess->idx < sess->count; ++sess->idx) {
for (; sess->idx < sess->count;
(pjsua_var.ua_cfg.stun_try_ipv6 && sess->af == pj_AF_INET())?
sess->af = pj_AF_INET6(): (++sess->idx, sess->af = pj_AF_INET()))
{
int af;
char target[64];
pj_str_t hostpart;
@ -1358,14 +1366,6 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess)
if (status != PJ_SUCCESS) {
PJ_LOG(2,(THIS_FILE, "Invalid STUN server entry %s", target));
continue;
} else if (af != pj_AF_INET()) {
/* Ignore IPv6 STUN server for now */
status = PJ_EAFNOTSUP;
PJ_LOG(3,(THIS_FILE, "Ignored STUN server entry %s, currently "
"only IPv4 STUN server is supported (does "
"IPv6 still need a mapped address?)",
target));
continue;
}
/* Use default port if not specified */
@ -1374,15 +1374,16 @@ static void resolve_stun_entry(pjsua_stun_resolve *sess)
pj_assert(sess->stun_sock == NULL);
PJ_LOG(4,(THIS_FILE, "Trying STUN server %s (%d of %d)..",
target, sess->idx+1, sess->count));
PJ_LOG(4,(THIS_FILE, "Trying STUN server %s %s (%d of %d)..",
target, (sess->af == pj_AF_INET()? "IPv4": "IPv6"),
sess->idx+1, sess->count));
/* Use STUN_sock to test this entry */
pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
stun_sock_cb.on_status = &test_stun_on_status;
sess->async_wait = PJ_FALSE;
status = pj_stun_sock_create(&pjsua_var.stun_cfg, "stunresolve",
pj_AF_INET(), &stun_sock_cb,
sess->af, &stun_sock_cb,
NULL, sess, &sess->stun_sock);
if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
@ -1488,6 +1489,7 @@ PJ_DEF(pj_status_t) pjsua_resolve_stun_servers( unsigned count,
sess->blocking = wait;
sess->waiter = pj_thread_this();
sess->status = PJ_EPENDING;
sess->af = pj_AF_INET();
sess->srv = (pj_str_t*) pj_pool_calloc(pool, count, sizeof(pj_str_t));
for (i=0; i<count; ++i) {
pj_strdup(pool, &sess->srv[i], &srv[i]);
@ -2157,18 +2159,22 @@ static pj_status_t create_sip_udp_sock(int af,
if (pj_sockaddr_get_port(p_pub_addr) == 0)
pj_sockaddr_set_port(p_pub_addr, (pj_uint16_t)port);
} else if (stun_srv.slen && af == pj_AF_INET()) {
} else if (stun_srv.slen &&
(af == pj_AF_INET() || pjsua_var.ua_cfg.stun_try_ipv6))
{
pjstun_setting stun_opt;
/*
* STUN is specified, resolve the address with STUN.
* Currently, this is available for IPv4 address only.
* Currently, this is only to get IPv4 mapped address
* (does IPv6 still need a mapped address?).
*/
pj_bzero(&stun_opt, sizeof(stun_opt));
stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
stun_opt.af = pjsua_var.stun_srv.addr.sa_family;
stun_opt.srv1 = stun_opt.srv2 = stun_srv;
stun_opt.port1 = stun_opt.port2 =
pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
pj_sockaddr_get_port(&pjsua_var.stun_srv);
status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
1, &sock, &p_pub_addr->ipv4);
if (status != PJ_SUCCESS) {
@ -2894,14 +2900,14 @@ PJ_DEF(pj_status_t) pjsua_detect_nat_type()
}
/* Make sure we have STUN */
if (pjsua_var.stun_srv.ipv4.sin_family == 0) {
if (pjsua_var.stun_srv.addr.sa_family == 0) {
pjsua_var.nat_status = PJNATH_ESTUNINSERVER;
return PJNATH_ESTUNINSERVER;
}
status = pj_stun_detect_nat_type(&pjsua_var.stun_srv.ipv4,
&pjsua_var.stun_cfg,
NULL, &nat_detect_cb);
status = pj_stun_detect_nat_type2(&pjsua_var.stun_srv,
&pjsua_var.stun_cfg,
NULL, &nat_detect_cb);
if (status != PJ_SUCCESS) {
pjsua_var.nat_status = status;

View File

@ -240,7 +240,7 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
RTP_RETRY = 100
};
int i;
pj_bool_t use_ipv6;
pj_bool_t use_ipv6, use_nat64;
int af;
pj_sockaddr bound_addr;
pj_sockaddr mapped_addr[2];
@ -250,10 +250,13 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
pj_sock_t sock[2];
use_ipv6 = (acc->cfg.ipv6_media_use != PJSUA_IPV6_DISABLED);
af = use_ipv6 ? pj_AF_INET6() : pj_AF_INET();
use_nat64 = (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED);
af = (use_ipv6 || use_nat64) ? pj_AF_INET6() : pj_AF_INET();
/* Make sure STUN server resolution has completed */
if (!use_ipv6 && pjsua_media_acc_is_using_stun(call_med->call->acc_id)) {
if ((!use_ipv6 || use_nat64) &&
pjsua_media_acc_is_using_stun(call_med->call->acc_id))
{
pj_bool_t retry_stun = (acc->cfg.media_stun_use &
PJSUA_STUN_RETRY_ON_FAILURE) ==
PJSUA_STUN_RETRY_ON_FAILURE;
@ -353,11 +356,11 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
* If we're configured to use STUN, then find out the mapped address,
* and make sure that the mapped RTCP port is adjacent with the RTP.
*/
if (!use_ipv6 &&
if ((!use_ipv6 || use_nat64) &&
pjsua_media_acc_is_using_stun(call_med->call->acc_id) &&
pjsua_var.stun_srv.addr.sa_family != 0)
{
char ip_addr[32];
char ip_addr[PJ_INET6_ADDRSTRLEN];
pj_str_t stun_srv;
pj_sockaddr_in resolved_addr[2];
pjstun_setting stun_opt;
@ -367,9 +370,10 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
pj_bzero(&stun_opt, sizeof(stun_opt));
stun_opt.use_stun2 = pjsua_var.ua_cfg.stun_map_use_stun2;
stun_opt.af = pjsua_var.stun_srv.addr.sa_family;
stun_opt.srv1 = stun_opt.srv2 = stun_srv;
stun_opt.port1 = stun_opt.port2 =
pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
pj_sockaddr_get_port(&pjsua_var.stun_srv);
status=pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
2, sock, resolved_addr);
#if defined(PJ_IPHONE_OS_HAS_MULTITASKING_SUPPORT) && \
@ -432,9 +436,10 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
stun_srv.slen = 0;
}
stun_opt.af = pjsua_var.stun_srv.addr.sa_family;
stun_opt.srv1 = stun_opt.srv2 = stun_srv;
stun_opt.port1 = stun_opt.port2 =
pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
pj_sockaddr_get_port(&pjsua_var.stun_srv);
status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory,
&stun_opt, 2, sock,
resolved_addr);
@ -823,10 +828,11 @@ static pj_status_t create_ice_media_transport(
char name[32];
unsigned comp_cnt;
pj_status_t status;
pj_bool_t use_ipv6;
pj_bool_t use_ipv6, use_nat64;
acc_cfg = &pjsua_var.acc[call_med->call->acc_id].cfg;
use_ipv6 = (acc_cfg->ipv6_media_use != PJSUA_IPV6_DISABLED);
use_nat64 = (acc_cfg->nat64_opt != PJSUA_NAT64_DISABLED);
/* Make sure STUN server resolution has completed */
if (pjsua_media_acc_is_using_stun(call_med->call->acc_id)) {
@ -863,7 +869,7 @@ static pj_status_t create_ice_media_transport(
if (pj_stricmp(&c->addr_type, &ID_IP6) == 0)
ice_cfg.af = pj_AF_INET6();
} else if (use_ipv6) {
} else if (use_ipv6 || use_nat64) {
ice_cfg.af = pj_AF_INET6();
}
@ -874,7 +880,9 @@ static pj_status_t create_ice_media_transport(
{
ice_cfg.stun_tp_cnt = 1;
pj_ice_strans_stun_cfg_default(&ice_cfg.stun_tp[0]);
if (use_ipv6 && PJ_ICE_MAX_STUN >= 2) {
if (use_nat64) {
ice_cfg.stun_tp[0].af = pj_AF_INET6();
} else if (use_ipv6 && PJ_ICE_MAX_STUN >= 2) {
ice_cfg.stun_tp_cnt = 2;
pj_ice_strans_stun_cfg_default(&ice_cfg.stun_tp[1]);
ice_cfg.stun_tp[1].af = pj_AF_INET6();
@ -885,72 +893,69 @@ static pj_status_t create_ice_media_transport(
if (ice_cfg.stun_tp_cnt) {
unsigned i;
/* Configure STUN server (currently only for IPv4) */
if (pj_sockaddr_has_addr(&pjsua_var.stun_srv) &&
pjsua_media_acc_is_using_stun(call_med->call->acc_id))
{
pj_sockaddr_print(&pjsua_var.stun_srv, stunip, sizeof(stunip), 0);
ice_cfg.stun_tp[0].server = pj_str(stunip);
ice_cfg.stun_tp[0].port =
pj_sockaddr_get_port(&pjsua_var.stun_srv);
}
pj_sockaddr_print(&pjsua_var.stun_srv, stunip, sizeof(stunip), 0);
/* Configure max host candidates */
if (acc_cfg->ice_cfg.ice_max_host_cands >= 0) {
for (i = 0; i < ice_cfg.stun_tp_cnt; ++i)
for (i = 0; i < ice_cfg.stun_tp_cnt; ++i) {
pj_str_t IN6_ADDR_ANY = {"0", 1};
/* Configure STUN server */
if (pj_sockaddr_has_addr(&pjsua_var.stun_srv) &&
pjsua_media_acc_is_using_stun(call_med->call->acc_id))
{
ice_cfg.stun_tp[i].server = pj_str(stunip);
ice_cfg.stun_tp[i].port = pj_sockaddr_get_port(
&pjsua_var.stun_srv);
}
/* Configure max host candidates */
if (acc_cfg->ice_cfg.ice_max_host_cands >= 0) {
ice_cfg.stun_tp[i].max_host_cands =
acc_cfg->ice_cfg.ice_max_host_cands;
}
}
/* Configure binding address */
pj_sockaddr_init(ice_cfg.stun_tp[0].af,
&ice_cfg.stun_tp[0].cfg.bound_addr,
&cfg->bound_addr, (pj_uint16_t)cfg->port);
ice_cfg.stun_tp[0].cfg.port_range = (pj_uint16_t)cfg->port_range;
if (cfg->port != 0 && ice_cfg.stun_tp[0].cfg.port_range == 0) {
ice_cfg.stun_tp[0].cfg.port_range =
/* Configure binding address */
pj_sockaddr_init(ice_cfg.stun_tp[i].af,
&ice_cfg.stun_tp[i].cfg.bound_addr,
(ice_cfg.stun_tp[i].af == pj_AF_INET()?
&cfg->bound_addr: &IN6_ADDR_ANY),
(pj_uint16_t)cfg->port);
ice_cfg.stun_tp[i].cfg.port_range = (pj_uint16_t)cfg->port_range;
if (cfg->port != 0 && ice_cfg.stun_tp[i].cfg.port_range == 0) {
ice_cfg.stun_tp[i].cfg.port_range =
(pj_uint16_t)(pjsua_var.ua_cfg.max_calls * 10);
}
if (use_ipv6 && ice_cfg.stun_tp_cnt > 1) {
pj_str_t IN6_ADDR_ANY = {"0", 1};
pj_sockaddr_init(pj_AF_INET6(),
&ice_cfg.stun_tp[1].cfg.bound_addr,
&IN6_ADDR_ANY, (pj_uint16_t)cfg->port);
ice_cfg.stun_tp[1].cfg.port_range =
ice_cfg.stun_tp[0].cfg.port_range;
}
}
/* Configure QoS setting */
ice_cfg.stun_tp[0].cfg.qos_type = cfg->qos_type;
pj_memcpy(&ice_cfg.stun_tp[0].cfg.qos_params, &cfg->qos_params,
sizeof(cfg->qos_params));
if (use_ipv6 && ice_cfg.stun_tp_cnt > 1) {
ice_cfg.stun_tp[1].cfg.qos_type = cfg->qos_type;
pj_memcpy(&ice_cfg.stun_tp[1].cfg.qos_params, &cfg->qos_params,
/* Configure QoS setting */
ice_cfg.stun_tp[i].cfg.qos_type = cfg->qos_type;
pj_memcpy(&ice_cfg.stun_tp[i].cfg.qos_params, &cfg->qos_params,
sizeof(cfg->qos_params));
/* Configure max packet size */
ice_cfg.stun_tp[i].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
}
/* Configure max packet size */
ice_cfg.stun_tp[0].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
if (use_ipv6 && ice_cfg.stun_tp_cnt > 1)
ice_cfg.stun_tp[1].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
}
/* Configure TURN settings */
if (acc_cfg->turn_cfg.enable_turn) {
ice_cfg.turn_tp_cnt = 1;
pj_ice_strans_turn_cfg_default(&ice_cfg.turn_tp[0]);
if (use_ipv6 && PJ_ICE_MAX_TURN >= 3) {
ice_cfg.turn_tp_cnt = 3;
unsigned i, idx = 0;
if (use_ipv6 && !use_nat64 && PJ_ICE_MAX_TURN >= 3) {
ice_cfg.turn_tp_cnt = 3;
idx = 1;
} else {
ice_cfg.turn_tp_cnt = 1;
}
for (i = 0; i < ice_cfg.turn_tp_cnt; i++)
pj_ice_strans_turn_cfg_default(&ice_cfg.turn_tp[i]);
pj_ice_strans_turn_cfg_default(&ice_cfg.turn_tp[1]);
ice_cfg.turn_tp[1].af = pj_AF_INET6();
if (use_ipv6 || use_nat64) {
if (!use_nat64)
ice_cfg.turn_tp[idx++].af = pj_AF_INET6();
/* Additional candidate: IPv4 relay via IPv6 TURN server */
pj_ice_strans_turn_cfg_default(&ice_cfg.turn_tp[2]);
ice_cfg.turn_tp[2].af = pj_AF_INET6();
ice_cfg.turn_tp[2].alloc_param.af = pj_AF_INET();
ice_cfg.turn_tp[idx].af = pj_AF_INET6();
ice_cfg.turn_tp[idx].alloc_param.af = pj_AF_INET();
}
/* Configure TURN server */
@ -962,72 +967,38 @@ static pj_status_t create_ice_media_transport(
return PJ_EINVAL;
}
/* Configure TURN connection settings and credential */
if (ice_cfg.turn_tp[0].port == 0)
ice_cfg.turn_tp[0].port = 3479;
ice_cfg.turn_tp[0].conn_type = acc_cfg->turn_cfg.turn_conn_type;
pj_memcpy(&ice_cfg.turn_tp[0].auth_cred,
&acc_cfg->turn_cfg.turn_auth_cred,
sizeof(ice_cfg.turn_tp[0].auth_cred));
if (use_ipv6 && ice_cfg.turn_tp_cnt > 1) {
ice_cfg.turn_tp[1].server = ice_cfg.turn_tp[0].server;
ice_cfg.turn_tp[1].port = ice_cfg.turn_tp[0].port;
ice_cfg.turn_tp[1].conn_type = ice_cfg.turn_tp[0].conn_type;
pj_memcpy(&ice_cfg.turn_tp[1].auth_cred,
for (i = 0; i < ice_cfg.turn_tp_cnt; i++) {
pj_str_t IN6_ADDR_ANY = {"0", 1};
/* Configure TURN connection settings and credential */
ice_cfg.turn_tp[i].server = ice_cfg.turn_tp[0].server;
ice_cfg.turn_tp[i].port = ice_cfg.turn_tp[0].port;
ice_cfg.turn_tp[i].conn_type = acc_cfg->turn_cfg.turn_conn_type;
pj_memcpy(&ice_cfg.turn_tp[i].auth_cred,
&acc_cfg->turn_cfg.turn_auth_cred,
sizeof(ice_cfg.turn_tp[1].auth_cred));
sizeof(ice_cfg.turn_tp[i].auth_cred));
ice_cfg.turn_tp[2].server = ice_cfg.turn_tp[0].server;
ice_cfg.turn_tp[2].port = ice_cfg.turn_tp[0].port;
ice_cfg.turn_tp[2].conn_type = ice_cfg.turn_tp[0].conn_type;
pj_memcpy(&ice_cfg.turn_tp[2].auth_cred,
&acc_cfg->turn_cfg.turn_auth_cred,
sizeof(ice_cfg.turn_tp[2].auth_cred));
}
/* Configure QoS setting */
ice_cfg.turn_tp[0].cfg.qos_type = cfg->qos_type;
pj_memcpy(&ice_cfg.turn_tp[0].cfg.qos_params, &cfg->qos_params,
sizeof(cfg->qos_params));
if (use_ipv6 && ice_cfg.turn_tp_cnt > 1) {
ice_cfg.turn_tp[1].cfg.qos_type = cfg->qos_type;
pj_memcpy(&ice_cfg.turn_tp[1].cfg.qos_params, &cfg->qos_params,
/* Configure QoS setting */
ice_cfg.turn_tp[i].cfg.qos_type = cfg->qos_type;
pj_memcpy(&ice_cfg.turn_tp[i].cfg.qos_params, &cfg->qos_params,
sizeof(cfg->qos_params));
ice_cfg.turn_tp[2].cfg.qos_type = cfg->qos_type;
pj_memcpy(&ice_cfg.turn_tp[2].cfg.qos_params, &cfg->qos_params,
sizeof(cfg->qos_params));
}
/* Configure binding address */
pj_sockaddr_init(ice_cfg.turn_tp[0].af, &ice_cfg.turn_tp[0].cfg.bound_addr,
&cfg->bound_addr, (pj_uint16_t)cfg->port);
ice_cfg.turn_tp[0].cfg.port_range = (pj_uint16_t)cfg->port_range;
if (cfg->port != 0 && ice_cfg.turn_tp[0].cfg.port_range == 0)
ice_cfg.turn_tp[0].cfg.port_range =
/* Configure binding address */
pj_sockaddr_init(ice_cfg.turn_tp[i].af,
&ice_cfg.turn_tp[i].cfg.bound_addr,
(ice_cfg.turn_tp[i].af == pj_AF_INET()?
&cfg->bound_addr: &IN6_ADDR_ANY),
(pj_uint16_t)cfg->port);
ice_cfg.turn_tp[i].cfg.port_range = (pj_uint16_t)cfg->port_range;
if (cfg->port != 0 && ice_cfg.turn_tp[i].cfg.port_range == 0)
ice_cfg.turn_tp[i].cfg.port_range =
(pj_uint16_t)(pjsua_var.ua_cfg.max_calls * 10);
if (use_ipv6 && ice_cfg.turn_tp_cnt > 1) {
pj_str_t IN6_ADDR_ANY = {"0", 1};
pj_sockaddr_init(pj_AF_INET6(),
&ice_cfg.turn_tp[1].cfg.bound_addr,
&IN6_ADDR_ANY, (pj_uint16_t)cfg->port);
ice_cfg.turn_tp[1].cfg.port_range =
ice_cfg.turn_tp[0].cfg.port_range;
pj_sockaddr_init(pj_AF_INET6(),
&ice_cfg.turn_tp[2].cfg.bound_addr,
&IN6_ADDR_ANY, (pj_uint16_t)cfg->port);
ice_cfg.turn_tp[2].cfg.port_range =
ice_cfg.turn_tp[0].cfg.port_range;
}
/* Configure max packet size */
ice_cfg.turn_tp[0].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
if (use_ipv6 && ice_cfg.turn_tp_cnt > 1) {
ice_cfg.turn_tp[1].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
ice_cfg.turn_tp[2].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
/* Configure max packet size */
ice_cfg.turn_tp[i].cfg.max_pkt_size = PJMEDIA_MAX_MRU;
}
}
@ -2395,13 +2366,16 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
/* Add connection line, if none */
if (m->conn == NULL && sdp->conn == NULL) {
pj_bool_t use_ipv6;
pj_bool_t use_nat64;
use_ipv6 = (pjsua_var.acc[call->acc_id].cfg.ipv6_media_use !=
PJSUA_IPV6_DISABLED);
use_nat64 = (pjsua_var.acc[call->acc_id].cfg.nat64_opt !=
PJSUA_NAT64_DISABLED);
m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
m->conn->net_type = pj_str("IN");
if (use_ipv6) {
if (use_ipv6 && !use_nat64) {
m->conn->addr_type = pj_str("IP6");
m->conn->addr = pj_str("::1");
} else {

View File

@ -184,6 +184,7 @@ void AccountNatConfig::readObject(const ContainerNode &node) throw(Error)
NODE_READ_NUM_T ( this_node, pjsua_stun_use, sipStunUse);
NODE_READ_NUM_T ( this_node, pjsua_stun_use, mediaStunUse);
NODE_READ_NUM_T ( this_node, pjsua_nat64_opt, nat64Opt);
NODE_READ_BOOL ( this_node, iceEnabled);
NODE_READ_INT ( this_node, iceMaxHostCands);
NODE_READ_BOOL ( this_node, iceAggressiveNomination);
@ -215,6 +216,7 @@ void AccountNatConfig::writeObject(ContainerNode &node) const throw(Error)
NODE_WRITE_NUM_T ( this_node, pjsua_stun_use, sipStunUse);
NODE_WRITE_NUM_T ( this_node, pjsua_stun_use, mediaStunUse);
NODE_WRITE_NUM_T ( this_node, pjsua_nat64_opt, nat64Opt);
NODE_WRITE_BOOL ( this_node, iceEnabled);
NODE_WRITE_INT ( this_node, iceMaxHostCands);
NODE_WRITE_BOOL ( this_node, iceAggressiveNomination);
@ -391,6 +393,7 @@ void AccountConfig::toPj(pjsua_acc_config &ret) const
// AccountNatConfig
ret.sip_stun_use = natConfig.sipStunUse;
ret.media_stun_use = natConfig.mediaStunUse;
ret.nat64_opt = natConfig.nat64Opt;
ret.ice_cfg_use = PJSUA_ICE_CONFIG_USE_CUSTOM;
ret.ice_cfg.enable_ice = natConfig.iceEnabled;
ret.ice_cfg.ice_max_host_cands = natConfig.iceMaxHostCands;
@ -534,6 +537,7 @@ void AccountConfig::fromPj(const pjsua_acc_config &prm,
// AccountNatConfig
natConfig.sipStunUse = prm.sip_stun_use;
natConfig.mediaStunUse = prm.media_stun_use;
natConfig.nat64Opt = prm.nat64_opt;
if (prm.ice_cfg_use == PJSUA_ICE_CONFIG_USE_CUSTOM) {
natConfig.iceEnabled = PJ2BOOL(prm.ice_cfg.enable_ice);
natConfig.iceMaxHostCands = prm.ice_cfg.ice_max_host_cands;

View File

@ -148,6 +148,7 @@ void UaConfig::fromPj(const pjsua_config &ua_cfg)
this->stunServer.push_back(pj2Str(ua_cfg.stun_srv[i]));
}
this->stunTryIpv6 = PJ2BOOL(ua_cfg.stun_try_ipv6);
this->stunIgnoreFailure = PJ2BOOL(ua_cfg.stun_ignore_failure);
this->natTypeInSdp = ua_cfg.nat_type_in_sdp;
this->mwiUnsolicitedEnabled = PJ2BOOL(ua_cfg.enable_unsolicited_mwi);
@ -194,6 +195,7 @@ void UaConfig::readObject(const ContainerNode &node) throw(Error)
NODE_READ_STRINGV ( this_node, nameserver);
NODE_READ_STRING ( this_node, userAgent);
NODE_READ_STRINGV ( this_node, stunServer);
NODE_READ_BOOL ( this_node, stunTryIpv6);
NODE_READ_BOOL ( this_node, stunIgnoreFailure);
NODE_READ_INT ( this_node, natTypeInSdp);
NODE_READ_BOOL ( this_node, mwiUnsolicitedEnabled);
@ -209,6 +211,7 @@ void UaConfig::writeObject(ContainerNode &node) const throw(Error)
NODE_WRITE_STRINGV ( this_node, nameserver);
NODE_WRITE_STRING ( this_node, userAgent);
NODE_WRITE_STRINGV ( this_node, stunServer);
NODE_WRITE_BOOL ( this_node, stunTryIpv6);
NODE_WRITE_BOOL ( this_node, stunIgnoreFailure);
NODE_WRITE_INT ( this_node, natTypeInSdp);
NODE_WRITE_BOOL ( this_node, mwiUnsolicitedEnabled);