diff options
-rw-r--r-- | pjlib/include/pj/addr_resolv.h | 25 | ||||
-rw-r--r-- | pjlib/src/pj/sock_common.c | 70 | ||||
-rw-r--r-- | pjsip-apps/src/pjsua/pjsua_app.c | 162 | ||||
-rw-r--r-- | pjsip/include/pjsip/sip_transport.h | 72 | ||||
-rw-r--r-- | pjsip/include/pjsua-lib/pjsua.h | 204 | ||||
-rw-r--r-- | pjsip/include/pjsua-lib/pjsua_internal.h | 14 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_transport.c | 138 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_acc.c | 249 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_call.c | 2 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_core.c | 62 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_media.c | 50 |
11 files changed, 865 insertions, 183 deletions
diff --git a/pjlib/include/pj/addr_resolv.h b/pjlib/include/pj/addr_resolv.h index 096dde14..7e89936c 100644 --- a/pjlib/include/pj/addr_resolv.h +++ b/pjlib/include/pj/addr_resolv.h @@ -117,6 +117,31 @@ PJ_DECL(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr); /** + * Get the interface IP address to send data to the specified destination. + * + * @param af The desired address family to query. Valid values + * are pj_AF_INET() or pj_AF_INET6(). + * @param dst The destination host. + * @param itf_addr On successful resolution, the address family and address + * part of this socket address will be filled up with the host + * IP address, in network byte order. Other parts of the socket + * address should be ignored. + * @param allow_resolve If \a dst may contain hostname (instead of IP + * address), specify whether hostname resolution should + * be performed. If not, default interface address will + * be returned. + * @param p_dst_addr If not NULL, it will be filled with the IP address of + * the destination host. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pj_getipinterface(int af, + const pj_str_t *dst, + pj_sockaddr *itf_addr, + pj_bool_t allow_resolve, + pj_sockaddr *p_dst_addr); + +/** * Get the IP address of the default interface. Default interface is the * interface of the default route. * diff --git a/pjlib/src/pj/sock_common.c b/pjlib/src/pj/sock_common.c index 948d47da..7aaf6689 100644 --- a/pjlib/src/pj/sock_common.c +++ b/pjlib/src/pj/sock_common.c @@ -956,42 +956,54 @@ PJ_DEF(pj_status_t) pj_gethostip(int af, pj_sockaddr *addr) return PJ_SUCCESS; } -/* Get the default IP interface */ -PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr) +/* Get IP interface for sending to the specified destination */ +PJ_DEF(pj_status_t) pj_getipinterface(int af, + const pj_str_t *dst, + pj_sockaddr *itf_addr, + pj_bool_t allow_resolve, + pj_sockaddr *p_dst_addr) { + pj_sockaddr dst_addr; pj_sock_t fd; - pj_str_t cp; - pj_sockaddr a; int len; pj_uint8_t zero[64]; pj_status_t status; - addr->addr.sa_family = (pj_uint16_t)af; - - status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd); + pj_sockaddr_init(af, &dst_addr, NULL, 53); + status = pj_inet_pton(af, dst, pj_sockaddr_get_addr(&dst_addr)); if (status != PJ_SUCCESS) { - return status; - } + /* "dst" is not an IP address. */ + if (allow_resolve) { + status = pj_sockaddr_init(af, &dst_addr, dst, 53); + } else { + pj_str_t cp; - if (af == PJ_AF_INET) { - cp = pj_str("1.1.1.1"); - } else { - cp = pj_str("1::1"); + if (af == PJ_AF_INET) { + cp = pj_str("1.1.1.1"); + } else { + cp = pj_str("1::1"); + } + status = pj_sockaddr_init(af, &dst_addr, &cp, 53); + } + + if (status != PJ_SUCCESS) + return status; } - status = pj_sockaddr_init(af, &a, &cp, 53); + + /* Create UDP socket and connect() to the destination IP */ + status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd); if (status != PJ_SUCCESS) { - pj_sock_close(fd); return status; } - status = pj_sock_connect(fd, &a, pj_sockaddr_get_len(&a)); + status = pj_sock_connect(fd, &dst_addr, pj_sockaddr_get_len(&dst_addr)); if (status != PJ_SUCCESS) { pj_sock_close(fd); return status; } - len = sizeof(a); - status = pj_sock_getsockname(fd, &a, &len); + len = sizeof(*itf_addr); + status = pj_sock_getsockname(fd, itf_addr, &len); if (status != PJ_SUCCESS) { pj_sock_close(fd); return status; @@ -1001,18 +1013,32 @@ PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr) /* Check that the address returned is not zero */ pj_bzero(zero, sizeof(zero)); - if (pj_memcmp(pj_sockaddr_get_addr(&a), zero, - pj_sockaddr_get_addr_len(&a))==0) + if (pj_memcmp(pj_sockaddr_get_addr(itf_addr), zero, + pj_sockaddr_get_addr_len(itf_addr))==0) { return PJ_ENOTFOUND; } - pj_sockaddr_copy_addr(addr, &a); + if (p_dst_addr) + *p_dst_addr = dst_addr; - /* Success */ return PJ_SUCCESS; } +/* Get the default IP interface */ +PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr) +{ + pj_str_t cp; + + if (af == PJ_AF_INET) { + cp = pj_str("1.1.1.1"); + } else { + cp = pj_str("1::1"); + } + + return pj_getipinterface(af, &cp, addr, PJ_FALSE, NULL); +} + /* Only need to implement these in DLL build */ #if defined(PJ_DLL) diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index b8c56529..b6a253c7 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -224,14 +224,11 @@ static void usage(void) puts (""); puts ("SIP Account options:"); - puts (" --use-ims Enable 3GPP/IMS related settings on this account"); -#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) - puts (" --use-srtp=N Use SRTP? 0:disabled, 1:optional, 2:mandatory,"); - puts (" 3:optional by duplicating media offer (def:0)"); - puts (" --srtp-secure=N SRTP require secure SIP? 0:no, 1:tls, 2:sips (def:1)"); -#endif puts (" --registrar=url Set the URL of registrar server"); puts (" --id=url Set the URL of local ID (used in From header)"); + puts (" --realm=string Set realm"); + puts (" --username=string Set authentication username"); + puts (" --password=string Set authentication password"); puts (" --contact=url Optionally override the Contact information"); puts (" --contact-params=S Append the specified parameters S in Contact header"); puts (" --contact-uri-params=S Append the specified parameters S in Contact URI"); @@ -243,11 +240,14 @@ static void usage(void) PJSUA_REG_RETRY_INTERVAL); puts (" --reg-use-proxy=N Control the use of proxy settings in REGISTER."); puts (" 0=no proxy, 1=outbound only, 2=acc only, 3=all (default)"); - puts (" --realm=string Set realm"); - puts (" --username=string Set authentication username"); - puts (" --password=string Set authentication password"); puts (" --publish Send presence PUBLISH for this account"); puts (" --mwi Subscribe to message summary/waiting indication"); + puts (" --use-ims Enable 3GPP/IMS related settings on this account"); +#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) + puts (" --use-srtp=N Use SRTP? 0:disabled, 1:optional, 2:mandatory,"); + puts (" 3:optional by duplicating media offer (def:0)"); + puts (" --srtp-secure=N SRTP require secure SIP? 0:no, 1:tls, 2:sips (def:1)"); +#endif puts (" --use-100rel Require reliable provisional response (100rel)"); puts (" --use-timer=N Use SIP session timers? (default=1)"); puts (" 0:inactive, 1:optional, 2:mandatory, 3:always"); @@ -257,6 +257,7 @@ static void usage(void) puts (" --outb-rid=string Set SIP outbound reg-id (default:1)"); puts (" --auto-update-nat=N Where N is 0 or 1 to enable/disable SIP traversal behind"); puts (" symmetric NAT (default 1)"); + puts (" --disable-stun Disable STUN for this account"); puts (" --next-cred Add another credentials"); puts (""); puts ("SIP Account Control:"); @@ -589,7 +590,7 @@ static pj_status_t parse_args(int argc, char *argv[], OPT_STDOUT_NO_BUF, #endif OPT_AUTO_UPDATE_NAT,OPT_USE_COMPACT_FORM,OPT_DIS_CODEC, - OPT_NO_FORCE_LR, + OPT_DISABLE_STUN, OPT_NO_FORCE_LR, OPT_TIMER, OPT_TIMER_SE, OPT_TIMER_MIN_SE, OPT_VIDEO, OPT_EXTRA_AUDIO, OPT_VCAPTURE_DEV, OPT_VRENDER_DEV, OPT_PLAY_AVI, OPT_AUTO_PLAY_AVI @@ -629,6 +630,7 @@ static pj_status_t parse_args(int argc, char *argv[], { "contact-params",1,0, OPT_CONTACT_PARAMS}, { "contact-uri-params",1,0, OPT_CONTACT_URI_PARAMS}, { "auto-update-nat", 1, 0, OPT_AUTO_UPDATE_NAT}, + { "disable-stun",0,0, OPT_DISABLE_STUN}, { "use-compact-form", 0, 0, OPT_USE_COMPACT_FORM}, { "accept-redirect", 1, 0, OPT_ACCEPT_REDIRECT}, { "no-force-lr",0, 0, OPT_NO_FORCE_LR}, @@ -1021,6 +1023,11 @@ static pj_status_t parse_args(int argc, char *argv[], cur_acc->allow_contact_rewrite = pj_strtoul(pj_cstr(&tmp, pj_optarg)); break; + case OPT_DISABLE_STUN: + cur_acc->sip_stun_use = PJSUA_STUN_USE_DISABLED; + cur_acc->media_stun_use = PJSUA_STUN_USE_DISABLED; + break; + case OPT_USE_COMPACT_FORM: /* enable compact form - from Ticket #342 */ { @@ -1171,42 +1178,54 @@ static pj_status_t parse_args(int argc, char *argv[], break; case OPT_USE_ICE: - cfg->media_cfg.enable_ice = PJ_TRUE; + cfg->media_cfg.enable_ice = + cur_acc->ice_cfg.enable_ice = PJ_TRUE; break; case OPT_ICE_REGULAR: - cfg->media_cfg.ice_opt.aggressive = PJ_FALSE; + cfg->media_cfg.ice_opt.aggressive = + cur_acc->ice_cfg.ice_opt.aggressive = PJ_FALSE; break; case OPT_USE_TURN: - cfg->media_cfg.enable_turn = PJ_TRUE; + cfg->media_cfg.enable_turn = + cur_acc->turn_cfg.enable_turn = PJ_TRUE; break; case OPT_ICE_MAX_HOSTS: - cfg->media_cfg.ice_max_host_cands = my_atoi(pj_optarg); + cfg->media_cfg.ice_max_host_cands = + cur_acc->ice_cfg.ice_max_host_cands = my_atoi(pj_optarg); break; case OPT_ICE_NO_RTCP: - cfg->media_cfg.ice_no_rtcp = PJ_TRUE; + cfg->media_cfg.ice_no_rtcp = + cur_acc->ice_cfg.ice_no_rtcp = PJ_TRUE; break; case OPT_TURN_SRV: - cfg->media_cfg.turn_server = pj_str(pj_optarg); + cfg->media_cfg.turn_server = + cur_acc->turn_cfg.turn_server = pj_str(pj_optarg); break; case OPT_TURN_TCP: - cfg->media_cfg.turn_conn_type = PJ_TURN_TP_TCP; + cfg->media_cfg.turn_conn_type = + cur_acc->turn_cfg.turn_conn_type = PJ_TURN_TP_TCP; break; case OPT_TURN_USER: - cfg->media_cfg.turn_auth_cred.type = PJ_STUN_AUTH_CRED_STATIC; - cfg->media_cfg.turn_auth_cred.data.static_cred.realm = pj_str("*"); - cfg->media_cfg.turn_auth_cred.data.static_cred.username = pj_str(pj_optarg); + cfg->media_cfg.turn_auth_cred.type = + cur_acc->turn_cfg.turn_auth_cred.type = PJ_STUN_AUTH_CRED_STATIC; + cfg->media_cfg.turn_auth_cred.data.static_cred.realm = + cur_acc->turn_cfg.turn_auth_cred.data.static_cred.realm = pj_str("*"); + cfg->media_cfg.turn_auth_cred.data.static_cred.username = + cur_acc->turn_cfg.turn_auth_cred.data.static_cred.username = pj_str(pj_optarg); break; case OPT_TURN_PASSWD: - cfg->media_cfg.turn_auth_cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; - cfg->media_cfg.turn_auth_cred.data.static_cred.data = pj_str(pj_optarg); + cfg->media_cfg.turn_auth_cred.data.static_cred.data_type = + cur_acc->turn_cfg.turn_auth_cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; + cfg->media_cfg.turn_auth_cred.data.static_cred.data = + cur_acc->turn_cfg.turn_auth_cred.data.static_cred.data = pj_str(pj_optarg); break; #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0) @@ -1577,6 +1596,13 @@ static pj_status_t parse_args(int argc, char *argv[], acfg->cred_count++; } + if (acfg->ice_cfg.enable_ice) { + acfg->ice_cfg_use = PJSUA_ICE_CONFIG_USE_CUSTOM; + } + if (acfg->turn_cfg.enable_turn) { + acfg->turn_cfg_use = PJSUA_TURN_CONFIG_USE_CUSTOM; + } + /* When IMS mode is enabled for the account, verify that settings * are okay. */ @@ -1771,6 +1797,55 @@ static void write_account_settings(int acc_index, pj_str_t *result) /* MWI */ if (acc_cfg->mwi_enabled) pj_strcat2(result, "--mwi\n"); + + if (acc_cfg->sip_stun_use != PJSUA_STUN_USE_DEFAULT || + acc_cfg->media_stun_use != PJSUA_STUN_USE_DEFAULT) + { + pj_strcat2(result, "--disable-stun\n"); + } + + /* Media Transport*/ + if (acc_cfg->ice_cfg.enable_ice) + pj_strcat2(result, "--use-ice\n"); + + if (acc_cfg->ice_cfg.ice_opt.aggressive == PJ_FALSE) + pj_strcat2(result, "--ice-regular\n"); + + if (acc_cfg->turn_cfg.enable_turn) + pj_strcat2(result, "--use-turn\n"); + + if (acc_cfg->ice_cfg.ice_max_host_cands >= 0) { + pj_ansi_sprintf(line, "--ice_max_host_cands %d\n", + acc_cfg->ice_cfg.ice_max_host_cands); + pj_strcat2(result, line); + } + + if (acc_cfg->ice_cfg.ice_no_rtcp) + pj_strcat2(result, "--ice-no-rtcp\n"); + + if (acc_cfg->turn_cfg.turn_server.slen) { + pj_ansi_sprintf(line, "--turn-srv %.*s\n", + (int)acc_cfg->turn_cfg.turn_server.slen, + acc_cfg->turn_cfg.turn_server.ptr); + pj_strcat2(result, line); + } + + if (acc_cfg->turn_cfg.turn_conn_type == PJ_TURN_TP_TCP) + pj_strcat2(result, "--turn-tcp\n"); + + if (acc_cfg->turn_cfg.turn_auth_cred.data.static_cred.username.slen) { + pj_ansi_sprintf(line, "--turn-user %.*s\n", + (int)acc_cfg->turn_cfg.turn_auth_cred.data.static_cred.username.slen, + acc_cfg->turn_cfg.turn_auth_cred.data.static_cred.username.ptr); + pj_strcat2(result, line); + } + + if (acc_cfg->turn_cfg.turn_auth_cred.data.static_cred.data.slen) { + pj_ansi_sprintf(line, "--turn-passwd %.*s\n", + (int)acc_cfg->turn_cfg.turn_auth_cred.data.static_cred.data.slen, + acc_cfg->turn_cfg.turn_auth_cred.data.static_cred.data.ptr); + pj_strcat2(result, line); + } } @@ -1967,49 +2042,6 @@ static int write_settings(const struct app_config *config, } #endif - /* Media Transport*/ - if (config->media_cfg.enable_ice) - pj_strcat2(&cfg, "--use-ice\n"); - - if (config->media_cfg.ice_opt.aggressive == PJ_FALSE) - pj_strcat2(&cfg, "--ice-regular\n"); - - if (config->media_cfg.enable_turn) - pj_strcat2(&cfg, "--use-turn\n"); - - if (config->media_cfg.ice_max_host_cands >= 0) { - pj_ansi_sprintf(line, "--ice_max_host_cands %d\n", - config->media_cfg.ice_max_host_cands); - pj_strcat2(&cfg, line); - } - - if (config->media_cfg.ice_no_rtcp) - pj_strcat2(&cfg, "--ice-no-rtcp\n"); - - if (config->media_cfg.turn_server.slen) { - pj_ansi_sprintf(line, "--turn-srv %.*s\n", - (int)config->media_cfg.turn_server.slen, - config->media_cfg.turn_server.ptr); - pj_strcat2(&cfg, line); - } - - if (config->media_cfg.turn_conn_type == PJ_TURN_TP_TCP) - pj_strcat2(&cfg, "--turn-tcp\n"); - - if (config->media_cfg.turn_auth_cred.data.static_cred.username.slen) { - pj_ansi_sprintf(line, "--turn-user %.*s\n", - (int)config->media_cfg.turn_auth_cred.data.static_cred.username.slen, - config->media_cfg.turn_auth_cred.data.static_cred.username.ptr); - pj_strcat2(&cfg, line); - } - - if (config->media_cfg.turn_auth_cred.data.static_cred.data.slen) { - pj_ansi_sprintf(line, "--turn-passwd %.*s\n", - (int)config->media_cfg.turn_auth_cred.data.static_cred.data.slen, - config->media_cfg.turn_auth_cred.data.static_cred.data.ptr); - pj_strcat2(&cfg, line); - } - /* Media */ if (config->null_audio) pj_strcat2(&cfg, "--null-audio\n"); diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h index 20ddcc5e..e3e44884 100644 --- a/pjsip/include/pjsip/sip_transport.h +++ b/pjsip/include/pjsip/sip_transport.h @@ -1076,6 +1076,8 @@ PJ_DECL(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool, * In this implementation, it will only select the transport based on * the transport type in the request. * + * @see pjsip_tpmgr_find_local_addr2() + * * @param tpmgr The transport manager. * @param pool Pool to allocate memory for the IP address. * @param type Destination address to contact. @@ -1093,6 +1095,76 @@ PJ_DECL(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr, int *port); /** + * Parameter for pjsip_tpmgr_find_local_addr2() function. + */ +typedef struct pjsip_tpmgr_fla2_param +{ + /** + * Specify transport type to use. This must be set. + */ + pjsip_transport_type_e tp_type; + + /** + * Optional pointer to preferred transport, if any. + */ + const pjsip_tpselector *tp_sel; + + /** + * Destination host, if known. The destination host is needed + * if \a local_if field below is set. + */ + pj_str_t dst_host; + + /** + * Specify if the function should return which local interface + * to use for the specified destination in \a dst_host. By definition, + * the returned address will always be local interface address. + */ + pj_bool_t local_if; + + /** + * The returned address. + */ + pj_str_t ret_addr; + + /** + * The returned port. + */ + pj_uint16_t ret_port; + + /** + * Returned pointer to the transport. Only set if local_if is set. + */ + const void *ret_tp; + +} pjsip_tpmgr_fla2_param; + +/** + * Initialize with default values. + * + * @param prm The parameter to be initialized. + */ +PJ_DECL(void) pjsip_tpmgr_fla2_param_default(pjsip_tpmgr_fla2_param *prm); + +/** + * Find out the appropriate local address info (IP address and port) to + * advertise in Contact or Via header header based on the remote address + * to be contacted. The local address info would be the address name of the + * transport or listener which will be used to send the request. + * + * @see pjsip_tpmgr_find_local_addr() + * + * @param tpmgr The transport manager. + * @param pool Pool to allocate memory for the IP address. + * @param param Function input and output parameters. + * + * @return PJ_SUCCESS, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsip_tpmgr_find_local_addr2(pjsip_tpmgr *tpmgr, + pj_pool_t *pool, + pjsip_tpmgr_fla2_param *prm); + +/** * Return number of transports currently registered to the transport * manager. * diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 64f1ce86..40517423 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -2567,6 +2567,120 @@ typedef enum pjsua_call_hold_type #endif /** + * This enumeration controls the use of STUN in the account. + */ +typedef enum pjsua_stun_use +{ + /** + * Follow the default setting in the global \a pjsua_config. + */ + PJSUA_STUN_USE_DEFAULT, + + /** + * Disable STUN. If STUN is not enabled in the global \a pjsua_config, + * this setting has no effect. + */ + PJSUA_STUN_USE_DISABLED + +} pjsua_stun_use; + +/** + * This enumeration controls the use of ICE settings in the account. + */ +typedef enum pjsua_ice_config_use +{ + /** + * Use the default settings in the global \a pjsua_media_config. + */ + PJSUA_ICE_CONFIG_USE_DEFAULT, + + /** + * Use the custom \a pjsua_ice_config setting in the account. + */ + PJSUA_ICE_CONFIG_USE_CUSTOM + +} pjsua_ice_config_use; + +/** + * This enumeration controls the use of TURN settings in the account. + */ +typedef enum pjsua_turn_config_use +{ + /** + * Use the default setting in the global \a pjsua_media_config. + */ + PJSUA_TURN_CONFIG_USE_DEFAULT, + + /** + * Use the custom \a pjsua_turn_config setting in the account. + */ + PJSUA_TURN_CONFIG_USE_CUSTOM + +} pjsua_turn_config_use; + +/** + * ICE setting. This setting is used in the pjsua_acc_config. + */ +typedef struct pjsua_ice_config +{ + /** + * Enable ICE. + */ + pj_bool_t enable_ice; + + /** + * Set the maximum number of host candidates. + * + * Default: -1 (maximum not set) + */ + int ice_max_host_cands; + + /** + * ICE session options. + */ + pj_ice_sess_options ice_opt; + + /** + * Disable RTCP component. + * + * Default: no + */ + pj_bool_t ice_no_rtcp; + +} pjsua_ice_config; + +/** + * TURN setting. This setting is used in the pjsua_acc_config. + */ +typedef struct pjsua_turn_config +{ + /** + * Enable TURN candidate in ICE. + */ + pj_bool_t enable_turn; + + /** + * Specify TURN domain name or host name, in in "DOMAIN:PORT" or + * "HOST:PORT" format. + */ + pj_str_t turn_server; + + /** + * Specify the connection type to be used to the TURN server. Valid + * values are PJ_TURN_TP_UDP or PJ_TURN_TP_TCP. + * + * Default: PJ_TURN_TP_UDP + */ + pj_turn_tp_type turn_conn_type; + + /** + * Specify the credential to authenticate with the TURN server. + */ + pj_stun_auth_cred turn_auth_cred; + +} pjsua_turn_config; + +/** * 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(). @@ -2967,13 +3081,55 @@ typedef struct pjsua_acc_config pjsua_transport_config rtp_cfg; /** + * Control the use of STUN for the SIP signaling. + * + * Default: PJSUA_STUN_USE_DEFAULT + */ + pjsua_stun_use sip_stun_use; + + /** + * Control the use of STUN for the media transports. + * + * Default: PJSUA_STUN_USE_DEFAULT + */ + pjsua_stun_use media_stun_use; + + /** + * Control the use of ICE in the account. By default, the settings in the + * \a pjsua_media_config will be used. + * + * Default: PJSUA_ICE_CONFIG_USE_DEFAULT + */ + pjsua_ice_config_use ice_cfg_use; + + /** + * The custom ICE setting for this account. This setting will only be + * used if \a ice_cfg_use is set to PJSUA_ICE_CONFIG_USE_CUSTOM + */ + pjsua_ice_config ice_cfg; + + /** + * Control the use of TURN in the account. By default, the settings in the + * \a pjsua_media_config will be used + * + * Default: PJSUA_TURN_CONFIG_USE_DEFAULT + */ + pjsua_turn_config_use turn_cfg_use; + + /** + * The custom TURN setting for this account. This setting will only be + * used if \a turn_cfg_use is set to PJSUA_TURN_CONFIG_USE_CUSTOM + */ + pjsua_turn_config turn_cfg; + + /** * Specify whether secure media transport should be used for this account. * Valid values are PJMEDIA_SRTP_DISABLED, PJMEDIA_SRTP_OPTIONAL, and * PJMEDIA_SRTP_MANDATORY. * * Default: #PJSUA_DEFAULT_USE_SRTP */ - pjmedia_srtp_use use_srtp; + pjmedia_srtp_use use_srtp; /** * Specify whether SRTP requires secure signaling to be used. This option @@ -3071,6 +3227,52 @@ typedef struct pjsua_acc_config /** + * Initialize ICE config from a media config. If the \a pool argument + * is NULL, a simple memcpy() will be used. + * + * @param pool Memory to duplicate strings. + * @param dst Destination config. + * @param src Source config. + */ +PJ_DECL(void) pjsua_ice_config_from_media_config(pj_pool_t *pool, + pjsua_ice_config *dst, + const pjsua_media_config *src); + +/** + * Clone. If the \a pool argument is NULL, a simple memcpy() will be used. + * + * @param pool Memory to duplicate strings. + * @param dst Destination config. + * @param src Source config. + */ +PJ_DECL(void) pjsua_ice_config_dup( pj_pool_t *pool, + pjsua_ice_config *dst, + const pjsua_ice_config *src); + +/** + * Initialize TURN config from a media config. If the \a pool argument + * is NULL, a simple memcpy() will be used. + * + * @param pool Memory to duplicate strings. + * @param dst Destination config. + * @param src Source config. + */ +PJ_DECL(void) pjsua_turn_config_from_media_config(pj_pool_t *pool, + pjsua_turn_config *dst, + const pjsua_media_config *src); + +/** + * Clone. If the \a pool argument is NULL, a simple memcpy() will be used. + * + * @param pool Memory to duplicate strings. + * @param dst Destination config. + * @param src Source config. + */ +PJ_DECL(void) pjsua_turn_config_dup(pj_pool_t *pool, + pjsua_turn_config *dst, + const pjsua_turn_config *src); + +/** * Call this function to initialize account config with default values. * * @param cfg The account config to be initialized. diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h index 80ebec01..5337b68b 100644 --- a/pjsip/include/pjsua-lib/pjsua_internal.h +++ b/pjsip/include/pjsua-lib/pjsua_internal.h @@ -583,6 +583,20 @@ pj_status_t resolve_stun_server(pj_bool_t wait); */ pj_status_t normalize_route_uri(pj_pool_t *pool, pj_str_t *uri); +/* acc use stun? */ +pj_bool_t pjsua_sip_acc_is_using_stun(pjsua_acc_id acc_id); + +/* Get local transport address suitable to be used for Via or Contact address + * to send request to the specified destination URI. + */ +pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id, + pj_pool_t *pool, + const pj_str_t *dst_uri, + pjsip_host_port *addr, + pjsip_transport_type_e *p_tp_type, + int *p_secure, + const void **p_tp); + /** * Handle incoming invite request. */ diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c index 2f3ceeba..1fbe260f 100644 --- a/pjsip/src/pjsip/sip_transport.c +++ b/pjsip/src/pjsip/sip_transport.c @@ -24,6 +24,7 @@ #include <pjsip/sip_private.h> #include <pjsip/sip_errno.h> #include <pjsip/sip_module.h> +#include <pj/addr_resolv.h> #include <pj/except.h> #include <pj/os.h> #include <pj/log.h> @@ -1080,6 +1081,10 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_unregister_tpfactory( pjsip_tpmgr *mgr, return PJ_SUCCESS; } +PJ_DECL(void) pjsip_tpmgr_fla2_param_default(pjsip_tpmgr_fla2_param *prm) +{ + pj_bzero(prm, sizeof(*prm)); +} /***************************************************************************** * @@ -1138,7 +1143,27 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool, return PJ_SUCCESS; } +/* Get the interface to send packet to the specified address */ +static pj_status_t get_net_interface(pjsip_transport_type_e tp_type, + const pj_str_t *dst, + pj_str_t *itf_str_addr) +{ + int af; + pj_sockaddr itf_addr; + pj_status_t status; + + af = (tp_type & PJSIP_TRANSPORT_IPV6)? PJ_AF_INET6 : PJ_AF_INET; + status = pj_getipinterface(af, dst, &itf_addr, PJ_FALSE, NULL); + if (status != PJ_SUCCESS) + return status; + + /* Print address */ + pj_sockaddr_print(&itf_addr, itf_str_addr->ptr, + PJ_INET6_ADDRSTRLEN, 0); + itf_str_addr->slen = pj_ansi_strlen(itf_str_addr->ptr); + return PJ_SUCCESS; +} /* * Find out the appropriate local address info (IP address and port) to @@ -1149,46 +1174,65 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_create( pj_pool_t *pool, * In this implementation, it will only select the transport based on * the transport type in the request. */ -PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr, +PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr2(pjsip_tpmgr *tpmgr, pj_pool_t *pool, - pjsip_transport_type_e type, - const pjsip_tpselector *sel, - pj_str_t *ip_addr, - int *port) + pjsip_tpmgr_fla2_param *prm) { + char tmp_buf[PJ_INET6_ADDRSTRLEN+10]; + pj_str_t tmp_str = { tmp_buf, 0 }; pj_status_t status = PJSIP_EUNSUPTRANSPORT; unsigned flag; /* Sanity checks */ - PJ_ASSERT_RETURN(tpmgr && pool && ip_addr && port, PJ_EINVAL); + PJ_ASSERT_RETURN(tpmgr && pool && prm, PJ_EINVAL); - ip_addr->slen = 0; - *port = 0; + prm->ret_addr.slen = 0; + prm->ret_port = 0; + prm->ret_tp = NULL; - flag = pjsip_transport_get_flag_from_type(type); + flag = pjsip_transport_get_flag_from_type(prm->tp_type); - if (sel && sel->type == PJSIP_TPSELECTOR_TRANSPORT && - sel->u.transport) + if (prm->tp_sel && prm->tp_sel->type == PJSIP_TPSELECTOR_TRANSPORT && + prm->tp_sel->u.transport) { - pj_strdup(pool, ip_addr, &sel->u.transport->local_name.host); - *port = sel->u.transport->local_name.port; + const pjsip_transport *tp = prm->tp_sel->u.transport; + if (prm->local_if) { + status = get_net_interface(tp->key.type, &prm->dst_host, + &tmp_str); + if (status != PJ_SUCCESS) + goto on_return; + pj_strdup(pool, &prm->ret_addr, &tmp_str); + prm->ret_port = pj_sockaddr_get_port(&tp->local_addr); + prm->ret_tp = tp; + } else { + pj_strdup(pool, &prm->ret_addr, &tp->local_name.host); + prm->ret_port = tp->local_name.port; + } status = PJ_SUCCESS; - } else if (sel && sel->type == PJSIP_TPSELECTOR_LISTENER && - sel->u.listener) + } else if (prm->tp_sel && prm->tp_sel->type == PJSIP_TPSELECTOR_LISTENER && + prm->tp_sel->u.listener) { - pj_strdup(pool, ip_addr, &sel->u.listener->addr_name.host); - *port = sel->u.listener->addr_name.port; + if (prm->local_if) { + status = get_net_interface(prm->tp_sel->u.listener->type, + &prm->dst_host, &tmp_str); + if (status != PJ_SUCCESS) + goto on_return; + pj_strdup(pool, &prm->ret_addr, &tmp_str); + } else { + pj_strdup(pool, &prm->ret_addr, + &prm->tp_sel->u.listener->addr_name.host); + } + prm->ret_port = prm->tp_sel->u.listener->addr_name.port; status = PJ_SUCCESS; } else if ((flag & PJSIP_TRANSPORT_DATAGRAM) != 0) { - pj_sockaddr remote; int addr_len; pjsip_transport *tp; pj_bzero(&remote, sizeof(remote)); - if (type & PJSIP_TRANSPORT_IPV6) { + if (prm->tp_type & PJSIP_TRANSPORT_IPV6) { addr_len = sizeof(pj_sockaddr_in6); remote.addr.sa_family = pj_AF_INET6(); } else { @@ -1196,13 +1240,22 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr, remote.addr.sa_family = pj_AF_INET(); } - status = pjsip_tpmgr_acquire_transport(tpmgr, type, &remote, + status = pjsip_tpmgr_acquire_transport(tpmgr, prm->tp_type, &remote, addr_len, NULL, &tp); if (status == PJ_SUCCESS) { - pj_strdup(pool, ip_addr, &tp->local_name.host); - *port = tp->local_name.port; - status = PJ_SUCCESS; + if (prm->local_if) { + status = get_net_interface(tp->key.type, &prm->dst_host, + &tmp_str); + if (status != PJ_SUCCESS) + goto on_return; + pj_strdup(pool, &prm->ret_addr, &tmp_str); + prm->ret_port = pj_sockaddr_get_port(&tp->local_addr); + prm->ret_tp = tp; + } else { + pj_strdup(pool, &prm->ret_addr, &tp->local_name.host); + prm->ret_port = tp->local_name.port; + } pjsip_transport_dec_ref(tp); } @@ -1215,22 +1268,55 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr, f = tpmgr->factory_list.next; while (f != &tpmgr->factory_list) { - if (f->type == type) + if (f->type == prm->tp_type) break; f = f->next; } if (f != &tpmgr->factory_list) { - pj_strdup(pool, ip_addr, &f->addr_name.host); - *port = f->addr_name.port; + 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); + } else { + pj_strdup(pool, &prm->ret_addr, &f->addr_name.host); + } + prm->ret_port = f->addr_name.port; status = PJ_SUCCESS; } pj_lock_release(tpmgr->lock); } +on_return: return status; } +PJ_DEF(pj_status_t) pjsip_tpmgr_find_local_addr( pjsip_tpmgr *tpmgr, + pj_pool_t *pool, + pjsip_transport_type_e type, + const pjsip_tpselector *sel, + pj_str_t *ip_addr, + int *port) +{ + pjsip_tpmgr_fla2_param prm; + pj_status_t status; + + pjsip_tpmgr_fla2_param_default(&prm); + prm.tp_type = type; + prm.tp_sel = sel; + + status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &prm); + if (status != PJ_SUCCESS) + return status; + + *ip_addr = prm.ret_addr; + *port = prm.ret_port; + + return PJ_SUCCESS; +} + /* * Return number of transports currently registered to the transport * manager. diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c index 28acf6ee..fc57f179 100644 --- a/pjsip/src/pjsua-lib/pjsua_acc.c +++ b/pjsip/src/pjsua-lib/pjsua_acc.c @@ -133,6 +133,9 @@ PJ_DEF(void) pjsua_acc_config_dup( pj_pool_t *pool, pjsua_transport_config_dup(pool, &dst->rtp_cfg, &src->rtp_cfg); + pjsua_ice_config_dup(pool, &dst->ice_cfg, &src->ice_cfg); + pjsua_turn_config_dup(pool, &dst->turn_cfg, &src->turn_cfg); + pj_strdup(pool, &dst->ka_data, &src->ka_data); } @@ -283,7 +286,7 @@ static pj_status_t initialize_acc(unsigned acc_id) * contact params. */ #if PJSUA_ADD_ICE_TAGS - if (pjsua_var.media_cfg.enable_ice) { + if (acc_cfg->ice_cfg.enable_ice) { unsigned new_len; pj_str_t new_prm; @@ -348,6 +351,18 @@ static pj_status_t initialize_acc(unsigned acc_id) } } + /* If account's ICE and TURN customization is not set, then + * initialize it with the settings from the global media config. + */ + if (acc->cfg.ice_cfg_use == PJSUA_ICE_CONFIG_USE_DEFAULT) { + pjsua_ice_config_from_media_config(NULL, &acc->cfg.ice_cfg, + &pjsua_var.media_cfg); + } + if (acc->cfg.turn_cfg_use == PJSUA_TURN_CONFIG_USE_DEFAULT) { + pjsua_turn_config_from_media_config(NULL, &acc->cfg.turn_cfg, + &pjsua_var.media_cfg); + } + /* Mark account as valid */ pjsua_var.acc[acc_id].valid = PJ_TRUE; @@ -1152,6 +1167,68 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id, update_reg = PJ_TRUE; } + /* Video settings */ + acc->cfg.vid_in_auto_show = cfg->vid_in_auto_show; + acc->cfg.vid_out_auto_transmit = cfg->vid_out_auto_transmit; + acc->cfg.vid_wnd_flags = cfg->vid_wnd_flags; + acc->cfg.vid_cap_dev = cfg->vid_cap_dev; + acc->cfg.vid_rend_dev = cfg->vid_rend_dev; + acc->cfg.vid_stream_rc_cfg = cfg->vid_stream_rc_cfg; + + /* Media settings */ + if (pj_stricmp(&acc->cfg.rtp_cfg.public_addr, &cfg->rtp_cfg.public_addr) || + pj_stricmp(&acc->cfg.rtp_cfg.bound_addr, &cfg->rtp_cfg.bound_addr)) + { + pjsua_transport_config_dup(acc->pool, &acc->cfg.rtp_cfg, + &cfg->rtp_cfg); + } else { + /* ..to save memory by not using the pool */ + acc->cfg.rtp_cfg = cfg->rtp_cfg; + } + + /* STUN and Media customization */ + if (acc->cfg.sip_stun_use != cfg->sip_stun_use) { + acc->cfg.sip_stun_use = cfg->sip_stun_use; + update_reg = PJ_TRUE; + } + acc->cfg.media_stun_use = cfg->media_stun_use; + + /* ICE settings */ + acc->cfg.ice_cfg_use = cfg->ice_cfg_use; + switch (acc->cfg.ice_cfg_use) { + case PJSUA_ICE_CONFIG_USE_DEFAULT: + /* Copy ICE settings from media settings so that we don't need to + * check the media config if we look for ICE config. + */ + pjsua_ice_config_from_media_config(NULL, &acc->cfg.ice_cfg, + &pjsua_var.media_cfg); + break; + case PJSUA_ICE_CONFIG_USE_CUSTOM: + pjsua_ice_config_dup(acc->pool, &acc->cfg.ice_cfg, &cfg->ice_cfg); + break; + } + + /* TURN settings */ + acc->cfg.turn_cfg_use = cfg->turn_cfg_use; + switch (acc->cfg.turn_cfg_use) { + case PJSUA_TURN_CONFIG_USE_DEFAULT: + /* Copy TURN settings from media settings so that we don't need to + * check the media config if we look for TURN config. + */ + pjsua_turn_config_from_media_config(NULL, &acc->cfg.turn_cfg, + &pjsua_var.media_cfg); + break; + case PJSUA_TURN_CONFIG_USE_CUSTOM: + pjsua_turn_config_dup(acc->pool, &acc->cfg.turn_cfg, + &cfg->turn_cfg); + break; + } + + acc->cfg.use_srtp = cfg->use_srtp; + + /* Call hold type */ + acc->cfg.call_hold_type = cfg->call_hold_type; + /* Unregister first */ if (unreg_first) { pjsua_acc_set_registration(acc->index, PJ_FALSE); @@ -1174,16 +1251,6 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id, pjsua_start_mwi(acc_id, PJ_TRUE); } - /* Video settings */ - acc->cfg.vid_in_auto_show = cfg->vid_in_auto_show; - acc->cfg.vid_out_auto_transmit = cfg->vid_out_auto_transmit; - acc->cfg.vid_wnd_flags = cfg->vid_wnd_flags; - acc->cfg.vid_cap_dev = cfg->vid_cap_dev; - acc->cfg.vid_rend_dev = cfg->vid_rend_dev; - - /* Call hold type */ - acc->cfg.call_hold_type = cfg->call_hold_type; - on_return: PJSUA_UNLOCK(); pj_log_pop_indent(); @@ -1515,6 +1582,7 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc, const char *ob = ";ob"; char *tmp; const char *beginquote, *endquote; + char transport_param[32]; int len; /* Enclose IPv6 address in square brackets */ @@ -1525,9 +1593,20 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc, beginquote = endquote = ""; } + /* Don't add transport parameter if it's UDP */ + if (tp->key.type != PJSIP_TRANSPORT_UDP && + tp->key.type != PJSIP_TRANSPORT_UDP6) + { + pj_ansi_snprintf(transport_param, sizeof(transport_param), + ";transport=%s", + pjsip_transport_get_type_name(tp->key.type)); + } else { + transport_param[0] = '\0'; + } + tmp = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); len = pj_ansi_snprintf(tmp, PJSIP_MAX_URL_SIZE, - "<sip:%.*s%s%s%.*s%s:%d;transport=%s%.*s%s>%.*s", + "<sip:%.*s%s%s%.*s%s:%d%s%.*s%s>%.*s", (int)acc->user_part.slen, acc->user_part.ptr, (acc->user_part.slen? "@" : ""), @@ -1536,7 +1615,7 @@ static pj_bool_t acc_check_nat_addr(pjsua_acc *acc, via_addr->ptr, endquote, rport, - tp->type_name, + transport_param, (int)acc->cfg.contact_uri_params.slen, acc->cfg.contact_uri_params.ptr, (acc->cfg.use_rfc5626? ob: ""), @@ -2146,6 +2225,13 @@ static pj_status_t pjsua_regc_init(int acc_id) return PJ_SUCCESS; } +pj_bool_t pjsua_sip_acc_is_using_stun(pjsua_acc_id acc_id) +{ + pjsua_acc *acc = &pjsua_var.acc[acc_id]; + + return acc->cfg.sip_stun_use != PJSUA_STUN_USE_DISABLED && + pjsua_var.ua_cfg.stun_srv_cnt != 0; +} /* * Update registration or perform unregistration. @@ -2153,6 +2239,7 @@ static pj_status_t pjsua_regc_init(int acc_id) PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id, pj_bool_t renew) { + pjsua_acc *acc; pj_status_t status = 0; pjsip_tx_data *tdata = 0; @@ -2166,6 +2253,8 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id, PJSUA_LOCK(); + acc = &pjsua_var.acc[acc_id]; + /* Cancel any re-registration timer */ if (pjsua_var.acc[acc_id].auto_rereg.timer.id) { pjsua_var.acc[acc_id].auto_rereg.timer.id = PJ_FALSE; @@ -2232,6 +2321,15 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id, pjsip_regc_set_via_sent_by(pjsua_var.acc[acc_id].regc, &pjsua_var.acc[acc_id].via_addr, pjsua_var.acc[acc_id].via_tp); + } else if (!pjsua_sip_acc_is_using_stun(acc_id)) { + /* Choose local interface to use in Via if acc is not using + * STUN + */ + pjsua_acc_get_uac_addr(acc_id, tdata->pool, + &acc->cfg.reg_uri, + &tdata->via_addr, + NULL, NULL, + &tdata->via_tp); } //pjsua_process_msg_data(tdata, NULL); @@ -2612,46 +2710,40 @@ PJ_DEF(pj_status_t) pjsua_acc_create_request(pjsua_acc_id acc_id, return PJ_SUCCESS; } - -PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool, - pj_str_t *contact, - pjsua_acc_id acc_id, - const pj_str_t *suri) +/* Get local transport address suitable to be used for Via or Contact address + * to send request to the specified destination URI. + */ +pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id, + pj_pool_t *pool, + const pj_str_t *dst_uri, + pjsip_host_port *addr, + pjsip_transport_type_e *p_tp_type, + int *secure, + const void **p_tp) { pjsua_acc *acc; pjsip_sip_uri *sip_uri; pj_status_t status; pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED; - pj_str_t local_addr; - pjsip_tpselector tp_sel; unsigned flag; - int secure; - int local_port; - const char *beginquote, *endquote; - char transport_param[32]; - const char *ob = ";ob"; + pjsip_tpselector tp_sel; + pjsip_tpmgr *tpmgr; + pjsip_tpmgr_fla2_param tfla2_prm; - PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL); acc = &pjsua_var.acc[acc_id]; - /* If force_contact is configured, then use use it */ - if (acc->cfg.force_contact.slen) { - *contact = acc->cfg.force_contact; - return PJ_SUCCESS; - } - - /* If route-set is configured for the account, then URI is the + /* If route-set is configured for the account, then URI is the * first entry of the route-set. */ if (!pj_list_empty(&acc->route_set)) { - sip_uri = (pjsip_sip_uri*) + sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(acc->route_set.next->name_addr.uri); } else { pj_str_t tmp; pjsip_uri *uri; - pj_strdup_with_null(pool, &tmp, suri); + pj_strdup_with_null(pool, &tmp, dst_uri); uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0); if (uri == NULL) @@ -2671,7 +2763,7 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool, tp_type = PJSIP_TRANSPORT_UDP; } else tp_type = pjsip_transport_get_type_from_name(&sip_uri->transport_param); - + if (tp_type == PJSIP_TRANSPORT_UNSPECIFIED) return PJSIP_EUNSUPTRANSPORT; @@ -2682,15 +2774,66 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool, tp_type = (pjsip_transport_type_e)(((int)tp_type) + PJSIP_TRANSPORT_IPV6); flag = pjsip_transport_get_flag_from_type(tp_type); - secure = (flag & PJSIP_TRANSPORT_SECURE) != 0; /* Init transport selector. */ - pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel); + pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); /* Get local address suitable to send request from */ - status = pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(pjsua_var.endpt), - pool, tp_type, &tp_sel, - &local_addr, &local_port); + pjsip_tpmgr_fla2_param_default(&tfla2_prm); + tfla2_prm.tp_type = tp_type; + tfla2_prm.tp_sel = &tp_sel; + tfla2_prm.dst_host = sip_uri->host; + tfla2_prm.local_if = (!pjsua_sip_acc_is_using_stun(acc_id) || + (flag & PJSIP_TRANSPORT_RELIABLE)); + + tpmgr = pjsip_endpt_get_tpmgr(pjsua_var.endpt); + status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &tfla2_prm); + if (status != PJ_SUCCESS) + return status; + + addr->host = tfla2_prm.ret_addr; + addr->port = tfla2_prm.ret_port; + + if (p_tp_type) + *p_tp_type = tp_type; + + if (secure) { + *secure = (flag & PJSIP_TRANSPORT_SECURE) != 0; + } + + if (p_tp) + *p_tp = tfla2_prm.ret_tp; + + return PJ_SUCCESS; +} + + +PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool, + pj_str_t *contact, + pjsua_acc_id acc_id, + const pj_str_t *suri) +{ + pjsua_acc *acc; + pj_status_t status; + pjsip_transport_type_e tp_type; + pjsip_host_port addr; + int secure; + const char *beginquote, *endquote; + char transport_param[32]; + const char *ob = ";ob"; + + + PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL); + acc = &pjsua_var.acc[acc_id]; + + /* If force_contact is configured, then use use it */ + if (acc->cfg.force_contact.slen) { + *contact = acc->cfg.force_contact; + return PJ_SUCCESS; + } + + status = pjsua_acc_get_uac_addr(acc_id, pool, suri, &addr, + &tp_type, &secure, NULL); if (status != PJ_SUCCESS) return status; @@ -2725,10 +2868,10 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uac_contact( pj_pool_t *pool, acc->user_part.ptr, (acc->user_part.slen?"@":""), beginquote, - (int)local_addr.slen, - local_addr.ptr, + (int)addr.host.slen, + addr.host.ptr, endquote, - local_port, + addr.port, transport_param, (int)acc->cfg.contact_uri_params.slen, acc->cfg.contact_uri_params.ptr, @@ -2760,6 +2903,8 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uas_contact( pj_pool_t *pool, pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED; pj_str_t local_addr; pjsip_tpselector tp_sel; + pjsip_tpmgr *tpmgr; + pjsip_tpmgr_fla2_param tfla2_prm; unsigned flag; int secure; int local_port; @@ -2847,12 +2992,22 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uas_contact( pj_pool_t *pool, pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel); /* Get local address suitable to send request from */ - status = pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(pjsua_var.endpt), - pool, tp_type, &tp_sel, - &local_addr, &local_port); + pjsip_tpmgr_fla2_param_default(&tfla2_prm); + tfla2_prm.tp_type = tp_type; + tfla2_prm.tp_sel = &tp_sel; + tfla2_prm.dst_host = sip_uri->host; + tfla2_prm.local_if = (!pjsua_sip_acc_is_using_stun(acc_id) || + (flag & PJSIP_TRANSPORT_RELIABLE)); + + tpmgr = pjsip_endpt_get_tpmgr(pjsua_var.endpt); + status = pjsip_tpmgr_find_local_addr2(tpmgr, pool, &tfla2_prm); if (status != PJ_SUCCESS) return status; + local_addr = tfla2_prm.ret_addr; + local_port = tfla2_prm.ret_port; + + /* Enclose IPv6 address in square brackets */ if (tp_type & PJSIP_TRANSPORT_IPV6) { beginquote = "["; diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c index 45ce8eb8..b972bb8a 100644 --- a/pjsip/src/pjsua-lib/pjsua_call.c +++ b/pjsip/src/pjsua-lib/pjsua_call.c @@ -1182,7 +1182,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) options |= PJSIP_INV_SUPPORT_TIMER; if (pjsua_var.acc[acc_id].cfg.require_100rel == PJSUA_100REL_MANDATORY) options |= PJSIP_INV_REQUIRE_100REL; - if (pjsua_var.media_cfg.enable_ice) + if (pjsua_var.acc[acc_id].cfg.ice_cfg.enable_ice) options |= PJSIP_INV_SUPPORT_ICE; if (pjsua_var.acc[acc_id].cfg.use_timer == PJSUA_SIP_TIMER_REQUIRED) options |= PJSIP_INV_REQUIRE_TIMER; diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index f4071c0e..bfcae3f9 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -196,12 +196,64 @@ PJ_DEF(void) pjsua_transport_config_dup(pj_pool_t *pool, pjsua_transport_config *dst, const pjsua_transport_config *src) { + pj_memcpy(dst, src, sizeof(*src)); + pj_strdup(pool, &dst->public_addr, &src->public_addr); + pj_strdup(pool, &dst->bound_addr, &src->bound_addr); +} + +PJ_DEF(void) pjsua_ice_config_from_media_config( pj_pool_t *pool, + pjsua_ice_config *dst, + const pjsua_media_config *src) +{ + PJ_UNUSED_ARG(pool); + + dst->enable_ice = src->enable_ice; + dst->ice_max_host_cands = src->ice_max_host_cands; + dst->ice_opt = src->ice_opt; + dst->ice_no_rtcp = src->ice_no_rtcp; +} + +PJ_DEF(void) pjsua_ice_config_dup( pj_pool_t *pool, + pjsua_ice_config *dst, + const pjsua_ice_config *src) +{ PJ_UNUSED_ARG(pool); pj_memcpy(dst, src, sizeof(*src)); } +PJ_DEF(void) pjsua_turn_config_from_media_config(pj_pool_t *pool, + pjsua_turn_config *dst, + const pjsua_media_config *src) +{ + dst->enable_turn = src->enable_turn; + dst->turn_conn_type = src->turn_conn_type; + if (pool == NULL) { + dst->turn_server = src->turn_server; + dst->turn_auth_cred = src->turn_auth_cred; + } else { + if (pj_stricmp(&dst->turn_server, &src->turn_server)) + pj_strdup(pool, &dst->turn_server, &src->turn_server); + pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred, + &src->turn_auth_cred); + } +} + +PJ_DEF(void) pjsua_turn_config_dup(pj_pool_t *pool, + pjsua_turn_config *dst, + const pjsua_turn_config *src) +{ + pj_memcpy(dst, src, sizeof(*src)); + if (pool) { + pj_strdup(pool, &dst->turn_server, &src->turn_server); + pj_stun_auth_cred_dup(pool, &dst->turn_auth_cred, + &src->turn_auth_cred); + } +} + PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg) { + pjsua_media_config med_cfg; + pj_bzero(cfg, sizeof(*cfg)); cfg->reg_timeout = PJSUA_REG_INTERVAL; @@ -224,6 +276,11 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg) pjmedia_vid_stream_rc_config_default(&cfg->vid_stream_rc_cfg); #endif pjsua_transport_config_default(&cfg->rtp_cfg); + + pjsua_media_config_default(&med_cfg); + pjsua_ice_config_from_media_config(NULL, &cfg->ice_cfg, &med_cfg); + pjsua_turn_config_from_media_config(NULL, &cfg->turn_cfg, &med_cfg); + cfg->use_srtp = pjsua_var.ua_cfg.use_srtp; cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling; cfg->srtp_optional_dup_offer = pjsua_var.ua_cfg.srtp_optional_dup_offer; @@ -2805,6 +2862,7 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail) PJ_LOG(3,(THIS_FILE, "Dumping media transports:")); for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) { pjsua_call *call = &pjsua_var.calls[i]; + pjsua_acc_config *acc_cfg; pjmedia_transport *tp[PJSUA_MAX_CALL_MEDIA*2]; unsigned tp_cnt = 0; unsigned j; @@ -2830,6 +2888,8 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail) } } + acc_cfg = &pjsua_var.acc[call->acc_id].cfg; + /* Dump the media transports in this call */ for (j = 0; j < tp_cnt; ++j) { pjmedia_transport_info tpinfo; @@ -2838,7 +2898,7 @@ PJ_DEF(void) pjsua_dump(pj_bool_t detail) pjmedia_transport_info_init(&tpinfo); pjmedia_transport_get_info(tp[j], &tpinfo); PJ_LOG(3,(THIS_FILE, " %s: %s", - (pjsua_var.media_cfg.enable_ice ? "ICE" : "UDP"), + (acc_cfg->ice_cfg.enable_ice ? "ICE" : "UDP"), pj_sockaddr_print(&tpinfo.sock_info.rtp_addr_name, addr_buf, sizeof(addr_buf), 3))); diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index 22b363cb..24f0ee61 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -165,9 +165,11 @@ pj_status_t pjsua_media_subsys_start(void) #endif /* Perform NAT detection */ - status = pjsua_detect_nat_type(); - if (status != PJ_SUCCESS) { - PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed")); + if (pjsua_var.ua_cfg.stun_srv_cnt) { + status = pjsua_detect_nat_type(); + if (status != PJ_SUCCESS) { + PJ_PERROR(1,(THIS_FILE, status, "NAT type detection failed")); + } } pj_log_pop_indent(); @@ -226,7 +228,8 @@ pj_status_t pjsua_media_subsys_destroy(unsigned flags) * Create RTP and RTCP socket pair, and possibly resolve their public * address via STUN. */ -static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg, +static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med, + const pjsua_transport_config *cfg, pjmedia_sock_info *skinfo) { enum { @@ -240,10 +243,12 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg, pj_sock_t sock[2]; /* Make sure STUN server resolution has completed */ - status = resolve_stun_server(PJ_TRUE); - if (status != PJ_SUCCESS) { - pjsua_perror(THIS_FILE, "Error resolving STUN server", status); - return status; + if (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); + return status; + } } if (next_rtp_port == 0) @@ -318,7 +323,9 @@ static pj_status_t create_rtp_rtcp_sock(const pjsua_transport_config *cfg, * 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_var.stun_srv.addr.sa_family != 0) { + if (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; @@ -440,7 +447,7 @@ static pj_status_t create_udp_media_transport(const pjsua_transport_config *cfg, pjmedia_sock_info skinfo; pj_status_t status; - status = create_rtp_rtcp_sock(cfg, &skinfo); + status = create_rtp_rtcp_sock(call_med, cfg, &skinfo); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create RTP/RTCP socket", status); @@ -660,12 +667,15 @@ static pj_status_t create_ice_media_transport( pj_bool_t async) { char stunip[PJ_INET6_ADDRSTRLEN]; + pjsua_acc_config *acc_cfg; pj_ice_strans_cfg ice_cfg; pjmedia_ice_cb ice_cb; char name[32]; unsigned comp_cnt; pj_status_t status; + acc_cfg = &pjsua_var.acc[call_med->call->acc_id].cfg; + /* Make sure STUN server resolution has completed */ status = resolve_stun_server(PJ_TRUE); if (status != PJ_SUCCESS) { @@ -682,7 +692,7 @@ static pj_status_t create_ice_media_transport( ice_cfg.af = pj_AF_INET(); ice_cfg.resolver = pjsua_var.resolver; - ice_cfg.opt = pjsua_var.media_cfg.ice_opt; + ice_cfg.opt = acc_cfg->ice_cfg.ice_opt; /* Configure STUN settings */ if (pj_sockaddr_has_addr(&pjsua_var.stun_srv)) { @@ -690,8 +700,8 @@ static pj_status_t create_ice_media_transport( ice_cfg.stun.server = pj_str(stunip); ice_cfg.stun.port = pj_sockaddr_get_port(&pjsua_var.stun_srv); } - if (pjsua_var.media_cfg.ice_max_host_cands >= 0) - ice_cfg.stun.max_host_cands = pjsua_var.media_cfg.ice_max_host_cands; + if (acc_cfg->ice_cfg.ice_max_host_cands >= 0) + ice_cfg.stun.max_host_cands = acc_cfg->ice_cfg.ice_max_host_cands; /* Copy QoS setting to STUN setting */ ice_cfg.stun.cfg.qos_type = cfg->qos_type; @@ -699,8 +709,8 @@ static pj_status_t create_ice_media_transport( sizeof(cfg->qos_params)); /* Configure TURN settings */ - if (pjsua_var.media_cfg.enable_turn) { - status = parse_host_port(&pjsua_var.media_cfg.turn_server, + if (acc_cfg->turn_cfg.enable_turn) { + status = parse_host_port(&acc_cfg->turn_cfg.turn_server, &ice_cfg.turn.server, &ice_cfg.turn.port); if (status != PJ_SUCCESS || ice_cfg.turn.server.slen == 0) { @@ -709,9 +719,9 @@ static pj_status_t create_ice_media_transport( } if (ice_cfg.turn.port == 0) ice_cfg.turn.port = 3479; - ice_cfg.turn.conn_type = pjsua_var.media_cfg.turn_conn_type; + ice_cfg.turn.conn_type = acc_cfg->turn_cfg.turn_conn_type; pj_memcpy(&ice_cfg.turn.auth_cred, - &pjsua_var.media_cfg.turn_auth_cred, + &acc_cfg->turn_cfg.turn_auth_cred, sizeof(ice_cfg.turn.auth_cred)); /* Copy QoS setting to TURN setting */ @@ -730,7 +740,7 @@ static pj_status_t create_ice_media_transport( call_med->tp_ready = PJ_EPENDING; comp_cnt = 1; - if (PJMEDIA_ADVERTISE_RTCP && !pjsua_var.media_cfg.ice_no_rtcp) + if (PJMEDIA_ADVERTISE_RTCP && !acc_cfg->ice_cfg.ice_no_rtcp) ++comp_cnt; status = pjmedia_ice_create3(pjsua_var.med_endpt, name, comp_cnt, @@ -858,7 +868,7 @@ PJ_DEF(pj_status_t) pjsua_media_transports_create( pjsua_transport_config_dup(pjsua_var.pool, &cfg, app_cfg); /* Create the transports */ - if (pjsua_var.media_cfg.enable_ice) { + if (pjsua_var.ice_cfg.enable_ice) { status = create_ice_media_transports(&cfg); } else { status = create_udp_media_transports(&cfg); @@ -1244,7 +1254,7 @@ pj_status_t pjsua_call_media_init(pjsua_call_media *call_med, pjsua_set_media_tp_state(call_med, PJSUA_MED_TP_CREATING); - if (pjsua_var.media_cfg.enable_ice) { + if (pjsua_var.acc[call_med->call->acc_id].cfg.ice_cfg.enable_ice) { status = create_ice_media_transport(tcfg, call_med, async); if (async && status == PJ_EPENDING) { /* We will resume call media initialization in the |