diff options
author | Benny Prijono <bennylp@teluu.com> | 2012-09-20 06:00:23 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2012-09-20 06:00:23 +0000 |
commit | c1da22781bc970d7948f35e5fa6ede7b54f45549 (patch) | |
tree | 238d85c1b6e1375c207486e9f2c2f22188ae49ca | |
parent | 8a001ec6f6a9c628eff9fbd9c9a478d127ed12d3 (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.c | 167 | ||||
-rw-r--r-- | pjsip/include/pjsip/sip_transport_tls.h | 40 | ||||
-rw-r--r-- | pjsip/include/pjsip/sip_types.h | 5 | ||||
-rw-r--r-- | pjsip/include/pjsua-lib/pjsua.h | 22 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_transport.c | 24 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_transport_tcp.c | 146 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_transport_tls.c | 163 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_acc.c | 2 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_core.c | 23 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_media.c | 94 |
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; |