Fixed #1585: IPv6 support for SIP TCP and TLS transports and PJSUA-LIB v2

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@4262 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
Benny Prijono 2012-09-20 06:00:23 +00:00
parent 28bd76b7ac
commit e135917e37
10 changed files with 410 additions and 276 deletions

View File

@ -170,7 +170,6 @@ static char some_buf[SOME_BUF_SIZE];
#ifdef STEREO_DEMO
static void stereo_demo();
#endif
static pj_status_t create_ipv6_media_transports(void);
pj_status_t app_destroy(void);
static void ringback_start(pjsua_call_id call_id);
@ -876,8 +875,8 @@ static pj_status_t parse_args(int argc, char *argv[],
break;
case OPT_NO_UDP: /* no-udp */
if (cfg->no_tcp) {
PJ_LOG(1,(THIS_FILE,"Error: can not disable both TCP and UDP"));
if (cfg->no_tcp && !cfg->use_tls) {
PJ_LOG(1,(THIS_FILE,"Error: cannot disable both TCP and UDP"));
return PJ_EINVAL;
}
@ -889,8 +888,8 @@ static pj_status_t parse_args(int argc, char *argv[],
break;
case OPT_NO_TCP: /* no-tcp */
if (cfg->no_udp) {
PJ_LOG(1,(THIS_FILE,"Error: can not disable both TCP and UDP"));
if (cfg->no_udp && !cfg->use_tls) {
PJ_LOG(1,(THIS_FILE,"Error: cannot disable both TCP and UDP"));
return PJ_EINVAL;
}
@ -5907,6 +5906,8 @@ pj_status_t app_init(int argc, char *argv[])
pjsua_acc_config acc_cfg;
pjsua_acc_get_config(aid, &acc_cfg);
app_config_init_video(&acc_cfg);
if (app_config.ipv6)
acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED;
pjsua_acc_modify(aid, &acc_cfg);
}
//pjsua_acc_set_transport(aid, transport_id);
@ -5945,6 +5946,33 @@ pj_status_t app_init(int argc, char *argv[])
}
/* Add TCP IPv6 transport unless it's disabled. */
if (!app_config.no_tcp && app_config.ipv6) {
pjsua_acc_id aid;
pjsip_transport_type_e type = PJSIP_TRANSPORT_TCP6;
tcp_cfg.port += 10;
status = pjsua_transport_create(type,
&tcp_cfg,
&transport_id);
if (status != PJ_SUCCESS)
goto on_error;
/* Add local account */
pjsua_acc_add_local(transport_id, PJ_TRUE, &aid);
if (PJMEDIA_HAS_VIDEO) {
pjsua_acc_config acc_cfg;
pjsua_acc_get_config(aid, &acc_cfg);
app_config_init_video(&acc_cfg);
if (app_config.ipv6)
acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED;
pjsua_acc_modify(aid, &acc_cfg);
}
//pjsua_acc_set_transport(aid, transport_id);
pjsua_acc_set_online_status(current_acc, PJ_TRUE);
}
#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
/* Add TLS transport when application wants one */
@ -5976,6 +6004,34 @@ pj_status_t app_init(int argc, char *argv[])
}
pjsua_acc_set_online_status(acc_id, PJ_TRUE);
}
/* Add TLS IPv6 transport unless it's disabled. */
if (app_config.use_tls && app_config.ipv6) {
pjsua_acc_id aid;
pjsip_transport_type_e type = PJSIP_TRANSPORT_TLS6;
tcp_cfg.port += 10;
status = pjsua_transport_create(type,
&tcp_cfg,
&transport_id);
if (status != PJ_SUCCESS)
goto on_error;
/* Add local account */
pjsua_acc_add_local(transport_id, PJ_TRUE, &aid);
if (PJMEDIA_HAS_VIDEO) {
pjsua_acc_config acc_cfg;
pjsua_acc_get_config(aid, &acc_cfg);
app_config_init_video(&acc_cfg);
if (app_config.ipv6)
acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED;
pjsua_acc_modify(aid, &acc_cfg);
}
//pjsua_acc_set_transport(aid, transport_id);
pjsua_acc_set_online_status(current_acc, PJ_TRUE);
}
#endif
if (transport_id == -1) {
@ -6026,16 +6082,6 @@ pj_status_t app_init(int argc, char *argv[])
#endif
}
/* Add RTP transports */
if (app_config.ipv6)
status = create_ipv6_media_transports();
#if DISABLED_FOR_TICKET_1185
else
status = pjsua_media_transports_create(&app_config.rtp_cfg);
#endif
if (status != PJ_SUCCESS)
goto on_error;
/* Use null sound device? */
#ifndef STEREO_DEMO
if (app_config.null_audio) {
@ -6251,94 +6297,3 @@ static void stereo_demo()
}
#endif
static pj_status_t create_ipv6_media_transports(void)
{
pjsua_media_transport tp[PJSUA_MAX_CALLS];
pj_status_t status;
int port = app_config.rtp_cfg.port;
unsigned i;
for (i=0; i<app_config.cfg.max_calls; ++i) {
enum { MAX_RETRY = 10 };
pj_sock_t sock[2];
pjmedia_sock_info si;
unsigned j;
/* Get rid of uninitialized var compiler warning with MSVC */
status = PJ_SUCCESS;
for (j=0; j<MAX_RETRY; ++j) {
unsigned k;
for (k=0; k<2; ++k) {
pj_sockaddr bound_addr;
status = pj_sock_socket(pj_AF_INET6(), pj_SOCK_DGRAM(), 0, &sock[k]);
if (status != PJ_SUCCESS)
break;
status = pj_sockaddr_init(pj_AF_INET6(), &bound_addr,
&app_config.rtp_cfg.bound_addr,
(unsigned short)(port+k));
if (status != PJ_SUCCESS)
break;
status = pj_sock_bind(sock[k], &bound_addr,
pj_sockaddr_get_len(&bound_addr));
if (status != PJ_SUCCESS)
break;
}
if (status != PJ_SUCCESS) {
if (k==1)
pj_sock_close(sock[0]);
if (port != 0)
port += 10;
else
break;
continue;
}
pj_bzero(&si, sizeof(si));
si.rtp_sock = sock[0];
si.rtcp_sock = sock[1];
pj_sockaddr_init(pj_AF_INET6(), &si.rtp_addr_name,
&app_config.rtp_cfg.public_addr,
(unsigned short)(port));
pj_sockaddr_init(pj_AF_INET6(), &si.rtcp_addr_name,
&app_config.rtp_cfg.public_addr,
(unsigned short)(port+1));
status = pjmedia_transport_udp_attach(pjsua_get_pjmedia_endpt(),
NULL,
&si,
0,
&tp[i].transport);
if (port != 0)
port += 10;
else
break;
if (status == PJ_SUCCESS)
break;
}
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error creating IPv6 UDP media transport",
status);
for (j=0; j<i; ++j) {
pjmedia_transport_close(tp[j].transport);
}
return status;
}
}
#if DISABLED_FOR_TICKET_1185
return pjsua_media_transports_attach(tp, i, PJ_TRUE);
#else
return PJ_ENOTSUP;
#endif
}

