From 294fe9656622d85c4d3a5b22ce45d2d18aac1784 Mon Sep 17 00:00:00 2001 From: sauwming Date: Wed, 3 Apr 2024 18:04:51 +0800 Subject: [PATCH] Improve IP address change IPv4 <-> IPv6 (#3910) --- pjsip-apps/src/pjsua/pjsua_app_legacy.c | 2 -- pjsip/include/pjsua-lib/pjsua.h | 12 ++++++++++ pjsip/include/pjsua2/account.hpp | 12 ++++++++++ pjsip/src/pjsip/sip_dialog.c | 9 ++++++- pjsip/src/pjsip/sip_util.c | 24 ++++++++++++++++++- pjsip/src/pjsua-lib/pjsua_acc.c | 32 +++++++++++++++++++++---- pjsip/src/pjsua2/account.cpp | 2 ++ 7 files changed, 84 insertions(+), 9 deletions(-) diff --git a/pjsip-apps/src/pjsua/pjsua_app_legacy.c b/pjsip-apps/src/pjsua/pjsua_app_legacy.c index 0559827007..14f3e95c8f 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_legacy.c +++ b/pjsip-apps/src/pjsua/pjsua_app_legacy.c @@ -1786,8 +1786,6 @@ static void ui_handle_ip_change() status = pjsua_handle_ip_change(¶m); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "IP change failed", status); - } else { - PJ_LOG(3,(THIS_FILE, "IP change succeeded")); } } diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 7b33a6a0d8..e39572f267 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -4542,6 +4542,18 @@ typedef struct pjsua_acc_config */ pj_bool_t register_on_acc_add; + /** + * Specify whether account modification with pjsua_acc_modify() should + * automatically update registration if necessary, for example if + * account credentials change. + * + * Disable this when immediate registration is not desirable, such as + * during IP address change. + * + * Default: PJ_FALSE. + */ + pj_bool_t disable_reg_on_modify; + /** * Specify account configuration specific to IP address change used when * calling #pjsua_handle_ip_change(). diff --git a/pjsip/include/pjsua2/account.hpp b/pjsip/include/pjsua2/account.hpp index f6d2c8cdb2..237d6b8f69 100644 --- a/pjsip/include/pjsua2/account.hpp +++ b/pjsip/include/pjsua2/account.hpp @@ -62,6 +62,18 @@ struct AccountRegConfig : public PersistentObject */ bool registerOnAdd; + /** + * Specify whether account modification with Account::modify() should + * automatically update registration if necessary, for example if + * account credentials change. + * + * Disable this when immediate registration is not desirable, such as + * during IP address change. + * + * Default: false. + */ + bool disableRegOnModify; + /** * The optional custom SIP headers to be put in the registration * request. diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c index 1be1f0704c..2c40106a66 100644 --- a/pjsip/src/pjsip/sip_dialog.c +++ b/pjsip/src/pjsip/sip_dialog.c @@ -474,6 +474,8 @@ pj_status_t create_uas_dialog( pjsip_user_agent *ua, if (rdata->tp_info.transport->dir == PJSIP_TP_DIR_OUTGOING) { pj_strdup(dlg->pool, &dlg->initial_dest, &rdata->tp_info.transport->remote_name.host); + PJ_LOG(5, (THIS_FILE, "Saving initial dest %.*s", + (int)dlg->initial_dest.slen, dlg->initial_dest.ptr)); } /* Init remote's contact from Contact header. @@ -1222,8 +1224,11 @@ static pj_status_t dlg_create_request_throw( pjsip_dialog *dlg, /* Copy the initial destination host to tdata. This information can be * used later by transport for transport selection. */ - if (dlg->initial_dest.slen) + if (dlg->initial_dest.slen) { pj_strdup(tdata->pool, &tdata->dest_info.name, &dlg->initial_dest); + PJ_LOG(5, (THIS_FILE, "Setting initial dest %.*s", + (int)dlg->initial_dest.slen, dlg->initial_dest.ptr)); + } /* Done. */ *p_tdata = tdata; @@ -1878,6 +1883,8 @@ static void dlg_update_routeset(pjsip_dialog *dlg, const pjsip_rx_data *rdata) { pj_strdup(dlg->pool, &dlg->initial_dest, &rdata->tp_info.transport->remote_name.host); + PJ_LOG(5, (THIS_FILE, "Saving initial dest %.*s", + (int)dlg->initial_dest.slen, dlg->initial_dest.ptr)); } else { /* Reset the stored remote name if the transport is a server * transport. diff --git a/pjsip/src/pjsip/sip_util.c b/pjsip/src/pjsip/sip_util.c index 4c5b3265c7..1167093166 100644 --- a/pjsip/src/pjsip/sip_util.c +++ b/pjsip/src/pjsip/sip_util.c @@ -1409,7 +1409,7 @@ 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? + 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()); @@ -1463,6 +1463,28 @@ PJ_DEF(pj_status_t) pjsip_endpt_send_request_stateless(pjsip_endpoint *endpt, if (!tdata->dest_info.name.slen) { pj_strdup(tdata->pool, &tdata->dest_info.name, &dest_info.addr.host); + } else { + /* Check if: + * - User configures transport to use a specific IP version + * - The IP version doesn't match with destination info + */ + if (tdata->tp_sel.type == PJSIP_TPSELECTOR_IP_VER && + ((tdata->tp_sel.u.ip_ver == PJSIP_TPSELECTOR_USE_IPV4_ONLY && + (dest_info.type & PJSIP_TRANSPORT_IPV6) != 0) || + (tdata->tp_sel.u.ip_ver == PJSIP_TPSELECTOR_USE_IPV6_ONLY && + (dest_info.type & PJSIP_TRANSPORT_IPV6) == 0))) + { + PJ_LOG(5, (THIS_FILE, "Using initial dest %.*s", + (int)tdata->dest_info.name.slen, + tdata->dest_info.name.ptr)); + pj_strdup(tdata->pool, &dest_info.addr.host, + &tdata->dest_info.name); + if (tdata->tp_sel.u.ip_ver == PJSIP_TPSELECTOR_USE_IPV4_ONLY) { + dest_info.type &= ~PJSIP_TRANSPORT_IPV6; + } else { + dest_info.type |= PJSIP_TRANSPORT_IPV6; + } + } } pjsip_endpt_resolve( endpt, tdata->pool, &dest_info, stateless_data, diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c index b7cd386566..03605ab76c 100644 --- a/pjsip/src/pjsua-lib/pjsua_acc.c +++ b/pjsip/src/pjsua-lib/pjsua_acc.c @@ -998,6 +998,14 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id, acc->cfg.ipv6_sip_use = cfg->ipv6_sip_use; update_reg = PJ_TRUE; unreg_first = PJ_TRUE; + + /* Set client registration's transport based on acc's config. */ + if (acc->regc) { + pjsip_tpselector tp_sel; + + pjsua_init_tpselector(acc->index, &tp_sel); + pjsip_regc_set_transport(acc->regc, &tp_sel); + } } /* User data */ @@ -1465,7 +1473,7 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id, acc->cfg.call_hold_type = cfg->call_hold_type; /* Unregister first */ - if (unreg_first) { + if (unreg_first && !cfg->disable_reg_on_modify) { if (acc->regc) { status = pjsua_acc_set_registration(acc->index, PJ_FALSE); if (status != PJ_SUCCESS) { @@ -1485,7 +1493,7 @@ PJ_DEF(pj_status_t) pjsua_acc_modify( pjsua_acc_id acc_id, } /* Update registration */ - if (update_reg) { + if (update_reg && !cfg->disable_reg_on_modify) { /* If accounts has registration enabled, start registration */ if (acc->cfg.reg_uri.slen) { status = pjsua_acc_set_registration(acc->index, PJ_TRUE); @@ -4425,6 +4433,8 @@ pj_status_t pjsua_acc_handle_call_on_ip_change(pjsua_acc *acc) { for (i = 0; i < pjsua_var.ua_cfg.max_calls; ++i) { pjsua_call_info call_info; + pjsua_call *call; + pjsip_dialog *dlg = NULL; if (!pjsua_call_is_active(i) || pjsua_var.calls[i].acc_id != acc->index || @@ -4433,6 +4443,21 @@ pj_status_t pjsua_acc_handle_call_on_ip_change(pjsua_acc *acc) continue; } + status = acquire_call("call_tpsel_on_ip_change()", + i, &call, &dlg); + if (status == PJ_SUCCESS) { + pjsip_tpselector 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); + + pjsip_dlg_dec_lock(dlg); + } else { + PJ_LOG(4, (THIS_FILE, "Failed to update call %d's transport " + "selector", i)); + } + if ((acc->cfg.ip_change_cfg.hangup_calls) && (call_info.state >= PJSIP_INV_STATE_EARLY)) { @@ -4488,9 +4513,6 @@ pj_status_t pjsua_acc_handle_call_on_ip_change(pjsua_acc *acc) /* Check if remote support SIP UPDATE method */ if (use_update) { - pjsua_call *call; - pjsip_dialog *dlg = NULL; - PJ_LOG(5, (THIS_FILE, "Call #%d: IP change is configured " "to using UPDATE", i)); diff --git a/pjsip/src/pjsua2/account.cpp b/pjsip/src/pjsua2/account.cpp index 025ca3acc7..5f00dbdbde 100644 --- a/pjsip/src/pjsua2/account.cpp +++ b/pjsip/src/pjsua2/account.cpp @@ -575,6 +575,7 @@ void AccountConfig::toPj(pjsua_acc_config &ret) const // AccountRegConfig ret.reg_uri = str2Pj(regConfig.registrarUri); ret.register_on_acc_add = regConfig.registerOnAdd; + ret.disable_reg_on_modify = regConfig.disableRegOnModify; ret.reg_timeout = regConfig.timeoutSec; ret.reg_retry_interval = regConfig.retryIntervalSec; ret.reg_first_retry_interval= regConfig.firstRetryIntervalSec; @@ -734,6 +735,7 @@ void AccountConfig::fromPj(const pjsua_acc_config &prm, // AccountRegConfig regConfig.registrarUri = pj2Str(prm.reg_uri); regConfig.registerOnAdd = (prm.register_on_acc_add != 0); + regConfig.disableRegOnModify= (prm.disable_reg_on_modify != 0); regConfig.timeoutSec = prm.reg_timeout; regConfig.retryIntervalSec = prm.reg_retry_interval; regConfig.firstRetryIntervalSec = prm.reg_first_retry_interval;