From 0eb867bdf53c202fc1b1bc3af1e1845beedb22bd Mon Sep 17 00:00:00 2001 From: sauwming Date: Mon, 5 Jun 2023 15:40:16 +0800 Subject: [PATCH 1/5] Add option for dual stack IPv4&IPv6 account config --- pjsip-apps/src/pjsua/pjsua_app.c | 6 +- pjsip-apps/src/pjsua/pjsua_app_config.c | 2 +- pjsip/include/pjsip/sip_resolve.h | 38 ++-- pjsip/include/pjsip/sip_transport.h | 19 ++ pjsip/include/pjsua-lib/pjsua.h | 33 +++- pjsip/include/pjsua2/account.hpp | 17 +- pjsip/src/pjsip/sip_transport.c | 9 + pjsip/src/pjsip/sip_util.c | 28 +++ pjsip/src/pjsua-lib/pjsua_acc.c | 236 +++++++++++++++--------- pjsip/src/pjsua-lib/pjsua_call.c | 28 +-- pjsip/src/pjsua-lib/pjsua_core.c | 41 ++-- pjsip/src/pjsua-lib/pjsua_im.c | 27 +-- pjsip/src/pjsua-lib/pjsua_media.c | 57 ++++-- pjsip/src/pjsua-lib/pjsua_pres.c | 39 ++-- pjsip/src/pjsua2/account.cpp | 2 + 15 files changed, 370 insertions(+), 212 deletions(-) diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index 92071bffbd..c53b04c0a9 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -1713,7 +1713,7 @@ static pj_status_t app_init(void) app_config_init_video(&acc_cfg); acc_cfg.rtp_cfg = app_config.rtp_cfg; - acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED; + // acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED; pjsua_acc_modify(aid, &acc_cfg); } @@ -1778,7 +1778,7 @@ static pj_status_t app_init(void) app_config_init_video(&acc_cfg); acc_cfg.rtp_cfg = app_config.rtp_cfg; - acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED; + // acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED; pjsua_acc_modify(aid, &acc_cfg); } @@ -1846,7 +1846,7 @@ static pj_status_t app_init(void) app_config_init_video(&acc_cfg); acc_cfg.rtp_cfg = app_config.rtp_cfg; - acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED; + // acc_cfg.ipv6_media_use = PJSUA_IPV6_ENABLED; pjsua_acc_modify(aid, &acc_cfg); } diff --git a/pjsip-apps/src/pjsua/pjsua_app_config.c b/pjsip-apps/src/pjsua/pjsua_app_config.c index ca85e5719b..9e710b8fcd 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_config.c +++ b/pjsip-apps/src/pjsua/pjsua_app_config.c @@ -91,7 +91,7 @@ static void usage(void) puts (""); puts ("Transport Options:"); #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6 - puts (" --ipv6 Use IPv6 instead for SIP and media."); + puts (" --ipv6 Create SIP IPv6 transports."); #endif puts (" --set-qos Enable QoS tagging for SIP and media."); puts (" --local-port=port Set TCP/UDP port. This implicitly enables both "); diff --git a/pjsip/include/pjsip/sip_resolve.h b/pjsip/include/pjsip/sip_resolve.h index 29a690cfce..1da5bc89b9 100644 --- a/pjsip/include/pjsip/sip_resolve.h +++ b/pjsip/include/pjsip/sip_resolve.h @@ -171,6 +171,25 @@ PJ_BEGIN_DECL * - RFC 3263: Locating SIP Servers */ + /** Address records. */ +typedef struct pjsip_server_address_record +{ + /** Preferable transport to be used to contact this address. */ + pjsip_transport_type_e type; + + /** Server priority (the lower the higher the priority). */ + unsigned priority; + + /** Server weight (the higher the more load it can handle). */ + unsigned weight; + + /** The server's address. */ + pj_sockaddr addr; + + /** Address length. */ + int addr_len; +} pjsip_server_address_record; + /** * The server addresses returned by the resolver. */ @@ -180,24 +199,7 @@ typedef struct pjsip_server_addresses unsigned count; /** Address records. */ - struct - { - /** Preferable transport to be used to contact this address. */ - pjsip_transport_type_e type; - - /** Server priority (the lower the higher the priority). */ - unsigned priority; - - /** Server weight (the higher the more load it can handle). */ - unsigned weight; - - /** The server's address. */ - pj_sockaddr addr; - - /** Address length. */ - int addr_len; - - } entry[PJSIP_MAX_RESOLVED_ADDRESSES]; + pjsip_server_address_record entry[PJSIP_MAX_RESOLVED_ADDRESSES]; } pjsip_server_addresses; diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h index 657081fdd5..a6a076d722 100644 --- a/pjsip/include/pjsip/sip_transport.h +++ b/pjsip/include/pjsip/sip_transport.h @@ -203,8 +203,25 @@ typedef enum pjsip_tpselector_type /** Use the specific listener to send request. */ PJSIP_TPSELECTOR_LISTENER, + /** Use the specific listener to send request. */ + PJSIP_TPSELECTOR_CONFIG, + } pjsip_tpselector_type; +typedef enum pjsip_tpselector_config +{ + PJSIP_TPSELECTOR_USE_IPV4_ONLY, + + PJSIP_TPSELECTOR_NO_PREFERENCE, + + PJSIP_TPSELECTOR_PREFER_IPV4, + + PJSIP_TPSELECTOR_PREFER_IPV6, + + PJSIP_TPSELECTOR_USE_IPV6_ONLY + +} pjsip_tpselector_config; + /** * This structure describes the transport/listener preference to be used @@ -233,6 +250,8 @@ typedef struct pjsip_tpselector /** The type of data in the union */ pjsip_tpselector_type type; + pjsip_tpselector_config config; + /** * Whether to disable reuse of an existing connection. * This setting will be ignored if (type == PJSIP_TPSELECTOR_TRANSPORT) diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index a2fcf206b6..15f8365c90 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -3677,6 +3677,8 @@ typedef struct pjsua_turn_config /** * Specify how IPv6 transport should be used in account config. + * IP version preference only applies for outgoing direction, for incoming + * direction, we will check the corresponding message/offer and match it. */ typedef enum pjsua_ipv6_use { @@ -3688,7 +3690,23 @@ typedef enum pjsua_ipv6_use /** * IPv6 is enabled. */ - PJSUA_IPV6_ENABLED + PJSUA_IPV6_ENABLED = 1, + PJSUA_IPV6_ENABLED_NO_PREFERENCE = 1, + + /** + * IPv6 is enabled, but IPv4 is preferable. + */ + PJSUA_IPV6_ENABLED_PREFER_IPV4, + + /** + * IPv6 is enabled and preferable. + */ + PJSUA_IPV6_ENABLED_PREFER_IPV6, + + /** + * Only IPv6 is enabled, IPv4 will not be used. + */ + PJSUA_IPV6_ENABLED_USE_IPV6_ONLY } pjsua_ipv6_use; @@ -4177,8 +4195,21 @@ typedef struct pjsua_acc_config */ pjsua_nat64_opt nat64_opt; + /** + * Specify whether IPv6 should be used for SIP signalling. + * + * Default: PJSUA_IPV6_ENABLED_NO_PREFERENCE + * (IP version used will be based on the address resolution + * returned by OS/resolver) + */ + pjsua_ipv6_use ipv6_sip_use; + /** * Specify whether IPv6 should be used on media. + * + * Default: PJSUA_IPV6_ENABLED_PREFER_IPV4 + * (Dual stack media, capable to use IPv4/IPv6. + * Outgoing offer will prefer to use IPv4) */ pjsua_ipv6_use ipv6_media_use; diff --git a/pjsip/include/pjsua2/account.hpp b/pjsip/include/pjsua2/account.hpp index d0b80d56a9..4ed74255d9 100644 --- a/pjsip/include/pjsua2/account.hpp +++ b/pjsip/include/pjsua2/account.hpp @@ -277,6 +277,15 @@ struct AccountSipConfig : public PersistentObject */ TransportId transportId; + /** + * Specify whether IPv6 should be used for SIP signalling. + * + * Default: PJSUA_IPV6_ENABLED_NO_PREFERENCE + * (IP version used will be based on the address resolution + * returned by OS/resolver) + */ + pjsua_ipv6_use ipv6Use; + public: /** * Read this object from a container node. @@ -1033,7 +1042,11 @@ struct AccountMediaConfig : public PersistentObject SrtpOpt srtpOpt; /** - * Specify whether IPv6 should be used on media. Default is not used. + * Specify whether IPv6 should be used on media. + * + * Default: PJSUA_IPV6_ENABLED_PREFER_IPV4 + * (Dual stack media, capable to use IPv4/IPv6. + * Outgoing offer will prefer to use IPv4) */ pjsua_ipv6_use ipv6Use; @@ -1082,7 +1095,7 @@ struct AccountMediaConfig : public PersistentObject streamKaEnabled(false), srtpUse(PJSUA_DEFAULT_USE_SRTP), srtpSecureSignaling(PJSUA_DEFAULT_SRTP_SECURE_SIGNALING), - ipv6Use(PJSUA_IPV6_DISABLED), + ipv6Use(PJSUA_IPV6_ENABLED_PREFER_IPV4), rtcpMuxEnabled(false), rtcpXrEnabled(PJMEDIA_STREAM_ENABLE_XR), useLoopMedTp(false), diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c index 6887f88813..77b110949d 100644 --- a/pjsip/src/pjsip/sip_transport.c +++ b/pjsip/src/pjsip/sip_transport.c @@ -2331,6 +2331,15 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr, TRACE_((THIS_FILE, "Listener type in tpsel not matched")); return PJSIP_ETPNOTSUITABLE; } + } else if (sel && sel->type == PJSIP_TPSELECTOR_CONFIG) { + if ((sel->config == PJSIP_TPSELECTOR_USE_IPV4_ONLY && + pjsip_transport_type_get_af(type) != pj_AF_INET()) || + (sel->config == PJSIP_TPSELECTOR_USE_IPV6_ONLY && + pjsip_transport_type_get_af(type) != pj_AF_INET6())) + { + TRACE_((THIS_FILE, "Address type in tpsel not matched")); + return PJSIP_ETPNOTSUITABLE; + } } if (!sel || sel->disable_connection_reuse == PJ_FALSE) { diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c index 3fa025490c..c5a9108655 100644 --- a/pjsip/src/pjsip/sip_util.c +++ b/pjsip/src/pjsip/sip_util.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -1306,6 +1307,26 @@ static void stateless_send_transport_cb( void *token, } +/* Resort addresses based on preferred address family. + * Note that the order of addresses within the same address family will + * be preserved. + */ +static void resort_address(pjsip_server_addresses *addr, int af) +{ + unsigned i = 0, j = 0; + + while (j < addr->count) { + if (addr->entry[j].addr.addr.sa_family == af) { + pjsip_server_address_record temp; + + pj_memcpy(&temp, &addr->entry[j], sizeof(temp)); + pj_array_insert(addr->entry, sizeof(addr->entry[0]), j, i, &addr->entry[j]); + i++; + } + j++; + } +} + /* Resolver callback for sending stateless request. */ static void stateless_send_resolver_callback( pj_status_t status, @@ -1382,6 +1403,13 @@ stateless_send_resolver_callback( pj_status_t status, } } + if (tdata->tp_sel.type == PJSIP_TPSELECTOR_CONFIG) { + if (tdata->tp_sel.config == PJSIP_TPSELECTOR_PREFER_IPV4) + resort_address(&tdata->dest_info.addr, pj_AF_INET()); + else if (tdata->tp_sel.config == PJSIP_TPSELECTOR_PREFER_IPV6) + resort_address(&tdata->dest_info.addr, pj_AF_INET6()); + } + /* Process the addresses. */ stateless_send_transport_cb( stateless_data, tdata, -PJ_EPENDING); } diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c index 1d327a6569..e44de0f5f2 100644 --- a/pjsip/src/pjsua-lib/pjsua_acc.c +++ b/pjsip/src/pjsua-lib/pjsua_acc.c @@ -2593,6 +2593,7 @@ static pj_status_t pjsua_regc_init(int acc_id) { pjsua_acc *acc; pj_pool_t *pool; + pjsip_tpselector tp_sel; pj_status_t status; PJ_ASSERT_RETURN(pjsua_acc_is_valid(acc_id), PJ_EINVAL); @@ -2656,16 +2657,9 @@ static pj_status_t pjsua_regc_init(int acc_id) pjsip_regc_set_reg_tsx_cb(acc->regc, regc_tsx_cb); - /* If account is locked to specific transport, then set transport to - * the client registration. - */ - if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) { - pjsip_tpselector tp_sel; - - pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel); - pjsip_regc_set_transport(acc->regc, &tp_sel); - } - + /* Set client registration's transport based on acc's config. */ + pjsua_init_tpselector(acc_id, &tp_sel); + pjsip_regc_set_transport(acc->regc, &tp_sel); /* Set credentials */ @@ -2759,7 +2753,37 @@ pj_bool_t pjsua_sip_acc_is_using_ipv6(pjsua_acc_id acc_id) { pjsua_acc *acc = &pjsua_var.acc[acc_id]; - return (acc->tp_type & PJSIP_TRANSPORT_IPV6) == PJSIP_TRANSPORT_IPV6; + return ((acc->tp_type & PJSIP_TRANSPORT_IPV6) == PJSIP_TRANSPORT_IPV6 || + pjsua_var.acc[acc_id].cfg.ipv6_sip_use == + PJSUA_IPV6_ENABLED_USE_IPV6_ONLY); +} + +static int sip_acc_get_pref_ip_ver(pjsua_acc_id acc_id) +{ + pjsua_acc *acc = &pjsua_var.acc[acc_id]; + + if ((acc->tp_type & PJSIP_TRANSPORT_IPV6) == PJSIP_TRANSPORT_IPV6 || + pjsua_var.acc[acc_id].cfg.ipv6_sip_use == + PJSUA_IPV6_ENABLED_PREFER_IPV6 || + pjsua_var.acc[acc_id].cfg.ipv6_sip_use == + PJSUA_IPV6_ENABLED_USE_IPV6_ONLY) + { + return 6; + } else if (acc->tp_type != PJSIP_TRANSPORT_UNSPECIFIED || + pjsua_var.acc[acc_id].cfg.ipv6_sip_use == + PJSUA_IPV6_ENABLED_PREFER_IPV4 || + pjsua_var.acc[acc_id].cfg.ipv6_sip_use == + PJSUA_IPV6_DISABLED) + { + return 4; + } else { + /* No preference. + * (acc->tp_type == PJSIP_TRANSPORT_UNSPECIFIED && + * pjsua_var.acc[acc_id].cfg.ipv6_sip_use == + * PJSUA_IPV6_ENABLED_NO_PREFERENCE) + */ + return 0; + } } pj_bool_t pjsua_sip_acc_is_using_stun(pjsua_acc_id acc_id) @@ -3295,6 +3319,7 @@ PJ_DEF(pj_status_t) pjsua_acc_create_request(pjsua_acc_id acc_id, pjsip_tx_data *tdata; pjsua_acc *acc; pjsip_route_hdr *r; + pjsip_tpselector tp_sel; pj_status_t status; PJ_ASSERT_RETURN(method && target && p_tdata, PJ_EINVAL); @@ -3318,15 +3343,9 @@ PJ_DEF(pj_status_t) pjsua_acc_create_request(pjsua_acc_id acc_id, r = r->next; } - /* If account is locked to specific transport, then set that transport to - * the transmit data. - */ - if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) { - pjsip_tpselector tp_sel; - - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); - pjsip_tx_data_set_transport(tdata, &tp_sel); - } + /* Set transmit data's transport based on acc's config. */ + pjsua_init_tpselector(acc_id, &tp_sel); + pjsip_tx_data_set_transport(tdata, &tp_sel); /* If via_addr is set, use this address for the Via header. */ if (pjsua_var.acc[acc_id].cfg.allow_via_rewrite && @@ -3390,6 +3409,7 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id, pj_status_t status; pjsip_transport_type_e tp_type = PJSIP_TRANSPORT_UNSPECIFIED; unsigned flag; + int sip_pref_ip; pjsip_tpselector tp_sel; pjsip_tpmgr *tpmgr; pjsip_tpmgr_fla2_param tfla2_prm; @@ -3444,14 +3464,14 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id, /* If destination URI specifies IPv6 or account is configured to use IPv6, * then set transport type to use IPv6 as well. */ - if (pj_strchr(&sip_uri->host, ':') || pjsua_sip_acc_is_using_ipv6(acc_id)) - tp_type = (pjsip_transport_type_e)(((int)tp_type) | - PJSIP_TRANSPORT_IPV6); + sip_pref_ip = sip_acc_get_pref_ip_ver(acc_id); + if (pj_strchr(&sip_uri->host, ':') || sip_pref_ip == 6) + tp_type |= PJSIP_TRANSPORT_IPV6; flag = pjsip_transport_get_flag_from_type(tp_type); /* Init transport selector. */ - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); + pjsua_init_tpselector(acc_id, &tp_sel); /* Get local address suitable to send request from */ pjsip_tpmgr_fla2_param_default(&tfla2_prm); @@ -3515,22 +3535,29 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id, if (acc->cfg.contact_use_src_port) { pjsip_host_info dinfo; pjsip_transport *tp = NULL; - pj_addrinfo ai; - pj_bool_t log_written = PJ_FALSE; + int af; + pj_addrinfo ai[2]; + unsigned ai_cnt = 0; + int ip_addr_ver; + unsigned i; + pjsip_tx_data tdata; + pj_uint16_t port; - status = pjsip_get_dest_info((pjsip_uri*)sip_uri, NULL, + status = pjsip_get_dest_info((pjsip_uri *)sip_uri, NULL, pool, &dinfo); + if (status != PJ_SUCCESS) { + PJ_PERROR(4, (THIS_FILE, status, "Unable to use source local " + "TCP/TLS socket address for Contact")); + goto on_return; + } - if (status==PJ_SUCCESS && (dinfo.flag & PJSIP_TRANSPORT_RELIABLE)==0) { + if ((dinfo.flag & PJSIP_TRANSPORT_RELIABLE) ==0 ) { /* Not TCP or TLS. No need to do this */ - status = PJ_EINVALIDOP; - log_written = PJ_TRUE; + goto on_return; } - if (status==PJ_SUCCESS && - get_ip_addr_ver(&dinfo.addr.host)==0 && - pjsua_var.ua_cfg.nameserver_count) - { + ip_addr_ver = get_ip_addr_ver(&dinfo.addr.host); + if (ip_addr_ver == 0 && pjsua_var.ua_cfg.nameserver_count) { /* If nameserver is configured, PJSIP will resolve destinations * by their DNS SRV record first. On the other hand, we will * resolve destination with DNS A record via pj_getaddrinfo(). @@ -3540,58 +3567,96 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id, */ PJ_LOG(4,(THIS_FILE, "Warning: cannot use source TCP/TLS socket" " address for Contact when nameserver is configured.")); - status = PJ_ENOTSUP; - log_written = PJ_TRUE; + goto on_return; } - if (status == PJ_SUCCESS) { - unsigned cnt=1; - int af = pj_AF_UNSPEC(); + if (ip_addr_ver == 6 || sip_pref_ip == 6) { + /* Get IPv6 address if dest host is IPv6 or we prefer IPv6. */ + af = pj_AF_INET6(); + } else if (ip_addr_ver == 4 || sip_pref_ip == 4) { + /* Get IPv4 address if dest host is IPv4 or we prefer IPv4. */ + af = pj_AF_INET(); + } else { + /* (ip_addr_ver == 0 && sip_pref_ip == 0) + * Destination host is not an IP address, and account config + * indicates no IP version preference, so we'll just use + * the first address returned by the OS. + */ + af = pj_AF_UNSPEC(); + } - if (pjsua_sip_acc_is_using_ipv6(acc_id) || - (dinfo.type & PJSIP_TRANSPORT_IPV6)) - { - af = pj_AF_INET6(); + ai_cnt = 1; + pj_getaddrinfo(af, &dinfo.addr.host, &ai_cnt, &ai[0]); + + /* Get fallback address, only if the host is not IP address and + * account is not bound to a certain transport. + */ + if (ip_addr_ver == 0 && acc->tp_type == PJSIP_TRANSPORT_UNSPECIFIED) { + unsigned cnt = 1; + + /* If first address is IPv4, fallback to IPv6, and vice versa. */ + if (ai_cnt) { + af = (ai[0].ai_addr.addr.sa_family == pj_AF_INET())? + pj_AF_INET6(): pj_AF_INET(); + } else { + af = (af == pj_AF_INET())? pj_AF_INET6(): pj_AF_INET(); } - status = pj_getaddrinfo(af, &dinfo.addr.host, &cnt, &ai); - if (cnt == 0) { - status = PJ_ENOTSUP; - } else if ((dinfo.type & PJSIP_TRANSPORT_IPV6)==0 && - ai.ai_addr.addr.sa_family == pj_AF_INET6()) + /* Check if the fallback addr is allowed. */ + if ((af == pj_AF_INET() && + acc->cfg.ipv6_sip_use != PJSUA_IPV6_ENABLED_USE_IPV6_ONLY) || + (af == pj_AF_INET6() && + acc->cfg.ipv6_sip_use != PJSUA_IPV6_DISABLED)) { - /* Destination is a hostname and account is not bound to IPv6, - * but hostname resolution reveals that it has IPv6 address, - * so let's use IPv6 transport type. - */ - dinfo.type |= PJSIP_TRANSPORT_IPV6; - tp_type |= PJSIP_TRANSPORT_IPV6; + pj_getaddrinfo(af, &dinfo.addr.host, &cnt, &ai[ai_cnt]); + ai_cnt += cnt; } } - if (status == PJ_SUCCESS) { - pjsip_tx_data tdata; - int addr_len = pj_sockaddr_get_len(&ai.ai_addr); - pj_uint16_t port = (pj_uint16_t)dinfo.addr.port; + if (ai_cnt == 0) { + PJ_LOG(4, (THIS_FILE, "Unable to resolve host to " + "generate Contact address")); + goto on_return; + } - /* Create a dummy tdata to inform remote host name to transport */ - pj_bzero(&tdata, sizeof(tdata)); - pj_strdup(pool, &tdata.dest_info.name, &dinfo.addr.host); + /* Create a dummy tdata to inform remote host name to transport */ + pj_bzero(&tdata, sizeof(tdata)); + pj_strdup(pool, &tdata.dest_info.name, &dinfo.addr.host); + port = (pj_uint16_t)dinfo.addr.port; + if (port == 0) { + port = (dinfo.flag & PJSIP_TRANSPORT_SECURE) ? 5061 : 5060; + } - if (port==0) { - port = (dinfo.flag & PJSIP_TRANSPORT_SECURE) ? 5061 : 5060; + /* Try to acquire transport, fallback if fails. */ + for (i = 0; i < ai_cnt; i++) { + int addr_len = pj_sockaddr_get_len(&ai[i].ai_addr); + + if (ai[i].ai_addr.addr.sa_family == pj_AF_INET6()) { + dinfo.type |= PJSIP_TRANSPORT_IPV6; + tp_type |= PJSIP_TRANSPORT_IPV6; + } else { + dinfo.type &= ~PJSIP_TRANSPORT_IPV6; + tp_type &= ~PJSIP_TRANSPORT_IPV6; } - pj_sockaddr_set_port(&ai.ai_addr, port); + + pj_sockaddr_set_port(&ai[i].ai_addr, port); status = pjsip_endpt_acquire_transport2(pjsua_var.endpt, dinfo.type, - &ai.ai_addr, + &ai[i].ai_addr, addr_len, &tp_sel, &tdata, &tp); + if (status == PJ_SUCCESS) + break; } - if (status == PJ_SUCCESS && (tp->local_name.port == 0 || - tp->local_name.host.slen==0 || - *tp->local_name.host.ptr=='0')) + if (status != PJ_SUCCESS) { + PJ_LOG(4,(THIS_FILE, "Unable to acquire transport for " + "Contact address")); + goto on_return; + } + + if (tp->local_name.port == 0 || tp->local_name.host.slen==0 || + *tp->local_name.host.ptr=='0') { /* Trap zero port or "0.0.0.0" address. */ /* The TCP/TLS transport is still connecting and unfortunately @@ -3599,11 +3664,7 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id, */ PJ_LOG(4,(THIS_FILE, "Unable to get transport local port " "for Contact address (OS doesn't support)")); - status = PJ_ENOTSUP; - log_written = PJ_TRUE; - } - - if (status == PJ_SUCCESS) { + } else { /* Got the local transport address, don't update if * we are on NAT64 and already obtained the address * from STUN above. @@ -3613,22 +3674,14 @@ pj_status_t pjsua_acc_get_uac_addr(pjsua_acc_id acc_id, addr->port = tp->local_name.port; } - if (tp) { - /* Here the transport's ref counter WILL reach zero. But the - * transport will NOT get destroyed because it should have an - * idle timer. - */ - pjsip_transport_dec_ref(tp); - tp = NULL; - } - - if (status != PJ_SUCCESS && !log_written) { - PJ_PERROR(4,(THIS_FILE, status, "Unable to use source local " - "TCP socket address for Contact")); - } - status = PJ_SUCCESS; + /* Here the transport's ref counter WILL reach zero. But the + * transport will NOT get destroyed because it should have an + * idle timer. + */ + pjsip_transport_dec_ref(tp); } +on_return: if (p_tp_type) *p_tp_type = tp_type; @@ -3832,6 +3885,8 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uas_contact( pj_pool_t *pool, pjsua_sip_acc_is_using_ipv6(acc_id) || (rdata->tp_info.transport->key.type & PJSIP_TRANSPORT_IPV6)) { + if (acc->cfg.ipv6_sip_use == PJSUA_IPV6_DISABLED) + return PJSIP_EUNSUPTRANSPORT; tp_type = (pjsip_transport_type_e) (((int)tp_type) | PJSIP_TRANSPORT_IPV6); } @@ -3840,7 +3895,10 @@ PJ_DEF(pj_status_t) pjsua_acc_create_uas_contact( pj_pool_t *pool, secure = (flag & PJSIP_TRANSPORT_SECURE) != 0; /* Init transport selector. */ - pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel); + pj_bzero(&tp_sel, sizeof(tp_sel)); + if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) { + pjsua_init_tpselector(acc_id, &tp_sel); + } /* Get local address suitable to send request from */ pjsip_tpmgr_fla2_param_default(&tfla2_prm); @@ -3928,7 +3986,7 @@ PJ_DEF(pj_status_t) pjsua_acc_set_transport( pjsua_acc_id acc_id, /* Update client registration's transport. */ pjsip_tpselector tp_sel; - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); + pjsua_init_tpselector(acc_id, &tp_sel); pjsip_regc_set_transport(acc->regc, &tp_sel); } } else { diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c index 256666d3c8..333a891d4d 100644 --- a/pjsip/src/pjsua-lib/pjsua_call.c +++ b/pjsip/src/pjsua-lib/pjsua_call.c @@ -439,6 +439,7 @@ on_make_call_med_tp_complete(pjsua_call_id call_id, unsigned options = 0; pjsip_tx_data *tdata; pj_bool_t cb_called = PJ_FALSE; + pjsip_tpselector tp_sel; pj_status_t status = (info? info->status: PJ_SUCCESS); PJSUA_LOCK(); @@ -524,15 +525,9 @@ on_make_call_med_tp_complete(pjsua_call_id call_id, dlg->mod_data[pjsua_var.mod.id] = call; inv->mod_data[pjsua_var.mod.id] = call; - /* If account is locked to specific transport, then lock dialog - * to this transport too. - */ - if (acc->cfg.transport_id != PJSUA_INVALID_ID) { - pjsip_tpselector tp_sel; - - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); - pjsip_dlg_set_transport(dlg, &tp_sel); - } + /* Set dialog's transport based on acc's config. */ + pjsua_init_tpselector(call->acc_id, &tp_sel); + pjsip_dlg_set_transport(dlg, &tp_sel); /* Set dialog Route-Set: */ if (!pj_list_empty(&acc->route_set)) @@ -814,7 +809,7 @@ void call_update_contact(pjsua_call *call, pj_str_t **new_contact) /* When contact is changed, the account transport may have been * changed too, so let's update the dialog's transport too. */ - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); + pjsua_init_tpselector(call->acc_id, &tp_sel); pjsip_dlg_set_transport(call->inv->dlg, &tp_sel); } @@ -1479,6 +1474,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) int sip_err_code = PJSIP_SC_INTERNAL_SERVER_ERROR; pjmedia_sdp_session *offer=NULL; pj_bool_t should_dec_dlg = PJ_FALSE; + pjsip_tpselector tp_sel; pj_status_t status; /* Don't want to handle anything but INVITE */ @@ -1872,15 +1868,9 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) goto on_return; } - /* If account is locked to specific transport, then lock dialog - * to this transport too. - */ - if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) { - pjsip_tpselector tp_sel; - - pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel); - pjsip_dlg_set_transport(dlg, &tp_sel); - } + /* Set dialog's transport based on acc's config. */ + pjsua_init_tpselector(acc_id, &tp_sel); + pjsip_dlg_set_transport(dlg, &tp_sel); /* Create and attach pjsua_var data to the dialog */ call->inv = inv; diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 3b75f7eaed..45f5563f4e 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -373,6 +373,9 @@ PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg) cfg->register_on_acc_add = PJ_TRUE; cfg->mwi_expires = PJSIP_MWI_DEFAULT_EXPIRES; + cfg->ipv6_sip_use = PJSUA_IPV6_ENABLED_NO_PREFERENCE; + cfg->ipv6_media_use = PJSUA_IPV6_ENABLED_PREFER_IPV4; + cfg->media_stun_use = PJSUA_STUN_RETRY_ON_FAILURE; cfg->ip_change_cfg.shutdown_tp = PJ_TRUE; cfg->ip_change_cfg.hangup_calls = PJ_FALSE; @@ -3210,30 +3213,36 @@ void pjsua_parse_media_type( pj_pool_t *pool, /* - * Internal function to init transport selector from transport id. + * Internal function to init transport selector based on account's config. */ -void pjsua_init_tpselector(pjsua_transport_id tp_id, +void pjsua_init_tpselector(pjsua_acc_id acc_id, pjsip_tpselector *sel) { - pjsua_transport_data *tpdata; - unsigned flag; + pjsua_acc *acc = &pjsua_var.acc[acc_id]; pj_bzero(sel, sizeof(*sel)); - if (tp_id == PJSUA_INVALID_ID) - return; - PJ_ASSERT_RETURN(tp_id >= 0 && - tp_id < (int)PJ_ARRAY_SIZE(pjsua_var.tpdata), ); - tpdata = &pjsua_var.tpdata[tp_id]; + if (acc->cfg.transport_id != PJSUA_INVALID_ID) { + pjsua_transport_data *tpdata; + unsigned flag; - flag = pjsip_transport_get_flag_from_type(tpdata->type); + PJ_ASSERT_RETURN(acc->cfg.transport_id >= 0 && + acc->cfg.transport_id < + (int)PJ_ARRAY_SIZE(pjsua_var.tpdata), ); + tpdata = &pjsua_var.tpdata[acc->cfg.transport_id]; - if (flag & PJSIP_TRANSPORT_DATAGRAM) { - sel->type = PJSIP_TPSELECTOR_TRANSPORT; - sel->u.transport = tpdata->data.tp; - } else { - sel->type = PJSIP_TPSELECTOR_LISTENER; - sel->u.listener = tpdata->data.factory; + flag = pjsip_transport_get_flag_from_type(tpdata->type); + + if (flag & PJSIP_TRANSPORT_DATAGRAM) { + sel->type = PJSIP_TPSELECTOR_TRANSPORT; + sel->u.transport = tpdata->data.tp; + } else { + sel->type = PJSIP_TPSELECTOR_LISTENER; + sel->u.listener = tpdata->data.factory; + } + } else if (acc->cfg.ipv6_sip_use == PJSUA_IPV6_ENABLED_NO_PREFERENCE) { + sel->type = PJSIP_TPSELECTOR_CONFIG; + sel->config = (pjsip_tpselector_config)acc->cfg.ipv6_sip_use; } } diff --git a/pjsip/src/pjsua-lib/pjsua_im.c b/pjsip/src/pjsua-lib/pjsua_im.c index 891cd3d794..e7e4c80a0f 100644 --- a/pjsip/src/pjsua-lib/pjsua_im.c +++ b/pjsip/src/pjsua-lib/pjsua_im.c @@ -542,6 +542,7 @@ PJ_DEF(pj_status_t) pjsua_im_send( pjsua_acc_id acc_id, pjsua_im_data *im_data; pjsua_acc *acc; pj_bool_t content_in_msg_data; + pjsip_tpselector tp_sel; pj_status_t status; PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc), @@ -568,15 +569,9 @@ PJ_DEF(pj_status_t) pjsua_im_send( pjsua_acc_id acc_id, return status; } - /* If account is locked to specific transport, then set transport to - * the request. - */ - if (acc->cfg.transport_id != PJSUA_INVALID_ID) { - pjsip_tpselector tp_sel; - - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); - pjsip_tx_data_set_transport(tdata, &tp_sel); - } + /* Set transmit data's transport based on acc's config. */ + pjsua_init_tpselector(acc_id, &tp_sel); + pjsip_tx_data_set_transport(tdata, &tp_sel); /* Add accept header. */ pjsip_msg_add_hdr( tdata->msg, @@ -674,6 +669,7 @@ PJ_DEF(pj_status_t) pjsua_im_typing( pjsua_acc_id acc_id, pjsua_im_data *im_data; pjsip_tx_data *tdata; pjsua_acc *acc; + pjsip_tpselector tp_sel; pj_status_t status; PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc), @@ -690,16 +686,9 @@ PJ_DEF(pj_status_t) pjsua_im_typing( pjsua_acc_id acc_id, return status; } - - /* If account is locked to specific transport, then set transport to - * the request. - */ - if (acc->cfg.transport_id != PJSUA_INVALID_ID) { - pjsip_tpselector tp_sel; - - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); - pjsip_tx_data_set_transport(tdata, &tp_sel); - } + /* Set transmit data's transport based on acc's config. */ + pjsua_init_tpselector(acc_id, &tp_sel); + pjsip_tx_data_set_transport(tdata, &tp_sel); /* Add accept header. */ pjsip_msg_add_hdr( tdata->msg, diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index 9a76ce0856..a947d41a58 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -246,6 +246,41 @@ pj_status_t pjsua_media_subsys_destroy(unsigned flags) return PJ_SUCCESS; } +static int get_media_ip_version(pjsua_call_media *call_med) +{ + pjmedia_sdp_session *rem_sdp = call_med->call->async_call.rem_sdp; + pjsua_ipv6_use ipv6_use; + + ipv6_use = pjsua_var.acc[call_med->call->acc_id].cfg.ipv6_media_use; + + if (rem_sdp) { + /* Match the default address family according to the offer */ + const pj_str_t ID_IP6 = { "IP6", 3}; + const pjmedia_sdp_media *m; + const pjmedia_sdp_conn *c; + + m = rem_sdp->media[call_med->idx]; + c = m->conn? m->conn : rem_sdp->conn; + + if (pj_stricmp(&c->addr_type, &ID_IP6) == 0 && + ipv6_use != PJSUA_IPV6_DISABLED) + { + /* Use IPv6. */ + return 6; + } + } else { + if (ipv6_use == PJSUA_IPV6_ENABLED_PREFER_IPV6 || + ipv6_use == PJSUA_IPV6_ENABLED_USE_IPV6_ONLY) + { + /* Use IPv6. */ + return 6; + } + } + + /* Use IPv4. */ + return 4; +} + /* * Create RTP and RTCP socket pair, and possibly resolve their public * address via STUN/UPnP. @@ -267,7 +302,7 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med, pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id]; pj_sock_t sock[2]; - use_ipv6 = (acc->cfg.ipv6_media_use != PJSUA_IPV6_DISABLED); + use_ipv6 = (get_media_ip_version(call_med) == 6); use_nat64 = (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED); af = (use_ipv6 || use_nat64) ? pj_AF_INET6() : pj_AF_INET(); @@ -718,7 +753,7 @@ static pj_status_t create_loop_media_transport( int af; pjsua_acc *acc = &pjsua_var.acc[call_med->call->acc_id]; - use_ipv6 = (acc->cfg.ipv6_media_use != PJSUA_IPV6_DISABLED); + use_ipv6 = (get_media_ip_version(call_med) == 6); use_nat64 = (acc->cfg.nat64_opt != PJSUA_NAT64_DISABLED); af = (use_ipv6 || use_nat64) ? pj_AF_INET6() : pj_AF_INET(); @@ -1001,7 +1036,7 @@ static pj_status_t create_ice_media_transport( pjmedia_sdp_session *rem_sdp; acc_cfg = &pjsua_var.acc[call_med->call->acc_id].cfg; - use_ipv6 = (acc_cfg->ipv6_media_use != PJSUA_IPV6_DISABLED); + use_ipv6 = (get_media_ip_version(call_med) == 6); use_nat64 = (acc_cfg->nat64_opt != PJSUA_NAT64_DISABLED); /* Make sure STUN server resolution has completed */ @@ -1028,24 +1063,12 @@ static pj_status_t create_ice_media_transport( ice_cfg.resolver = pjsua_var.resolver; ice_cfg.opt = acc_cfg->ice_cfg.ice_opt; - rem_sdp = call_med->call->async_call.rem_sdp; - - if (rem_sdp) { - /* Match the default address family according to the offer */ - const pj_str_t ID_IP6 = { "IP6", 3}; - const pjmedia_sdp_media *m; - const pjmedia_sdp_conn *c; - - m = rem_sdp->media[call_med->idx]; - c = m->conn? m->conn : rem_sdp->conn; - - if (pj_stricmp(&c->addr_type, &ID_IP6) == 0) - ice_cfg.af = pj_AF_INET6(); - } else if (use_ipv6 || use_nat64) { + if (use_ipv6 || use_nat64) { ice_cfg.af = pj_AF_INET6(); } /* Should not wait for ICE STUN/TURN ready when trickle ICE is enabled */ + rem_sdp = call_med->call->async_call.rem_sdp; if (ice_cfg.opt.trickle != PJ_ICE_SESS_TRICKLE_DISABLED && (call_med->call->inv == NULL || call_med->call->inv->state < PJSIP_INV_STATE_CONFIRMED)) diff --git a/pjsip/src/pjsua-lib/pjsua_pres.c b/pjsip/src/pjsua-lib/pjsua_pres.c index 2c83c20cb0..45921b8b5f 100644 --- a/pjsip/src/pjsua-lib/pjsua_pres.c +++ b/pjsip/src/pjsua-lib/pjsua_pres.c @@ -810,6 +810,7 @@ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata) pj_str_t reason; pjsip_expires_hdr *expires_hdr; pjsua_msg_data msg_data; + pjsip_tpselector tp_sel; pj_status_t status; if (pjsip_method_cmp(req_method, pjsip_get_subscribe_method()) != 0) @@ -943,15 +944,9 @@ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata) /* Subscription has been created, decrement & release dlg lock */ pjsip_dlg_dec_lock(dlg); - /* If account is locked to specific transport, then lock dialog - * to this transport too. - */ - if (acc->cfg.transport_id != PJSUA_INVALID_ID) { - pjsip_tpselector tp_sel; - - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); - pjsip_dlg_set_transport(dlg, &tp_sel); - } + /* Set dialog's transport based on acc's config. */ + pjsua_init_tpselector(acc_id, &tp_sel); + pjsip_dlg_set_transport(dlg, &tp_sel); /* Attach our data to the subscription: */ uapres = PJ_POOL_ALLOC_T(dlg->pool, pjsua_srv_pres); @@ -1795,6 +1790,7 @@ static void subscribe_buddy_presence(pjsua_buddy_id buddy_id) pjsua_acc *acc; pj_str_t contact; pjsip_tx_data *tdata; + pjsip_tpselector tp_sel; pj_status_t status; /* Event subscription callback. */ @@ -1886,15 +1882,9 @@ static void subscribe_buddy_presence(pjsua_buddy_id buddy_id) return; } - /* If account is locked to specific transport, then lock dialog - * to this transport too. - */ - if (acc->cfg.transport_id != PJSUA_INVALID_ID) { - pjsip_tpselector tp_sel; - - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); - pjsip_dlg_set_transport(buddy->dlg, &tp_sel); - } + /* Set dialog's transport based on acc's config. */ + pjsua_init_tpselector(acc_id, &tp_sel); + pjsip_dlg_set_transport(buddy->dlg, &tp_sel); /* Set route-set */ if (!pj_list_empty(&acc->route_set)) { @@ -2111,6 +2101,7 @@ pj_status_t pjsua_start_mwi(pjsua_acc_id acc_id, pj_bool_t force_renew) pj_pool_t *tmp_pool = NULL; pj_str_t contact; pjsip_tx_data *tdata; + pjsip_tpselector tp_sel; pj_status_t status = PJ_SUCCESS; PJ_ASSERT_RETURN(acc_id>=0 && acc_id<(int)PJ_ARRAY_SIZE(pjsua_var.acc) @@ -2220,15 +2211,9 @@ pj_status_t pjsua_start_mwi(pjsua_acc_id acc_id, pj_bool_t force_renew) goto on_return; } - /* If account is locked to specific transport, then lock dialog - * to this transport too. - */ - if (acc->cfg.transport_id != PJSUA_INVALID_ID) { - pjsip_tpselector tp_sel; - - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); - pjsip_dlg_set_transport(acc->mwi_dlg, &tp_sel); - } + /* Set dialog's transport based on acc's config. */ + pjsua_init_tpselector(acc_id, &tp_sel); + pjsip_dlg_set_transport(acc->mwi_dlg, &tp_sel); /* Set route-set */ if (!pj_list_empty(&acc->route_set)) { diff --git a/pjsip/src/pjsua2/account.cpp b/pjsip/src/pjsua2/account.cpp index 67e75159c8..cfa829ae43 100644 --- a/pjsip/src/pjsua2/account.cpp +++ b/pjsip/src/pjsua2/account.cpp @@ -620,6 +620,7 @@ void AccountConfig::toPj(pjsua_acc_config &ret) const ret.auth_pref.initial_auth = sipConfig.authInitialEmpty; ret.auth_pref.algorithm = str2Pj(sipConfig.authInitialAlgorithm); ret.transport_id = sipConfig.transportId; + ret.ipv6_sip_use = sipConfig.ipv6Use; // AccountCallConfig ret.call_hold_type = callConfig.holdType; @@ -781,6 +782,7 @@ void AccountConfig::fromPj(const pjsua_acc_config &prm, sipConfig.authInitialEmpty = PJ2BOOL(prm.auth_pref.initial_auth); sipConfig.authInitialAlgorithm = pj2Str(prm.auth_pref.algorithm); sipConfig.transportId = prm.transport_id; + sipConfig.ipv6Use = prm.ipv6_sip_use; // AccountCallConfig callConfig.holdType = prm.call_hold_type; From 4cc007fd8ddab984f91af231f0e01d12ce80a5df Mon Sep 17 00:00:00 2001 From: sauwming Date: Wed, 7 Jun 2023 16:41:27 +0800 Subject: [PATCH 2/5] Modify tpselector config to criteria based on comment --- pjsip/include/pjsip/sip_transport.h | 14 ++++++++------ pjsip/src/pjsip/sip_transport.c | 6 +++--- pjsip/src/pjsip/sip_util.c | 6 +++--- pjsip/src/pjsua-lib/pjsua_core.c | 6 +++--- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h index a6a076d722..6d701319dc 100644 --- a/pjsip/include/pjsip/sip_transport.h +++ b/pjsip/include/pjsip/sip_transport.h @@ -203,12 +203,15 @@ typedef enum pjsip_tpselector_type /** Use the specific listener to send request. */ PJSIP_TPSELECTOR_LISTENER, - /** Use the specific listener to send request. */ - PJSIP_TPSELECTOR_CONFIG, + /** Use the IP version criteria to send request. */ + PJSIP_TPSELECTOR_IP_VER, } pjsip_tpselector_type; -typedef enum pjsip_tpselector_config +/** + * This enumerator describes the IP version criteria for pjsip_tpselector. + */ +typedef enum pjsip_tpselector_ip_ver { PJSIP_TPSELECTOR_USE_IPV4_ONLY, @@ -220,7 +223,7 @@ typedef enum pjsip_tpselector_config PJSIP_TPSELECTOR_USE_IPV6_ONLY -} pjsip_tpselector_config; +} pjsip_tpselector_ip_ver; /** @@ -250,8 +253,6 @@ typedef struct pjsip_tpselector /** The type of data in the union */ pjsip_tpselector_type type; - pjsip_tpselector_config config; - /** * Whether to disable reuse of an existing connection. * This setting will be ignored if (type == PJSIP_TPSELECTOR_TRANSPORT) @@ -264,6 +265,7 @@ typedef struct pjsip_tpselector pjsip_transport *transport; pjsip_tpfactory *listener; void *ptr; + pjsip_tpselector_ip_ver ip_ver; } u; } pjsip_tpselector; diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c index 77b110949d..04a5c509eb 100644 --- a/pjsip/src/pjsip/sip_transport.c +++ b/pjsip/src/pjsip/sip_transport.c @@ -2331,10 +2331,10 @@ PJ_DEF(pj_status_t) pjsip_tpmgr_acquire_transport2(pjsip_tpmgr *mgr, TRACE_((THIS_FILE, "Listener type in tpsel not matched")); return PJSIP_ETPNOTSUITABLE; } - } else if (sel && sel->type == PJSIP_TPSELECTOR_CONFIG) { - if ((sel->config == PJSIP_TPSELECTOR_USE_IPV4_ONLY && + } else if (sel && sel->type == PJSIP_TPSELECTOR_IP_VER) { + if ((sel->u.ip_ver == PJSIP_TPSELECTOR_USE_IPV4_ONLY && pjsip_transport_type_get_af(type) != pj_AF_INET()) || - (sel->config == PJSIP_TPSELECTOR_USE_IPV6_ONLY && + (sel->u.ip_ver == PJSIP_TPSELECTOR_USE_IPV6_ONLY && pjsip_transport_type_get_af(type) != pj_AF_INET6())) { TRACE_((THIS_FILE, "Address type in tpsel not matched")); diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c index c5a9108655..91247c163e 100644 --- a/pjsip/src/pjsip/sip_util.c +++ b/pjsip/src/pjsip/sip_util.c @@ -1403,10 +1403,10 @@ stateless_send_resolver_callback( pj_status_t status, } } - if (tdata->tp_sel.type == PJSIP_TPSELECTOR_CONFIG) { - if (tdata->tp_sel.config == PJSIP_TPSELECTOR_PREFER_IPV4) + if (tdata->tp_sel.type == PJSIP_TPSELECTOR_IP_VER) { + if (tdata->tp_sel.u.ip_ver == PJSIP_TPSELECTOR_PREFER_IPV4) resort_address(&tdata->dest_info.addr, pj_AF_INET()); - else if (tdata->tp_sel.config == PJSIP_TPSELECTOR_PREFER_IPV6) + else if (tdata->tp_sel.u.ip_ver == PJSIP_TPSELECTOR_PREFER_IPV6) resort_address(&tdata->dest_info.addr, pj_AF_INET6()); } diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 45f5563f4e..bf69daf89d 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -3240,9 +3240,9 @@ void pjsua_init_tpselector(pjsua_acc_id acc_id, sel->type = PJSIP_TPSELECTOR_LISTENER; sel->u.listener = tpdata->data.factory; } - } else if (acc->cfg.ipv6_sip_use == PJSUA_IPV6_ENABLED_NO_PREFERENCE) { - sel->type = PJSIP_TPSELECTOR_CONFIG; - sel->config = (pjsip_tpselector_config)acc->cfg.ipv6_sip_use; + } else if (acc->cfg.ipv6_sip_use != PJSUA_IPV6_ENABLED_NO_PREFERENCE) { + sel->type = PJSIP_TPSELECTOR_IP_VER; + sel->u.ip_ver = (pjsip_tpselector_ip_ver)acc->cfg.ipv6_sip_use; } } From 236ac38bae0d5e840e0e1437c05043848fd8f987 Mon Sep 17 00:00:00 2001 From: sauwming Date: Thu, 8 Jun 2023 13:53:04 +0800 Subject: [PATCH 3/5] Put tpsel ptr at bottom and add pjsua2.i ipv6 enum --- pjsip-apps/src/swig/symbols.i | 6 +++++- pjsip/include/pjsip/sip_transport.h | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/pjsip-apps/src/swig/symbols.i b/pjsip-apps/src/swig/symbols.i index 8c37a0a4ab..85bd7c1066 100644 --- a/pjsip-apps/src/swig/symbols.i +++ b/pjsip-apps/src/swig/symbols.i @@ -816,7 +816,11 @@ typedef enum pjsua_sip_timer_use typedef enum pjsua_ipv6_use { PJSUA_IPV6_DISABLED, - PJSUA_IPV6_ENABLED + PJSUA_IPV6_ENABLED = 1, + PJSUA_IPV6_ENABLED_NO_PREFERENCE = 1, + PJSUA_IPV6_ENABLED_PREFER_IPV4, + PJSUA_IPV6_ENABLED_PREFER_IPV6, + PJSUA_IPV6_ENABLED_USE_IPV6_ONLY } pjsua_ipv6_use; typedef enum pjsua_nat64_opt diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h index 6d701319dc..ee6cd3cee4 100644 --- a/pjsip/include/pjsip/sip_transport.h +++ b/pjsip/include/pjsip/sip_transport.h @@ -262,10 +262,10 @@ typedef struct pjsip_tpselector /** Union representing the transport/listener criteria to be used. */ union { - pjsip_transport *transport; - pjsip_tpfactory *listener; - void *ptr; - pjsip_tpselector_ip_ver ip_ver; + pjsip_transport *transport; + pjsip_tpfactory *listener; + pjsip_tpselector_ip_ver ip_ver; + void *ptr; } u; } pjsip_tpselector; From 1b4065b22a23b6f34a043b9d65898cd6f4add691 Mon Sep 17 00:00:00 2001 From: sauwming Date: Thu, 8 Jun 2023 16:06:17 +0800 Subject: [PATCH 4/5] Fix address sorting bug and add log --- pjsip/src/pjsip/sip_util.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c index 91247c163e..4c5b3265c7 100644 --- a/pjsip/src/pjsip/sip_util.c +++ b/pjsip/src/pjsip/sip_util.c @@ -34,7 +34,7 @@ #include #include -#define THIS_FILE "endpoint" +#define THIS_FILE "sip_util.c" static const char *event_str[] = { @@ -1317,10 +1317,13 @@ static void resort_address(pjsip_server_addresses *addr, int af) while (j < addr->count) { if (addr->entry[j].addr.addr.sa_family == af) { - pjsip_server_address_record temp; + if (i != j) { + pjsip_server_address_record temp; - pj_memcpy(&temp, &addr->entry[j], sizeof(temp)); - pj_array_insert(addr->entry, sizeof(addr->entry[0]), j, i, &addr->entry[j]); + pj_memcpy(&temp, &addr->entry[j], sizeof(temp)); + pj_array_insert(addr->entry, sizeof(addr->entry[0]), + j, i, &temp); + } i++; } j++; @@ -1404,6 +1407,10 @@ stateless_send_resolver_callback( pj_status_t status, } if (tdata->tp_sel.type == PJSIP_TPSELECTOR_IP_VER) { + PJ_LOG(5, (THIS_FILE, "Resorting target addresses based on " + "%s preference", + tdata->tp_sel.u.ip_ver == PJSIP_TPSELECTOR_PREFER_IPV4? + "IPv4": "IPv6")); if (tdata->tp_sel.u.ip_ver == PJSIP_TPSELECTOR_PREFER_IPV4) resort_address(&tdata->dest_info.addr, pj_AF_INET()); else if (tdata->tp_sel.u.ip_ver == PJSIP_TPSELECTOR_PREFER_IPV6) From b2a6683e4863571e7395bbd6142944c04c1ef95e Mon Sep 17 00:00:00 2001 From: sauwming Date: Fri, 9 Jun 2023 11:19:23 +0800 Subject: [PATCH 5/5] Add doc --- pjsip/include/pjsip/sip_resolve.h | 2 +- pjsip/include/pjsip/sip_transport.h | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pjsip/include/pjsip/sip_resolve.h b/pjsip/include/pjsip/sip_resolve.h index 1da5bc89b9..702365e96d 100644 --- a/pjsip/include/pjsip/sip_resolve.h +++ b/pjsip/include/pjsip/sip_resolve.h @@ -171,7 +171,7 @@ PJ_BEGIN_DECL * - RFC 3263: Locating SIP Servers */ - /** Address records. */ +/** Address records. */ typedef struct pjsip_server_address_record { /** Preferable transport to be used to contact this address. */ diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h index ee6cd3cee4..27b4201bea 100644 --- a/pjsip/include/pjsip/sip_transport.h +++ b/pjsip/include/pjsip/sip_transport.h @@ -213,14 +213,22 @@ typedef enum pjsip_tpselector_type */ typedef enum pjsip_tpselector_ip_ver { + /** IPv4 only. */ PJSIP_TPSELECTOR_USE_IPV4_ONLY, + /** + * No preference. IP version used will depend on the order of addresses + * returned by pjsip_resolver. + */ PJSIP_TPSELECTOR_NO_PREFERENCE, + /** IPv4 is preferred. */ PJSIP_TPSELECTOR_PREFER_IPV4, + /** IPv6 is preferred. */ PJSIP_TPSELECTOR_PREFER_IPV6, + /** IPv6 only. */ PJSIP_TPSELECTOR_USE_IPV6_ONLY } pjsip_tpselector_ip_ver; @@ -260,7 +268,10 @@ typedef struct pjsip_tpselector */ pj_bool_t disable_connection_reuse; - /** Union representing the transport/listener criteria to be used. */ + /** + * Union representing the transport/listener/IP version criteria + * to be used. + */ union { pjsip_transport *transport; pjsip_tpfactory *listener;