View File

@ -262,6 +262,8 @@ PJ_INLINE(void) pjsip_tls_setting_copy(pj_pool_t *pool,
* instance of SIP TLS transport factory and register it to the
* transport manager.
*
* See also #pjsip_tls_transport_start2() which supports IPv6.
*
* @param endpt The SIP endpoint.
* @param opt Optional TLS settings.
* @param local Optional local address to bind, or specify the
@ -294,7 +296,43 @@ PJ_DECL(pj_status_t) pjsip_tls_transport_start(pjsip_endpoint *endpt,
unsigned async_cnt,
pjsip_tpfactory **p_factory);
/**
* Variant of #pjsip_tls_transport_start() that supports IPv6. To instantiate
* IPv6 listener, set the address family of the "local" argument to IPv6
* (the host and port part may be left unspecified if not desired, i.e. by
* filling them with zeroes).
*
* @param endpt The SIP endpoint.
* @param opt Optional TLS settings.
* @param local Optional local address to bind, or specify the
* address to bind the server socket to. Both IP
* interface address and port fields are optional.
* If IP interface address is not specified, socket
* will be bound to any address. If port is not
* specified, socket will be bound to any port
* selected by the operating system.
* @param a_name Optional published address, which is the address to be
* advertised as the address of this SIP transport.
* If this argument is NULL, then the bound address
* will be used as the published address.
* @param async_cnt Number of simultaneous asynchronous accept()
* operations to be supported. It is recommended that
* the number here corresponds to the number of
* processors in the system (or the number of SIP
* worker threads).
* @param p_factory Optional pointer to receive the instance of the
* SIP TLS transport factory just created.
*
* @return PJ_SUCCESS when the transport has been successfully
* started and registered to transport manager, or
* the appropriate error code.
*/
PJ_DECL(pj_status_t) pjsip_tls_transport_start2(pjsip_endpoint *endpt,
const pjsip_tls_setting *opt,
const pj_sockaddr *local,
const pjsip_host_port *a_name,
unsigned async_cnt,
pjsip_tpfactory **p_factory);
PJ_END_DECL

View File

@ -92,7 +92,10 @@ typedef enum pjsip_transport_type_e
PJSIP_TRANSPORT_UDP6 = PJSIP_TRANSPORT_UDP + PJSIP_TRANSPORT_IPV6,
/** TCP over IPv6 */
PJSIP_TRANSPORT_TCP6 = PJSIP_TRANSPORT_TCP + PJSIP_TRANSPORT_IPV6
PJSIP_TRANSPORT_TCP6 = PJSIP_TRANSPORT_TCP + PJSIP_TRANSPORT_IPV6,
/** TLS over IPv6 */
PJSIP_TRANSPORT_TLS6 = PJSIP_TRANSPORT_TLS + PJSIP_TRANSPORT_IPV6
} pjsip_transport_type_e;

View File

@ -2689,6 +2689,23 @@ typedef struct pjsua_turn_config
} pjsua_turn_config;
/**
* Specify how IPv6 transport should be used in account config.
*/
typedef enum pjsua_ipv6_use
{
/**
* IPv6 is not used.
*/
PJSUA_IPV6_DISABLED,
/**
* IPv6 is enabled.
*/
PJSUA_IPV6_ENABLED
} pjsua_ipv6_use;
/**
* This structure describes account configuration to be specified when
* adding a new account with #pjsua_acc_add(). Application MUST initialize
@ -3089,6 +3106,11 @@ typedef struct pjsua_acc_config
*/
pjsua_transport_config rtp_cfg;
/**
* Specify whether IPv6 should be used on media.
*/
pjsua_ipv6_use ipv6_media_use;
/**
* Control the use of STUN for the SIP signaling.
*

View File

@ -198,6 +198,13 @@ struct transport_names_t
"TCP IPv6 transport",
PJSIP_TRANSPORT_RELIABLE
},
{
PJSIP_TRANSPORT_TLS6,
5061,
{"TLS", 3},
"TLS IPv6 transport",
PJSIP_TRANSPORT_RELIABLE | PJSIP_TRANSPORT_SECURE
},
};
static void tp_state_callback(pjsip_transport *tp,
@ -1279,9 +1286,20 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr2(pjsip_tpmgr *tpmgr,
if (prm->local_if) {
status = get_net_interface(f->type, &prm->dst_host,
&tmp_str);
if (status != PJ_SUCCESS)
goto on_return;
pj_strdup(pool, &prm->ret_addr, &tmp_str);
if (status == PJ_SUCCESS) {
pj_strdup(pool, &prm->ret_addr, &tmp_str);
} else {
/* It could fail "normally" on certain cases, e.g.
* when connecting to IPv6 link local address, it
* will wail with EINVAL.
* In this case, fallback to use the default interface
* rather than failing the call.
*/
PJ_PERROR(5,(THIS_FILE, status, "Warning: unable to "
"determine local interface"));
pj_strdup(pool, &prm->ret_addr, &f->addr_name.host);
status = PJ_SUCCESS;
}
} else {
pj_strdup(pool, &prm->ret_addr, &f->addr_name.host);
}

View File

