Skip to content

Commit

Permalink
Update IP version choosing logic in media transport creation for gene…
Browse files Browse the repository at this point in the history
…rating SDP offer. (#4067)
  • Loading branch information
nanangizz authored Oct 1, 2024
1 parent 906f816 commit 7249136
Show file tree
Hide file tree
Showing 3 changed files with 279 additions and 12 deletions.
45 changes: 45 additions & 0 deletions pjlib/include/pj/addr_resolv.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,51 @@ PJ_DECL(pj_status_t) pj_getaddrinfo(int af, const pj_str_t *name,
unsigned *count, pj_addrinfo ai[]);


/**
* Enumeration of IP address type.
*/
typedef enum pj_addr_type
{
/**
* Disabled: 0.0.0.0/8 or ::/128
*/
PJ_ADDR_TYPE_DISABLED = 1,

/**
* Loopback: 127.0.0.0/8 or ::1/128
*/
PJ_ADDR_TYPE_LOOPBACK = 2,

/**
* Link-local: 169.254.0.0/16 or fe80::/64
*/
PJ_ADDR_TYPE_LINK_LOCAL = 4,

/**
* Private: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 or fc00::/7
*/
PJ_ADDR_TYPE_PRIVATE = 8,

/**
* Multicast: 224.0.0.0/3 or ff00::/8
*/
PJ_ADDR_TYPE_MULTICAST = 16,

} pj_addr_type;



/**
* Check IP address type.
*
* @param addr The IP address to check, must be IPv4 or IPv6 address.
* @param type Bit mask of address type pj_addr_type.
*
* @return PJ_TRUE if the type of specified address \addr match to
* the specified types \a type.
*/
PJ_DECL(pj_bool_t) pj_check_addr_type(const pj_sockaddr *addr, unsigned type);


/** @} */

Expand Down
111 changes: 111 additions & 0 deletions pjlib/src/pj/sock_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,7 @@ PJ_DEF(pj_status_t) pj_sockaddr_parse( int af, unsigned options,
return status;
}


/* Resolve the IP address of local machine */
PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr)
{
Expand Down Expand Up @@ -1410,6 +1411,116 @@ PJ_DEF(pj_status_t) pj_sock_socketpair(int family,
#endif


/* Check IP address type. */
PJ_DEF(pj_bool_t) pj_check_addr_type(const pj_sockaddr *addr, unsigned type)
{
int af;

PJ_ASSERT_RETURN(addr && type, PJ_EINVAL);
PJ_ASSERT_RETURN(addr->addr.sa_family == PJ_AF_INET ||
addr->addr.sa_family == PJ_AF_INET6, PJ_EINVAL);

af = addr->addr.sa_family;

if (af == PJ_AF_INET) {
enum {
/* Disabled: 0.0.0.0/8 */
ADDR4_DISABLED = 0x00000000,
MASK4_DISABLED = 0xFF000000,
/* Loopback: 127.0.0.0/8 */
ADDR4_LOOPBACK = 0x7f000000,
MASK4_LOOPBACK = 0xFF000000,
/* Link-local: 169.254.0.0/16 */
ADDR4_LINKLOCAL = 0xa9fe0000,
MASK4_LINKLOCAL = 0xFFFF0000,
/* Multicast: 224.0.0.0/3 */
ADDR4_MULTICAST = 0xE0000000,
MASK4_MULTICAST = 0xF0000000,
};

pj_uint32_t a = pj_ntohl(addr->ipv4.sin_addr.s_addr);

if ((type & PJ_ADDR_TYPE_DISABLED) &&
(a & (pj_uint32_t)MASK4_DISABLED)==(pj_uint32_t)ADDR4_DISABLED)
{
return PJ_TRUE;
}

if ((type & PJ_ADDR_TYPE_LOOPBACK) &&
(a & (pj_uint32_t)MASK4_LOOPBACK)==(pj_uint32_t)ADDR4_LOOPBACK)
{
return PJ_TRUE;
}

if ((type & PJ_ADDR_TYPE_LINK_LOCAL) &&
(a & (pj_uint32_t)MASK4_LINKLOCAL)==(pj_uint32_t)ADDR4_LINKLOCAL)
{
return PJ_TRUE;
}

if (type & PJ_ADDR_TYPE_PRIVATE) {
pj_uint8_t b1 = (pj_uint8_t)(a >> 24);
pj_uint8_t b2 = (pj_uint8_t)((a >> 16) & 0x0ff);;

/* 10.0.0.0/8 */
if (b1 == 10)
return PJ_TRUE;

/* 172.16.0.0/12 or 172.16.0.0-172.31.255.255 */
if ((b1 == 172) && (b2 >= 16) && (b2 <= 31))
return PJ_TRUE;

/* 192.168.0.0/16 */
if ((b1 == 192) && (b2 == 168))
return PJ_TRUE;
}

if ((type & PJ_ADDR_TYPE_MULTICAST) &&
(a & (pj_uint32_t)MASK4_MULTICAST)==(pj_uint32_t)ADDR4_MULTICAST)
{
return PJ_TRUE;
}

} else /* if (af == PJ_AF_INET6) */ {

if (type & PJ_ADDR_TYPE_DISABLED) {
/* ::/128 */
pj_uint8_t saddr[16] = {0x0,0x0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
if (pj_memcmp(saddr, &addr->ipv6.sin6_addr, 16) == 0)
return PJ_TRUE;
}

if (type & PJ_ADDR_TYPE_LOOPBACK) {
/* ::1/128 */
pj_uint8_t saddr[16] = {0x0,0x0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
if (pj_memcmp(saddr, &addr->ipv6.sin6_addr, 16) == 0)
return PJ_TRUE;
}

if (type & PJ_ADDR_TYPE_LINK_LOCAL) {
/* fe80::/64 */
pj_uint8_t saddr[16] = {0xfe,0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
if (pj_memcmp(saddr, &addr->ipv6.sin6_addr, 8) == 0)
return PJ_TRUE;
}

if (type & PJ_ADDR_TYPE_PRIVATE) {
/* fc00::/7 */
if ((addr->ipv6.sin6_addr.s6_addr[0] & 0xfe) == 0xfc)
return PJ_TRUE;
}

if (type & PJ_ADDR_TYPE_MULTICAST) {
/* ff00::/8 */
if (addr->ipv6.sin6_addr.s6_addr[0] == 0xff)
return PJ_TRUE;
}
}

return PJ_FALSE;
}


/* Only need to implement these in DLL build */
#if defined(PJ_DLL)

Expand Down
135 changes: 123 additions & 12 deletions pjsip/src/pjsua-lib/pjsua_media.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,9 @@ pj_status_t pjsua_media_subsys_destroy(unsigned flags)
}

static int get_media_ip_version(pjsua_call_media *call_med,
const pjmedia_sdp_session *rem_sdp)
const pjmedia_sdp_session *rem_sdp,
pj_bool_t loop_tp,
pj_bool_t ice_tp)
{
#if PJ_HAS_IPV6

Expand All @@ -270,13 +272,118 @@ static int get_media_ip_version(pjsua_call_media *call_med,
/* Use IPv6. */
return 6;
}

} else {
if (ipv6_use == PJSUA_IPV6_ENABLED_PREFER_IPV6 ||
ipv6_use == PJSUA_IPV6_ENABLED_USE_IPV6_ONLY)
{
/* Use IPv6. */
pj_sockaddr addr = {{0}};
pj_status_t status;

/* Status:
* - not avail: no IP address, gethostip() returns error.
* - available: IP address is loopback, local-link, or disabled.
* - usable : IP address is not loopback, local-link, nor disabled.
*/
unsigned ipv6_status = 0; /* 0: not avail, 1: available, 2: usable*/
unsigned ipv4_status = 0; /* 0: not avail, 1: available, 2: usable*/

/* Use IPv4 regardless. */
if (ipv6_use == PJSUA_IPV6_DISABLED)
return 4;

/* Use IPv6 regardless. */
if (ipv6_use == PJSUA_IPV6_ENABLED_USE_IPV6_ONLY)
return 6;

/* For loop transport, use the preferred */
if (loop_tp) {
if (ipv6_use == PJSUA_IPV6_ENABLED_PREFER_IPV6)
return 6;
if (ipv6_use == PJSUA_IPV6_ENABLED_PREFER_IPV4)
return 4;

/* No preference, just use IPv4 */
return 4;
}


/* Check IPv6 & IPv4 availability & usability */

status = pj_gethostip(PJ_AF_INET6, &addr);
if (status == PJ_SUCCESS) {
/* IPv6 is available */
ipv6_status = 1;

/* Check if it is usable */
if (!pj_check_addr_type(&addr,
PJ_ADDR_TYPE_DISABLED |
PJ_ADDR_TYPE_LOOPBACK |
PJ_ADDR_TYPE_LINK_LOCAL))
{
/* If IPv6 is usable & preferred, use it */
if (ipv6_use == PJSUA_IPV6_ENABLED_PREFER_IPV6)
return 6;

/* IPv6 seems usable */
ipv6_status = 2;
}
}

/* For ICE transport, use IPv6 if available */
if (ice_tp) {
return (ipv6_status >= 1)? 6 : 4;
}

status = pj_gethostip(PJ_AF_INET, &addr);
if (status == PJ_SUCCESS) {
/* IPv4 is available */
ipv4_status = 1;

/* Check if it is usable */
if (!pj_check_addr_type(&addr,
PJ_ADDR_TYPE_DISABLED |
PJ_ADDR_TYPE_LOOPBACK |
PJ_ADDR_TYPE_LINK_LOCAL))
{
/* If IPv4 is usable & preferred, use it */
if (ipv6_use == PJSUA_IPV6_ENABLED_PREFER_IPV4)
return 4;

/* IPv4 seems usable */
ipv4_status = 2;
}
}


/* Preferred IP version is not usable, fallback to any usable.
* In this point, either only one is usable (but not preferred)
* or there is no preference (IPv4 will be returned).
*/
if (ipv4_status == 2)
return 4;
if (ipv6_status == 2)
return 6;

PJ_LOG(3,(THIS_FILE,"Call %d: Media %d: Warning, no usable "
"IP address for SDP offer",
call_med->call->index, call_med->idx));

/* No usable IP version, pick based on availability & preference. */
if (ipv6_use == PJSUA_IPV6_ENABLED_PREFER_IPV6 && ipv6_status > 0)
return 6;
if (ipv6_use == PJSUA_IPV6_ENABLED_PREFER_IPV4 && ipv4_status > 0)
return 4;

/* Preferred IP version is not available, fallback to any available.
* In this point, either only one is available (but not preferred)
* or there is no preference (IPv4 will be returned).
*/
if (ipv4_status == 1)
return 4;
if (ipv6_status == 1)
return 6;

PJ_LOG(3,(THIS_FILE,"Call %d: Media %d: Warning, no available "
"IP address for SDP offer",
call_med->call->index, call_med->idx));
}
#else
PJ_UNUSED_ARG(call_med);
Expand Down Expand Up @@ -309,7 +416,7 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];
pj_sock_t sock[2];

use_ipv6 = (get_media_ip_version(call_med, rem_sdp) == 6);
use_ipv6 = (get_media_ip_version(call_med, rem_sdp, PJ_FALSE, PJ_FALSE)==6);
use_nat64 = PJ_HAS_IPV6 && (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED);
af = (use_ipv6 || use_nat64) ? pj_AF_INET6() : pj_AF_INET();

Expand Down Expand Up @@ -762,7 +869,7 @@ static pj_status_t create_loop_media_transport(
int af;
pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id];

use_ipv6 = (get_media_ip_version(call_med, rem_sdp) == 6);
use_ipv6 = (get_media_ip_version(call_med, rem_sdp, PJ_TRUE, PJ_FALSE)==6);
use_nat64 = PJ_HAS_IPV6 && (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED);
af = (use_ipv6 || use_nat64) ? pj_AF_INET6() : pj_AF_INET();

Expand Down Expand Up @@ -1020,7 +1127,8 @@ static pj_status_t create_ice_media_transport(
pjmedia_sdp_session *rem_sdp;

acc_cfg = &pjsua_var.acc[call_med->call->acc_id].cfg;
use_ipv6 = (get_media_ip_version(call_med, remote_sdp) == 6);
use_ipv6 = (get_media_ip_version(call_med, remote_sdp, PJ_FALSE, PJ_TRUE)
== 6);
use_nat64 = PJ_HAS_IPV6 && (acc_cfg->nat64_opt != PJSUA_NAT64_DISABLED);

/* Make sure STUN server resolution has completed */
Expand Down Expand Up @@ -2824,11 +2932,14 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id,
pj_bool_t use_nat64;

if (rem_sdp) {
use_ipv6 = (get_media_ip_version(call_med, rem_sdp) == 6);
use_ipv6 = (get_media_ip_version(call_med, rem_sdp,
PJ_FALSE, PJ_FALSE) == 6);
} else {
use_ipv6 = PJ_HAS_IPV6 &&
(pjsua_var.acc[call->acc_id].cfg.ipv6_media_use !=
PJSUA_IPV6_DISABLED);
//use_ipv6 = PJ_HAS_IPV6 &&
// (pjsua_var.acc[call->acc_id].cfg.ipv6_media_use !=
// PJSUA_IPV6_DISABLED);
use_ipv6 = (get_media_ip_version(call_med, rem_sdp,
PJ_FALSE, PJ_FALSE) == 6);
}
use_nat64 = PJ_HAS_IPV6 &&
(pjsua_var.acc[call->acc_id].cfg.nat64_opt !=
Expand Down

0 comments on commit 7249136

Please sign in to comment.