summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2012-09-20 06:00:23 +0000
committerBenny Prijono <bennylp@teluu.com>2012-09-20 06:00:23 +0000
commitc1da22781bc970d7948f35e5fa6ede7b54f45549 (patch)
tree238d85c1b6e1375c207486e9f2c2f22188ae49ca
parent8a001ec6f6a9c628eff9fbd9c9a478d127ed12d3 (diff)
Fixed #1585: IPv6 support for SIP TCP and TLS transports and PJSUA-LIB v2
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@4262 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjsip-apps/src/pjsua/pjsua_app.c167
-rw-r--r--pjsip/include/pjsip/sip_transport_tls.h40
-rw-r--r--pjsip/include/pjsip/sip_types.h5
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h22
-rw-r--r--pjsip/src/pjsip/sip_transport.c24
-rw-r--r--pjsip/src/pjsip/sip_transport_tcp.c146
-rw-r--r--pjsip/src/pjsip/sip_transport_tls.c163
-rw-r--r--pjsip/src/pjsua-lib/pjsua_acc.c2
-rw-r--r--pjsip/src/pjsua-lib/pjsua_core.c23
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c94
10 files changed, 410 insertions, 276 deletions
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index b6a253c7..494520e7 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -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
-}
-
diff --git a/pjsip/include/pjsip/sip_transport_tls.h b/pjsip/include/pjsip/sip_transport_tls.h
index ae823f36..1f8ee431 100644
--- a/pjsip/include/pjsip/sip_transport_tls.h
+++ b/pjsip/include/pjsip/sip_transport_tls.h
@@ -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
diff --git a/pjsip/include/pjsip/sip_types.h b/pjsip/include/pjsip/sip_types.h
index 2d863be0..d212dd2e 100644
--- a/pjsip/include/pjsip/sip_types.h
+++ b/pjsip/include/pjsip/sip_types.h
@@ -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;
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index 922190a3..ad8e519c 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -2690,6 +2690,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
* this structure first by calling #pjsua_acc_config_default().
@@ -3090,6 +3107,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.
*
* Default: PJSUA_STUN_USE_DEFAULT
diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index 76a1eb11..0215a7b0 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -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);
}
diff --git a/pjsip/src/pjsip/sip_transport_tcp.c b/pjsip/src/pjsip/sip_transport_tcp.c
index 967d0670..9de8311c 100644
--- a/pjsip/src/pjsip/sip_transport_tcp.c
+++ b/pjsip/src/pjsip/sip_transport_tcp.c
@@ -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);
}
diff --git a/pjsip/src/pjsip/sip_transport_tls.c b/pjsip/src/pjsip/sip_transport_tls.c
index f0e7081f..f16625fc 100644
--- a/pjsip/src/pjsip/sip_transport_tls.c
+++ b/pjsip/src/pjsip/sip_transport_tls.c
@@ -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);
}
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index caad41b6..105e24d1 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -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;
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index f0b44119..fd6ab3bf 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -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);
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index 483df783..3c1d16e8 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -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;