@ -57,6 +57,7 @@ struct tcp_listener
pjsip_endpoint *endpt;
pjsip_tpmgr *tpmgr;
pj_activesock_t *asock;
pj_sockaddr bound_addr;
pj_qos_type qos_type;
pj_qos_params qos_params;
};
@ -141,8 +142,8 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
static pj_status_t tcp_create(struct tcp_listener *listener,
pj_pool_t *pool,
pj_sock_t sock, pj_bool_t is_server,
const pj_sockaddr_in *local,
const pj_sockaddr_in *remote,
const pj_sockaddr *local,
const pj_sockaddr *remote,
struct tcp_transport **p_tcp);
@ -159,10 +160,10 @@ static void tcp_perror(const char *sender, const char *title,
static void sockaddr_to_host_port( pj_pool_t *pool,
pjsip_host_port *host_port,
const pj_sockaddr_in *addr )
const pj_sockaddr *addr )
{
host_port->host.ptr = (char*) pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+4);
pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 2);
pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 0);
host_port->host.slen = pj_ansi_strlen(host_port->host.ptr);
host_port->port = pj_sockaddr_get_port(addr);
}
@ -267,17 +268,21 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
listener = PJ_POOL_ZALLOC_T(pool, struct tcp_listener);
listener->factory.pool = pool;
listener->factory.type = PJSIP_TRANSPORT_TCP;
listener->factory.type_name = "tcp";
listener->factory.type = cfg->af==pj_AF_INET() ? PJSIP_TRANSPORT_TCP :
PJSIP_TRANSPORT_TCP6;
listener->factory.type_name = (char*)
pjsip_transport_get_type_name(listener->factory.type);
listener->factory.flag =
pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TCP);
pjsip_transport_get_flag_from_type(listener->factory.type);
listener->qos_type = cfg->qos_type;
pj_memcpy(&listener->qos_params, &cfg->qos_params,
sizeof(cfg->qos_params));
pj_ansi_strcpy(listener->factory.obj_name, "tcplis");
if (listener->factory.type==PJSIP_TRANSPORT_TCP6)
pj_ansi_strcat(listener->factory.obj_name, "6");
status = pj_lock_create_recursive_mutex(pool, "tcplis",
status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
&listener->factory.lock);
if (status != PJ_SUCCESS)
goto on_error;
@ -293,6 +298,11 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
2, listener->factory.obj_name,
"SIP TCP listener socket");
/* Bind address may be different than factory.local_addr because
* factory.local_addr will be resolved below.
*/
pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr);
/* Bind socket */
listener_addr = &listener->factory.local_addr;
pj_sockaddr_cp(listener_addr, &cfg->bind_addr);
@ -327,19 +337,18 @@ PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
if (!pj_sockaddr_has_addr(listener_addr)) {
pj_sockaddr hostip;
status = pj_gethostip(pj_AF_INET(), &hostip);
status = pj_gethostip(listener->bound_addr.addr.sa_family,
&hostip);
if (status != PJ_SUCCESS)
goto on_error;
pj_memcpy(pj_sockaddr_get_addr(listener_addr),
pj_sockaddr_get_addr(&hostip),
pj_sockaddr_get_addr_len(&hostip));
pj_sockaddr_copy_addr(listener_addr, &hostip);
}
/* Save the address name */
sockaddr_to_host_port(listener->factory.pool,
&listener->factory.addr_name,
(pj_sockaddr_in*)listener_addr);
listener_addr);
}
/* If port is zero, get the bound port */
@ -536,8 +545,8 @@ static void tcp_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e);
static pj_status_t tcp_create( struct tcp_listener *listener,
pj_pool_t *pool,
pj_sock_t sock, pj_bool_t is_server,
const pj_sockaddr_in *local,
const pj_sockaddr_in *remote,
const pj_sockaddr *local,
const pj_sockaddr *remote,
struct tcp_transport **p_tcp)
{
struct tcp_transport *tcp;
@ -545,6 +554,7 @@ static pj_status_t tcp_create( struct tcp_listener *listener,
pj_activesock_cfg asock_cfg;
pj_activesock_cb tcp_callback;
const pj_str_t ka_pkt = PJSIP_TCP_KEEP_ALIVE_DATA;
char print_addr[PJ_INET6_ADDRSTRLEN+10];
pj_status_t status;
@ -580,18 +590,20 @@ static pj_status_t tcp_create( struct tcp_listener *listener,
goto on_error;
}
tcp->base.key.type = PJSIP_TRANSPORT_TCP;
pj_memcpy(&tcp->base.key.rem_addr, remote, sizeof(pj_sockaddr_in));
tcp->base.type_name = "tcp";
tcp->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TCP);
tcp->base.key.type = listener->factory.type;
pj_sockaddr_cp(&tcp->base.key.rem_addr, remote);
tcp->base.type_name = (char*)
pjsip_transport_get_type_name(tcp->base.key.type);
tcp->base.flag = pjsip_transport_get_flag_from_type(tcp->base.key.type);
tcp->base.info = (char*) pj_pool_alloc(pool, 64);
pj_ansi_snprintf(tcp->base.info, 64, "TCP to %s:%d",
pj_inet_ntoa(remote->sin_addr),
(int)pj_ntohs(remote->sin_port));
pj_ansi_snprintf(tcp->base.info, 64, "%s to %s",
tcp->base.type_name,
pj_sockaddr_print(remote, print_addr,
sizeof(print_addr), 3));
tcp->base.addr_len = sizeof(pj_sockaddr_in);
pj_memcpy(&tcp->base.local_addr, local, sizeof(pj_sockaddr_in));
tcp->base.addr_len = pj_sockaddr_get_len(remote);
pj_sockaddr_cp(&tcp->base.local_addr, local);
sockaddr_to_host_port(pool, &tcp->base.local_name, local);
sockaddr_to_host_port(pool, &tcp->base.remote_name, remote);
tcp->base.dir = is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING;
@ -602,7 +614,6 @@ static pj_status_t tcp_create( struct tcp_listener *listener,
tcp->base.do_shutdown = &tcp_shutdown;
tcp->base.destroy = &tcp_destroy_transport;
/* Create active socket */
pj_activesock_cfg_default(&asock_cfg);
asock_cfg.async_cnt = 1;
@ -801,7 +812,7 @@ static pj_status_t tcp_start_read(struct tcp_transport *tcp)
{
pj_pool_t *pool;
pj_ssize_t size;
pj_sockaddr_in *rem_addr;
pj_sockaddr *rem_addr;
void *readbuf[1];
pj_status_t status;
@ -824,11 +835,11 @@ static pj_status_t tcp_start_read(struct tcp_transport *tcp)
sizeof(pj_ioqueue_op_key_t));
tcp->rdata.pkt_info.src_addr = tcp->base.key.rem_addr;
tcp->rdata.pkt_info.src_addr_len = sizeof(pj_sockaddr_in);
rem_addr = (pj_sockaddr_in*) &tcp->base.key.rem_addr;
pj_ansi_strcpy(tcp->rdata.pkt_info.src_name,
pj_inet_ntoa(rem_addr->sin_addr));
tcp->rdata.pkt_info.src_port = pj_ntohs(rem_addr->sin_port);
tcp->rdata.pkt_info.src_addr_len = sizeof(tcp->rdata.pkt_info.src_addr);
rem_addr = &tcp->base.key.rem_addr;
pj_sockaddr_print(rem_addr, tcp->rdata.pkt_info.src_name,
sizeof(tcp->rdata.pkt_info.src_name), 0);
tcp->rdata.pkt_info.src_port = pj_sockaddr_get_port(rem_addr);
size = sizeof(tcp->rdata.pkt_info.packet);
readbuf[0] = tcp->rdata.pkt_info.packet;
@ -858,23 +869,25 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
struct tcp_listener *listener;
struct tcp_transport *tcp;
pj_sock_t sock;
pj_sockaddr_in local_addr;
pj_sockaddr local_addr;
pj_status_t status;
/* Sanity checks */
PJ_ASSERT_RETURN(factory && mgr && endpt && rem_addr &&
addr_len && p_transport, PJ_EINVAL);
/* Check that address is a sockaddr_in */
PJ_ASSERT_RETURN(rem_addr->addr.sa_family == pj_AF_INET() &&
addr_len == sizeof(pj_sockaddr_in), PJ_EINVAL);
/* Check that address is a sockaddr_in or sockaddr_in6*/
PJ_ASSERT_RETURN((rem_addr->addr.sa_family == pj_AF_INET() &&
addr_len == sizeof(pj_sockaddr_in)) ||
(rem_addr->addr.sa_family == pj_AF_INET6() &&
addr_len == sizeof(pj_sockaddr_in6)), PJ_EINVAL);
listener = (struct tcp_listener*)factory;
/* Create socket */
status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
status = pj_sock_socket(rem_addr->addr.sa_family, pj_SOCK_STREAM(),
0, &sock);
if (status != PJ_SUCCESS)
return status;
@ -884,15 +897,20 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
2, listener->factory.obj_name,
"outgoing SIP TCP socket");
/* Bind to any port */
status = pj_sock_bind_in(sock, 0, 0);
/* Bind to listener's address and any port */
pj_bzero(&local_addr, sizeof(local_addr));
pj_sockaddr_cp(&local_addr, &listener->bound_addr);
pj_sockaddr_set_port(&local_addr, 0);
status = pj_sock_bind(sock, &local_addr,
pj_sockaddr_get_len(&local_addr));
if (status != PJ_SUCCESS) {
pj_sock_close(sock);
return status;
}
/* Get the local port */
addr_len = sizeof(pj_sockaddr_in);
addr_len = sizeof(local_addr);
status = pj_sock_getsockname(sock, &local_addr, &addr_len);
if (status != PJ_SUCCESS) {
pj_sock_close(sock);
@ -900,12 +918,13 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
}
/* Initially set the address from the listener's address */
local_addr.sin_addr.s_addr =
((pj_sockaddr_in*)&listener->factory.local_addr)->sin_addr.s_addr;
if (!pj_sockaddr_has_addr(&local_addr)) {
pj_sockaddr_copy_addr(&local_addr, &listener->factory.local_addr);
}
/* Create the transport descriptor */
status = tcp_create(listener, NULL, sock, PJ_FALSE, &local_addr,
(pj_sockaddr_in*)rem_addr, &tcp);
rem_addr, &tcp);
if (status != PJ_SUCCESS)
return status;
@ -913,7 +932,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
/* Start asynchronous connect() operation */
tcp->has_pending_connect = PJ_TRUE;
status = pj_activesock_start_connect(tcp->asock, tcp->base.pool, rem_addr,
sizeof(pj_sockaddr_in));
addr_len);
if (status == PJ_SUCCESS) {
on_connect_complete(tcp->asock, PJ_SUCCESS);
} else if (status != PJ_EPENDING) {
@ -925,18 +944,17 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
/* Update (again) local address, just in case local address currently
* set is different now that asynchronous connect() is started.
*/
addr_len = sizeof(pj_sockaddr_in);
addr_len = sizeof(local_addr);
if (pj_sock_getsockname(sock, &local_addr, &addr_len)==PJ_SUCCESS) {
pj_sockaddr_in *tp_addr = (pj_sockaddr_in*)&tcp->base.local_addr;
pj_sockaddr *tp_addr = &tcp->base.local_addr;
/* Some systems (like old Win32 perhaps) may not set local address
* properly before socket is fully connected.
*/
if (tp_addr->sin_addr.s_addr != local_addr.sin_addr.s_addr &&
local_addr.sin_addr.s_addr != 0)
if (pj_sockaddr_cmp(tp_addr, &local_addr) &&
pj_sockaddr_get_port(&local_addr) != 0)
{
tp_addr->sin_addr.s_addr = local_addr.sin_addr.s_addr;
tp_addr->sin_port = local_addr.sin_port;
pj_sockaddr_cp(tp_addr, &local_addr);
sockaddr_to_host_port(tcp->base.pool, &tcp->base.local_name,
&local_addr);
}
@ -972,6 +990,7 @@ static pj_bool_t on_accept_complete(pj_activesock_t *asock,
struct tcp_transport *tcp;
char addr[PJ_INET6_ADDRSTRLEN+10];
pjsip_tp_state_callback state_cb;
pj_sockaddr tmp_src_addr;
pj_status_t status;
PJ_UNUSED_ARG(src_addr_len);
@ -995,13 +1014,19 @@ static pj_bool_t on_accept_complete(pj_activesock_t *asock,
2, listener->factory.obj_name,
"incoming SIP TCP socket");
/* tcp_create() expect pj_sockaddr, so copy src_addr to temporary var,
* just in case.
*/
pj_bzero(&tmp_src_addr, sizeof(tmp_src_addr));
pj_sockaddr_cp(&tmp_src_addr, src_addr);
/*
* Incoming connection!
* Create TCP transport for the new socket.
*/
status = tcp_create( listener, NULL, sock, PJ_TRUE,
(const pj_sockaddr_in*)&listener->factory.local_addr,
(const pj_sockaddr_in*)src_addr, &tcp);
&listener->factory.local_addr,
&tmp_src_addr, &tcp);
if (status == PJ_SUCCESS) {
status = tcp_start_read(tcp);
if (status != PJ_SUCCESS) {
@ -1105,9 +1130,9 @@ static pj_status_t tcp_send_msg(pjsip_transport *transport,
PJ_ASSERT_RETURN(tdata->op_key.tdata == NULL, PJSIP_EPENDINGTX);
/* Check the address is supported */
PJ_ASSERT_RETURN(rem_addr && addr_len==sizeof(pj_sockaddr_in), PJ_EINVAL);
PJ_ASSERT_RETURN(rem_addr && (addr_len==sizeof(pj_sockaddr_in) ||
addr_len==sizeof(pj_sockaddr_in6)),
PJ_EINVAL);
/* Init op key. */
tdata->op_key.tdata = tdata;
@ -1288,7 +1313,7 @@ static pj_bool_t on_connect_complete(pj_activesock_t *asock,
pj_status_t status)
{
struct tcp_transport *tcp;
pj_sockaddr_in addr;
pj_sockaddr addr;
int addrlen;
pjsip_tp_state_callback state_cb;
@ -1333,15 +1358,14 @@ static pj_bool_t on_connect_complete(pj_activesock_t *asock,
* set is different now that the socket is connected (could happen
* on some systems, like old Win32 probably?).
*/
addrlen = sizeof(pj_sockaddr_in);
addrlen = sizeof(addr);
if (pj_sock_getsockname(tcp->sock, &addr, &addrlen)==PJ_SUCCESS) {
pj_sockaddr_in *tp_addr = (pj_sockaddr_in*)&tcp->base.local_addr;
pj_sockaddr *tp_addr = &tcp->base.local_addr;
if (pj_sockaddr_has_addr(&addr) &&
tp_addr->sin_addr.s_addr != addr.sin_addr.s_addr)
pj_sockaddr_cmp(&addr, tp_addr) != 0)
{
tp_addr->sin_addr.s_addr = addr.sin_addr.s_addr;
tp_addr->sin_port = addr.sin_port;
pj_sockaddr_cp(tp_addr, &addr);
sockaddr_to_host_port(tcp->base.pool, &tcp->base.local_name,
tp_addr);
}

View File

@ -55,6 +55,7 @@ struct tls_listener
pjsip_endpoint *endpt;
pjsip_tpmgr *tpmgr;
pj_ssl_sock_t *ssock;
pj_sockaddr bound_addr;
pj_ssl_cert_t *cert;
pjsip_tls_setting tls_setting;
};
@ -147,8 +148,8 @@ static pj_status_t tls_create(struct tls_listener *listener,
pj_pool_t *pool,
pj_ssl_sock_t *ssock,
pj_bool_t is_server,
const pj_sockaddr_in *local,
const pj_sockaddr_in *remote,
const pj_sockaddr *local,
const pj_sockaddr *remote,
const pj_str_t *remote_name,
struct tls_transport **p_tls);
@ -166,10 +167,10 @@ static void tls_perror(const char *sender, const char *title,
static void sockaddr_to_host_port( pj_pool_t *pool,
pjsip_host_port *host_port,
const pj_sockaddr_in *addr )
const pj_sockaddr *addr )
{
host_port->host.ptr = (char*) pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+4);
pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 2);
pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 0);
host_port->host.slen = pj_ansi_strlen(host_port->host.ptr);
host_port->port = pj_sockaddr_get_port(addr);
}
@ -235,29 +236,50 @@ static void tls_init_shutdown(struct tls_transport *tls, pj_status_t status)
*/
PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
const pjsip_tls_setting *opt,
const pj_sockaddr_in *local,
const pj_sockaddr_in *local_in,
const pjsip_host_port *a_name,
unsigned async_cnt,
pjsip_tpfactory **p_factory)
{
pj_sockaddr local;
if (local_in)
pj_sockaddr_cp(&local, local_in);
return pjsip_tls_transport_start2(endpt, opt, (local_in? &local : NULL),
a_name, async_cnt, p_factory);
}
PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt,
const pjsip_tls_setting *opt,
const pj_sockaddr *local,
const pjsip_host_port *a_name,
unsigned async_cnt,
pjsip_tpfactory **p_factory)
{
pj_pool_t *pool;
pj_bool_t is_ipv6;
int af;
struct tls_listener *listener;
pj_ssl_sock_param ssock_param;
pj_sockaddr_in *listener_addr;
pj_sockaddr *listener_addr;
pj_bool_t has_listener;
pj_status_t status;
/* Sanity check */
PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);
is_ipv6 = (local && local->addr.sa_family == pj_AF_INET6());
af = is_ipv6 ? pj_AF_INET6() : pj_AF_INET();
/* Verify that address given in a_name (if any) is valid */
if (a_name && a_name->host.slen) {
pj_sockaddr_in tmp;
pj_sockaddr tmp;
status = pj_sockaddr_in_init(&tmp, &a_name->host,
(pj_uint16_t)a_name->port);
if (status != PJ_SUCCESS || tmp.sin_addr.s_addr == PJ_INADDR_ANY ||
tmp.sin_addr.s_addr == PJ_INADDR_NONE)
status = pj_sockaddr_init(af, &tmp, &a_name->host,
(pj_uint16_t)a_name->port);
if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
(!is_ipv6 && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE))
{
/* Invalid address */
return PJ_EINVAL;
@ -270,19 +292,25 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
listener = PJ_POOL_ZALLOC_T(pool, struct tls_listener);
listener->factory.pool = pool;
listener->factory.type = PJSIP_TRANSPORT_TLS;
listener->factory.type_name = "tls";
if (is_ipv6)
listener->factory.type = PJSIP_TRANSPORT_TLS6;
else
listener->factory.type = PJSIP_TRANSPORT_TLS;
listener->factory.type_name = (char*)
pjsip_transport_get_type_name(listener->factory.type);
listener->factory.flag =
pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS);
pjsip_transport_get_flag_from_type(listener->factory.type);
pj_ansi_strcpy(listener->factory.obj_name, "tlslis");
if (is_ipv6)
pj_ansi_strcat(listener->factory.obj_name, "6");
if (opt)
pjsip_tls_setting_copy(pool, &listener->tls_setting, opt);
else
pjsip_tls_setting_default(&listener->tls_setting);
status = pj_lock_create_recursive_mutex(pool, "tlslis",
status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
&listener->factory.lock);
if (status != PJ_SUCCESS)
goto on_error;
@ -292,6 +320,7 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
/* Build SSL socket param */
pj_ssl_sock_param_default(&ssock_param);
ssock_param.sock_af = af;
ssock_param.cb.on_accept_complete = &on_accept_complete;
ssock_param.cb.on_data_read = &on_data_read;
ssock_param.cb.on_data_sent = &on_data_sent;
@ -338,12 +367,17 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
if (status != PJ_SUCCESS)
goto on_error;
listener_addr = (pj_sockaddr_in*)&listener->factory.local_addr;
/* Bind address may be different than factory.local_addr because
* factory.local_addr will be resolved below.
*/
listener_addr = &listener->factory.local_addr;
if (local) {
pj_sockaddr_cp((pj_sockaddr_t*)listener_addr,
(const pj_sockaddr_t*)local);
pj_sockaddr_cp(&listener->bound_addr, local);
} else {
pj_sockaddr_in_init(listener_addr, NULL, 0);
pj_sockaddr_init(af, listener_addr, NULL, 0);
pj_sockaddr_init(af, &listener->bound_addr, NULL, 0);
}
/* Check if certificate/CA list for SSL socket is set */
@ -401,14 +435,14 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
/* If the address returns 0.0.0.0, use the default
* interface address as the transport's address.
*/
if (listener_addr->sin_addr.s_addr == 0) {
if (!pj_sockaddr_has_addr(listener_addr)) {
pj_sockaddr hostip;
status = pj_gethostip(pj_AF_INET(), &hostip);
status = pj_gethostip(af, &hostip);
if (status != PJ_SUCCESS)
goto on_error;
listener_addr->sin_addr.s_addr = hostip.ipv4.sin_addr.s_addr;
pj_sockaddr_copy_addr(listener_addr, &hostip);
}
/* Save the address name */
@ -418,7 +452,7 @@ PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
/* If port is zero, get the bound port */
if (listener->factory.addr_name.port == 0) {
listener->factory.addr_name.port = pj_ntohs(listener_addr->sin_port);
listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
}
pj_ansi_snprintf(listener->factory.obj_name,
@ -535,13 +569,14 @@ static pj_status_t tls_create( struct tls_listener *listener,
pj_pool_t *pool,
pj_ssl_sock_t *ssock,
pj_bool_t is_server,
const pj_sockaddr_in *local,
const pj_sockaddr_in *remote,
const pj_sockaddr *local,
const pj_sockaddr *remote,
const pj_str_t *remote_name,
struct tls_transport **p_tls)
{
struct tls_transport *tls;
const pj_str_t ka_pkt = PJSIP_TLS_KEEP_ALIVE_DATA;
char print_addr[PJ_INET6_ADDRSTRLEN+10];
pj_status_t status;
@ -579,17 +614,20 @@ static pj_status_t tls_create( struct tls_listener *listener,
if (remote_name)
pj_strdup(pool, &tls->remote_name, remote_name);
tls->base.key.type = PJSIP_TRANSPORT_TLS;
pj_memcpy(&tls->base.key.rem_addr, remote, sizeof(pj_sockaddr_in));
tls->base.type_name = "tls";
tls->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS);
tls->base.key.type = listener->factory.type;
pj_sockaddr_cp(&tls->base.key.rem_addr, remote);
tls->base.type_name = (char*)
pjsip_transport_get_type_name(tls->base.key.type);
tls->base.flag = pjsip_transport_get_flag_from_type(tls->base.key.type);
tls->base.info = (char*) pj_pool_alloc(pool, 64);
pj_ansi_snprintf(tls->base.info, 64, "TLS to %s:%d",
pj_inet_ntoa(remote->sin_addr),
(int)pj_ntohs(remote->sin_port));
pj_ansi_snprintf(tls->base.info, 64, "%s to %s",
tls->base.type_name,
pj_sockaddr_print(remote, print_addr,
sizeof(print_addr), 3));
tls->base.addr_len = sizeof(pj_sockaddr_in);
tls->base.addr_len = pj_sockaddr_get_len(remote);
tls->base.dir = is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING;
/* Set initial local address */
@ -600,11 +638,10 @@ static pj_status_t tls_create( struct tls_listener *listener,
pj_sockaddr_cp(&tls->base.local_addr, local);
}
sockaddr_to_host_port(pool, &tls->base.local_name,
(pj_sockaddr_in*)&tls->base.local_addr);
sockaddr_to_host_port(pool, &tls->base.local_name, &tls->base.local_addr);
if (tls->remote_name.slen) {
tls->base.remote_name.host = tls->remote_name;
tls->base.remote_name.port = pj_sockaddr_in_get_port(remote);
tls->base.remote_name.port = pj_sockaddr_get_port(remote);
} else {
sockaddr_to_host_port(pool, &tls->base.remote_name, remote);
}
@ -794,7 +831,7 @@ static pj_status_t tls_start_read(struct tls_transport *tls)
{
pj_pool_t *pool;
pj_ssize_t size;
pj_sockaddr_in *rem_addr;
pj_sockaddr *rem_addr;
void *readbuf[1];
pj_status_t status;
@ -817,11 +854,11 @@ static pj_status_t tls_start_read(struct tls_transport *tls)
sizeof(pj_ioqueue_op_key_t));
tls->rdata.pkt_info.src_addr = tls->base.key.rem_addr;
tls->rdata.pkt_info.src_addr_len = sizeof(pj_sockaddr_in);
rem_addr = (pj_sockaddr_in*) &tls->base.key.rem_addr;
pj_ansi_strcpy(tls->rdata.pkt_info.src_name,
pj_inet_ntoa(rem_addr->sin_addr));
tls->rdata.pkt_info.src_port = pj_ntohs(rem_addr->sin_port);
tls->rdata.pkt_info.src_addr_len = sizeof(tls->rdata.pkt_info.src_addr);
rem_addr = &tls->base.key.rem_addr;
pj_sockaddr_print(rem_addr, tls->rdata.pkt_info.src_name,
sizeof(tls->rdata.pkt_info.src_name), 0);
tls->rdata.pkt_info.src_port = pj_sockaddr_get_port(rem_addr);
size = sizeof(tls->rdata.pkt_info.packet);
readbuf[0] = tls->rdata.pkt_info.packet;
@ -854,7 +891,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
pj_pool_t *pool;
pj_ssl_sock_t *ssock;
pj_ssl_sock_param ssock_param;
pj_sockaddr_in local_addr;
pj_sockaddr local_addr;
pj_str_t remote_name;
pj_status_t status;
@ -862,9 +899,11 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
PJ_ASSERT_RETURN(factory && mgr && endpt && rem_addr &&
addr_len && p_transport, PJ_EINVAL);
/* Check that address is a sockaddr_in */
PJ_ASSERT_RETURN(rem_addr->addr.sa_family == pj_AF_INET() &&
addr_len == sizeof(pj_sockaddr_in), PJ_EINVAL);
/* Check that address is a sockaddr_in or sockaddr_in6*/
PJ_ASSERT_RETURN((rem_addr->addr.sa_family == pj_AF_INET() &&
addr_len == sizeof(pj_sockaddr_in)) ||
(rem_addr->addr.sa_family == pj_AF_INET6() &&
addr_len == sizeof(pj_sockaddr_in6)), PJ_EINVAL);
listener = (struct tls_listener*)factory;
@ -881,6 +920,8 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
/* Build SSL socket param */
pj_ssl_sock_param_default(&ssock_param);
ssock_param.sock_af = (factory->type & PJSIP_TRANSPORT_IPV6) ?
pj_AF_INET6() : pj_AF_INET();
ssock_param.cb.on_connect_complete = &on_connect_complete;
ssock_param.cb.on_data_read = &on_data_read;
ssock_param.cb.on_data_sent = &on_data_sent;
@ -931,12 +972,14 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
return status;
}
/* Initially set bind address to PJ_INADDR_ANY port 0 */
pj_sockaddr_in_init(&local_addr, NULL, 0);
/* Initially set bind address to listener's bind address */
pj_sockaddr_init(listener->bound_addr.addr.sa_family,
&local_addr, NULL, 0);
pj_sockaddr_copy_addr(&local_addr, &listener->bound_addr);
/* Create the transport descriptor */
status = tls_create(listener, pool, ssock, PJ_FALSE, &local_addr,
(pj_sockaddr_in*)rem_addr, &remote_name, &tls);
rem_addr, &remote_name, &tls);
if (status != PJ_SUCCESS)
return status;
@ -983,7 +1026,7 @@ static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
}
sockaddr_to_host_port(tls->base.pool, &tls->base.local_name,
(pj_sockaddr_in*)&tls->base.local_addr);
&tls->base.local_addr);
}
PJ_LOG(4,(tls->base.obj_name,
@ -1017,6 +1060,7 @@ static pj_bool_t on_accept_complete(pj_ssl_sock_t *ssock,
pj_ssl_sock_info ssl_info;
char addr[PJ_INET6_ADDRSTRLEN+10];
pjsip_tp_state_callback state_cb;
pj_sockaddr tmp_src_addr;
pj_bool_t is_shutdown;
pj_status_t status;
@ -1044,13 +1088,17 @@ static pj_bool_t on_accept_complete(pj_ssl_sock_t *ssock,
return PJ_TRUE;
}
/* Copy to larger buffer, just in case */
pj_bzero(&tmp_src_addr, sizeof(tmp_src_addr));
pj_sockaddr_cp(&tmp_src_addr, src_addr);
/*
* Incoming connection!
* Create TLS transport for the new socket.
*/
status = tls_create( listener, NULL, new_ssock, PJ_TRUE,
(const pj_sockaddr_in*)&listener->factory.local_addr,
(const pj_sockaddr_in*)src_addr, NULL, &tls);
&listener->factory.local_addr,
&tmp_src_addr, NULL, &tls);
if (status != PJ_SUCCESS)
return PJ_TRUE;
@ -1200,9 +1248,9 @@ static pj_status_t tls_send_msg(pjsip_transport *transport,
PJ_ASSERT_RETURN(tdata->op_key.tdata == NULL, PJSIP_EPENDINGTX);
/* Check the address is supported */
PJ_ASSERT_RETURN(rem_addr && addr_len==sizeof(pj_sockaddr_in), PJ_EINVAL);
PJ_ASSERT_RETURN(rem_addr && (addr_len==sizeof(pj_sockaddr_in) ||
addr_len==sizeof(pj_sockaddr_in6)),
PJ_EINVAL);
/* Init op key. */
tdata->op_key.tdata = tdata;
@ -1384,7 +1432,7 @@ static pj_bool_t on_connect_complete(pj_ssl_sock_t *ssock,
{
struct tls_transport *tls;
pj_ssl_sock_info ssl_info;
pj_sockaddr_in addr, *tp_addr;
pj_sockaddr addr, *tp_addr;
pjsip_tp_state_callback state_cb;
pj_bool_t is_shutdown;
@ -1422,12 +1470,11 @@ static pj_bool_t on_connect_complete(pj_ssl_sock_t *ssock,
* set is different now that the socket is connected (could happen
* on some systems, like old Win32 probably?).
*/
tp_addr = (pj_sockaddr_in*)&tls->base.local_addr;
tp_addr = &tls->base.local_addr;
pj_sockaddr_cp((pj_sockaddr_t*)&addr,
(pj_sockaddr_t*)&ssl_info.local_addr);
if (tp_addr->sin_addr.s_addr != addr.sin_addr.s_addr) {
tp_addr->sin_addr.s_addr = addr.sin_addr.s_addr;
tp_addr->sin_port = addr.sin_port;
if (pj_sockaddr_cmp(tp_addr, &addr) != 0) {
pj_sockaddr_cp(tp_addr, &addr);
sockaddr_to_host_port(tls->base.pool, &tls->base.local_name,
tp_addr);
}

View File

@ -1190,6 +1190,8 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id,
acc->cfg.rtp_cfg = cfg->rtp_cfg;
}
acc->cfg.ipv6_media_use = cfg->ipv6_media_use;
/* STUN and Media customization */
if (acc->cfg.sip_stun_use != cfg->sip_stun_use) {
acc->cfg.sip_stun_use = cfg->sip_stun_use;

View File

@ -2067,8 +2067,10 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
pjsua_transport_config config;
pjsip_tpfactory *tcp;
pjsip_tcp_transport_cfg tcp_cfg;
int af;
pjsip_tcp_transport_cfg_default(&tcp_cfg, pj_AF_INET());
af = (type==PJSIP_TRANSPORT_TCP6) ? pj_AF_INET6() : pj_AF_INET();
pjsip_tcp_transport_cfg_default(&tcp_cfg, af);
/* Supply default config if it's not specified */
if (cfg == NULL) {
@ -2118,14 +2120,15 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
#endif /* PJ_HAS_TCP */
#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
} else if (type == PJSIP_TRANSPORT_TLS) {
} else if (type == PJSIP_TRANSPORT_TLS || type == PJSIP_TRANSPORT_TLS6) {
/*
* Create TLS transport.
*/
pjsua_transport_config config;
pjsip_host_port a_name;
pjsip_tpfactory *tls;
pj_sockaddr_in local_addr;
pj_sockaddr local_addr;
int af;
/* Supply default config if it's not specified */
if (cfg == NULL) {
@ -2135,13 +2138,15 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
}
/* Init local address */
pj_sockaddr_in_init(&local_addr, 0, 0);
af = (type==PJSIP_TRANSPORT_TLS) ? pj_AF_INET() : pj_AF_INET6();
pj_sockaddr_init(af, &local_addr, NULL, 0);
if (cfg->port)
local_addr.sin_port = pj_htons((pj_uint16_t)cfg->port);
pj_sockaddr_set_port(&local_addr, (pj_uint16_t)cfg->port);
if (cfg->bound_addr.slen) {
status = pj_sockaddr_in_set_str_addr(&local_addr,&cfg->bound_addr);
status = pj_sockaddr_set_str_addr(af, &local_addr,
&cfg->bound_addr);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE,
"Unable to resolve transport bound address",
@ -2155,9 +2160,9 @@ PJ_DEF(pj_status_t) pjsua_transport_create( pjsip_transport_type_e type,
if (cfg->public_addr.slen)
a_name.host = cfg->public_addr;
status = pjsip_tls_transport_start(pjsua_var.endpt,
&cfg->tls_setting,
&local_addr, &a_name, 1, &tls);
status = pjsip_tls_transport_start2(pjsua_var.endpt,
&cfg->tls_setting,
&local_addr, &a_name, 1, &tls);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error creating SIP TLS listener",
status);

View File

@ -236,14 +236,20 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
RTP_RETRY = 100
};
int i;
pj_sockaddr_in bound_addr;
pj_sockaddr_in mapped_addr[2];
pj_bool_t use_ipv6;
int af;
pj_sockaddr bound_addr;
pj_sockaddr mapped_addr[2];
pj_status_t status = PJ_SUCCESS;
char addr_buf[PJ_INET6_ADDRSTRLEN+2];
char addr_buf[PJ_INET6_ADDRSTRLEN+10];
pj_sock_t sock[2];
use_ipv6 = (pjsua_var.acc[call_med->call->acc_id].cfg.ipv6_media_use !=
PJSUA_IPV6_DISABLED);
af = use_ipv6 ? pj_AF_INET6() : pj_AF_INET();
/* Make sure STUN server resolution has completed */
if (pjsua_sip_acc_is_using_stun(call_med->call->acc_id)) {
if (!use_ipv6 && pjsua_sip_acc_is_using_stun(call_med->call->acc_id)) {
status = resolve_stun_server(PJ_TRUE);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Error resolving STUN server", status);
@ -260,9 +266,9 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
for (i=0; i<2; ++i)
sock[i] = PJ_INVALID_SOCKET;
bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;
pj_sockaddr_init(af, &bound_addr, NULL, 0);
if (cfg->bound_addr.slen) {
status = pj_sockaddr_in_set_str_addr(&bound_addr, &cfg->bound_addr);
status = pj_sockaddr_set_str_addr(af, &bound_addr, &cfg->bound_addr);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to resolve transport bind address",
status);
@ -274,7 +280,7 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
for (i=0; i<RTP_RETRY; ++i, next_rtp_port += 2) {
/* Create RTP socket. */
status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[0]);
status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock[0]);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "socket() error", status);
return status;
@ -286,8 +292,9 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
2, THIS_FILE, "RTP socket");
/* Bind RTP socket */
status=pj_sock_bind_in(sock[0], pj_ntohl(bound_addr.sin_addr.s_addr),
next_rtp_port);
pj_sockaddr_set_port(&bound_addr, next_rtp_port);
status=pj_sock_bind(sock[0], &bound_addr,
pj_sockaddr_get_len(&bound_addr));
if (status != PJ_SUCCESS) {
pj_sock_close(sock[0]);
sock[0] = PJ_INVALID_SOCKET;
@ -295,7 +302,7 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
}
/* Create RTCP socket. */
status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock[1]);
status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &sock[1]);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "socket() error", status);
pj_sock_close(sock[0]);
@ -308,8 +315,9 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
2, THIS_FILE, "RTCP socket");
/* Bind RTCP socket */
status=pj_sock_bind_in(sock[1], pj_ntohl(bound_addr.sin_addr.s_addr),
(pj_uint16_t)(next_rtp_port+1));
pj_sockaddr_set_port(&bound_addr, (pj_uint16_t)(next_rtp_port+1));
status=pj_sock_bind(sock[1], &bound_addr,
pj_sockaddr_get_len(&bound_addr));
if (status != PJ_SUCCESS) {
pj_sock_close(sock[0]);
sock[0] = PJ_INVALID_SOCKET;
@ -323,11 +331,12 @@ 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 (pjsua_sip_acc_is_using_stun(call_med->call->acc_id) &&
if (!use_ipv6 && pjsua_sip_acc_is_using_stun(call_med->call->acc_id) &&
pjsua_var.stun_srv.addr.sa_family != 0)
{
char ip_addr[32];
pj_str_t stun_srv;
pj_sockaddr_in resolved_addr[2];
pjstun_setting stun_opt;
pj_ansi_strcpy(ip_addr,
@ -340,15 +349,18 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
stun_opt.port1 = stun_opt.port2 =
pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port);
status=pjstun_get_mapped_addr2(&pjsua_var.cp.factory, &stun_opt,
2, sock, mapped_addr);
2, sock, resolved_addr);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "STUN resolve error", status);
goto on_error;
}
pj_sockaddr_cp(&mapped_addr[0], &resolved_addr[0]);
pj_sockaddr_cp(&mapped_addr[1], &resolved_addr[1]);
#if PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT
if (pj_ntohs(mapped_addr[1].sin_port) ==
pj_ntohs(mapped_addr[0].sin_port)+1)
if (pj_sockaddr_get_port(&mapped_addr[1]) ==
pj_sockaddr_get_port(&mapped_addr[0])+1)
{
/* Success! */
break;
@ -360,14 +372,14 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
pj_sock_close(sock[1]);
sock[1] = PJ_INVALID_SOCKET;
#else
if (pj_ntohs(mapped_addr[1].sin_port) !=
pj_ntohs(mapped_addr[0].sin_port)+1)
if (pj_sockaddr_get_port(&mapped_addr[1]) !=
pj_sockaddr_get_port(&mapped_addr[0])+1)
{
PJ_LOG(4,(THIS_FILE,
"Note: STUN mapped RTCP port %d is not adjacent"
" to RTP port %d",
pj_ntohs(mapped_addr[1].sin_port),
pj_ntohs(mapped_addr[0].sin_port)));
pj_sockaddr_get_port(&mapped_addr[1]),
pj_sockaddr_get_port(&mapped_addr[0])));
}
/* Success! */
break;
@ -375,13 +387,13 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
} else if (cfg->public_addr.slen) {
status = pj_sockaddr_in_init(&mapped_addr[0], &cfg->public_addr,
(pj_uint16_t)next_rtp_port);
status = pj_sockaddr_init(af, &mapped_addr[0], &cfg->public_addr,
(pj_uint16_t)next_rtp_port);
if (status != PJ_SUCCESS)
goto on_error;
status = pj_sockaddr_in_init(&mapped_addr[1], &cfg->public_addr,
(pj_uint16_t)(next_rtp_port+1));
status = pj_sockaddr_init(af, &mapped_addr[1], &cfg->public_addr,
(pj_uint16_t)(next_rtp_port+1));
if (status != PJ_SUCCESS)
goto on_error;
@ -389,24 +401,24 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
} else {
if (bound_addr.sin_addr.s_addr == 0) {
if (!pj_sockaddr_has_addr(&bound_addr)) {
pj_sockaddr addr;
/* Get local IP address. */
status = pj_gethostip(pj_AF_INET(), &addr);
status = pj_gethostip(af, &addr);
if (status != PJ_SUCCESS)
goto on_error;
bound_addr.sin_addr.s_addr = addr.ipv4.sin_addr.s_addr;
pj_sockaddr_copy_addr(&bound_addr, &addr);
}
for (i=0; i<2; ++i) {
pj_sockaddr_in_init(&mapped_addr[i], NULL, 0);
mapped_addr[i].sin_addr.s_addr = bound_addr.sin_addr.s_addr;
pj_sockaddr_init(af, &mapped_addr[i], NULL, 0);
pj_sockaddr_copy_addr(&mapped_addr[i], &bound_addr);
pj_sockaddr_set_port(&mapped_addr[i],
(pj_uint16_t)(next_rtp_port+i));
}
mapped_addr[0].sin_port=pj_htons((pj_uint16_t)next_rtp_port);
mapped_addr[1].sin_port=pj_htons((pj_uint16_t)(next_rtp_port+1));
break;
}
}
@ -419,12 +431,10 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med,
skinfo->rtp_sock = sock[0];
pj_memcpy(&skinfo->rtp_addr_name,
&mapped_addr[0], sizeof(pj_sockaddr_in));
pj_sockaddr_cp(&skinfo->rtp_addr_name, &mapped_addr[0]);
skinfo->rtcp_sock = sock[1];
pj_memcpy(&skinfo->rtcp_addr_name,
&mapped_addr[1], sizeof(pj_sockaddr_in));
pj_sockaddr_cp(&skinfo->rtcp_addr_name, &mapped_addr[1]);
PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s",
pj_sockaddr_print(&skinfo->rtp_addr_name, addr_buf,
@ -1908,10 +1918,20 @@ 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;
use_ipv6 = (pjsua_var.acc[call->acc_id].cfg.ipv6_media_use !=
PJSUA_IPV6_DISABLED);
m->conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
m->conn->net_type = pj_str("IN");
m->conn->addr_type = pj_str("IP4");
m->conn->addr = pj_str("127.0.0.1");
if (use_ipv6) {
m->conn->addr_type = pj_str("IP6");
m->conn->addr = pj_str("::1");
} else {
m->conn->addr_type = pj_str("IP4");
m->conn->addr = pj_str("127.0.0.1");
}
}
sdp->media[sdp->media_count++] = m;