From c8ce02fa38dff05a43755c1e625241e29bf77e10 Mon Sep 17 00:00:00 2001 From: laconicman Date: Sun, 4 Oct 2026 12:28:29 +0300 Subject: [PATCH 1/6] pjsua: send a configured +sip.instance without SIP outbound too pjsua appends +sip.instance to the registration Contact only together with reg-id, while SIP outbound is wanted, and drops both when the registrar does not confirm outbound. RFC 5626 section 6 allows an instance ID without reg-id, and registrars use it on its own to recognize a device across registrations. If the application set rfc5626_instance_id, update_regc_contact() now appends it whether or not outbound is wanted: over UDP, with use_rfc5626 disabled, when a 2xx lacks "Require: outbound", and on the retry after a 439. reg-id is still sent only while outbound is wanted. The generated instance ID is sent as before, only with outbound: it is a hash of the host name, the same for all instances on one host and on iOS. init_outbound_setting() now also runs for an account that sets an instance ID with use_rfc5626 disabled, marks outbound as wanted only if use_rfc5626 is set, and logs a configured instance ID. The pjsua app gets --instance-id, applied to every account including those added at runtime. --- pjsip-apps/src/pjsua/pjsua_app.c | 1 + pjsip-apps/src/pjsua/pjsua_app_cli.c | 1 + pjsip-apps/src/pjsua/pjsua_app_common.h | 1 + pjsip-apps/src/pjsua/pjsua_app_config.c | 13 +++++++++++++ pjsip-apps/src/pjsua/pjsua_app_legacy.c | 1 + pjsip/include/pjsua-lib/pjsua.h | 4 ++++ pjsip/include/pjsua2/account.hpp | 4 ++++ pjsip/src/pjsua-lib/pjsua_acc.c | 21 ++++++++++++++++----- 8 files changed, 41 insertions(+), 5 deletions(-) diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index fd60ebb765..4023071210 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -2190,6 +2190,7 @@ static pj_status_t app_init(void) app_config_init_video(&app_config.acc_cfg[i]); app_config.acc_cfg[i].txt_red_level = app_config.txt_red_level; + app_config.acc_cfg[i].rfc5626_instance_id = app_config.instance_id; status = pjsua_acc_add(&app_config.acc_cfg[i], PJ_TRUE, NULL); if (status != PJ_SUCCESS) diff --git a/pjsip-apps/src/pjsua/pjsua_app_cli.c b/pjsip-apps/src/pjsua/pjsua_app_cli.c index 9d7fbaddc8..b7990fdfe4 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_cli.c +++ b/pjsip-apps/src/pjsua/pjsua_app_cli.c @@ -843,6 +843,7 @@ static pj_status_t cmd_add_account(pj_cli_cmd_val *cval) acc_cfg.rtp_cfg = app_config.rtp_cfg; acc_cfg.txt_red_level = app_config.txt_red_level; + acc_cfg.rfc5626_instance_id = app_config.instance_id; app_config_init_video(&acc_cfg); status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL); diff --git a/pjsip-apps/src/pjsua/pjsua_app_common.h b/pjsip-apps/src/pjsua/pjsua_app_common.h index f0b8b2682b..a2a1eadf32 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_common.h +++ b/pjsip-apps/src/pjsua/pjsua_app_common.h @@ -89,6 +89,7 @@ typedef struct pjsua_app_config pj_bool_t no_udp; pj_bool_t use_tls; pj_bool_t keep_call_on_tsx_fail; + pj_str_t instance_id; pjsua_transport_config udp_cfg; pjsua_transport_config rtp_cfg; pj_bool_t enable_rtcp_mux; diff --git a/pjsip-apps/src/pjsua/pjsua_app_config.c b/pjsip-apps/src/pjsua/pjsua_app_config.c index b30153f70a..46383340cc 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_config.c +++ b/pjsip-apps/src/pjsua/pjsua_app_config.c @@ -97,6 +97,8 @@ static void usage(void) PJSIP_SESS_TIMER_DEF_SE); puts (" --timer-min-se=N Session timers minimum expiration period, in secs (def:90)"); puts (" --outb-rid=string Set SIP outbound reg-id (default:1)"); + puts (" --instance-id=URN Set the SIP instance ID of all accounts, e.g."); + puts (" \"\""); puts (" --auto-update-nat=N Enable/disable SIP traversal behind symmetric NAT (def: 1)"); puts (" 0: disabled, 1:enabled with exception, 2: fully enabled"); puts (" --disable-stun Disable STUN for this account"); @@ -409,6 +411,7 @@ static pj_status_t parse_args(int argc, char *argv[], OPT_100REL, OPT_USE_IMS, OPT_REALM, OPT_USERNAME, OPT_PASSWORD, OPT_AKA_OP, OPT_AKA_AMF, OPT_REG_RETRY_INTERVAL, OPT_REG_USE_PROXY, OPT_MWI, OPT_NAMESERVER, OPT_STUN_SRV, OPT_UPNP, OPT_OUTB_RID, + OPT_INSTANCE_ID, OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE, OPT_AUTO_ANSWER, OPT_AUTO_PLAY, OPT_AUTO_PLAY_HANGUP, OPT_AUTO_LOOP, OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_SND_CLOCK_RATE, OPT_STEREO, @@ -596,6 +599,7 @@ static pj_status_t parse_args(int argc, char *argv[], { "timer-se", 1, 0, OPT_TIMER_SE}, { "timer-min-se", 1, 0, OPT_TIMER_MIN_SE}, { "outb-rid", 1, 0, OPT_OUTB_RID}, + { "instance-id", 1, 0, OPT_INSTANCE_ID}, { "video", 0, 0, OPT_VIDEO}, { "text", 0, 0, OPT_TEXT}, { "text-red", 1, 0, OPT_TEXT_RED}, @@ -911,6 +915,10 @@ static pj_status_t parse_args(int argc, char *argv[], cur_acc->rfc5626_reg_id = pj_str(pj_optarg); break; + case OPT_INSTANCE_ID: + cfg->instance_id = pj_str(pj_optarg); + break; + case OPT_USE_IMS: /* Activate IMS settings */ cur_acc->auth_pref.initial_auth = PJ_TRUE; break; @@ -2399,6 +2407,11 @@ int write_settings(pjsua_app_config *config, char *buf, pj_size_t max) if (config->cfg.server_failover) cfg_add(&cfg, max, "--server-failover\n"); + if (config->instance_id.slen) { + cfg_addf(&cfg, max, "--instance-id %.*s\n", + (int)config->instance_id.slen, config->instance_id.ptr); + } + /* Outbound proxy */ for (i=0; icfg.outbound_proxy_cnt; ++i) { cfg_addf(&cfg, max, "--outbound %.*s\n", diff --git a/pjsip-apps/src/pjsua/pjsua_app_legacy.c b/pjsip-apps/src/pjsua/pjsua_app_legacy.c index ed67c95e4e..6e9b4917c9 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_legacy.c +++ b/pjsip-apps/src/pjsua/pjsua_app_legacy.c @@ -1051,6 +1051,7 @@ static void ui_add_account(pjsua_transport_config *rtp_cfg) acc_cfg.rtp_cfg = *rtp_cfg; acc_cfg.txt_red_level = app_config.txt_red_level; + acc_cfg.rfc5626_instance_id = app_config.instance_id; app_config_init_video(&acc_cfg); status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL); diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 4629389d36..b59f926f8d 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -4841,6 +4841,10 @@ typedef struct pjsua_acc_config * value will look like "" * without the doublequote. * + * An instance ID set here is sent in every REGISTER, also without SIP + * outbound. The generated one is sent only with outbound: it is the same + * for all instances on one host, and on iOS ("localhost"). + * * Default: empty */ pj_str_t rfc5626_instance_id; diff --git a/pjsip/include/pjsua2/account.hpp b/pjsip/include/pjsua2/account.hpp index ac5862e090..b81f649db3 100644 --- a/pjsip/include/pjsua2/account.hpp +++ b/pjsip/include/pjsua2/account.hpp @@ -838,6 +838,10 @@ struct AccountNatConfig : public PersistentObject * value will look like "" * without the double-quotes. * + * An instance ID set here is sent in every REGISTER, also without SIP + * outbound. The generated one is sent only with outbound: it is the same + * for all instances on one host, and on iOS ("localhost"). + * * Default: empty */ string sipOutboundInstanceId; diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c index 6aed518db2..8ea3ae717a 100644 --- a/pjsip/src/pjsua-lib/pjsua_acc.c +++ b/pjsip/src/pjsua-lib/pjsua_acc.c @@ -261,6 +261,10 @@ static void init_outbound_setting(pjsua_acc *acc) (int)acc_cfg->rfc5626_instance_id.slen, acc_cfg->rfc5626_instance_id.ptr); acc->rfc5626_instprm.slen = len; + PJ_LOG(4,(THIS_FILE, "Acc %d: instance ID %.*s is sent in every " + "REGISTER", acc->index, + (int)acc_cfg->rfc5626_instance_id.slen, + acc_cfg->rfc5626_instance_id.ptr)); } if (acc_cfg->rfc5626_reg_id.slen == 0) { @@ -279,7 +283,8 @@ static void init_outbound_setting(pjsua_acc *acc) acc->rfc5626_regprm.slen = len; } - acc->rfc5626_status = OUTBOUND_WANTED; + if (acc_cfg->use_rfc5626) + acc->rfc5626_status = OUTBOUND_WANTED; } /* Forget a 439 recorded against a first hop we may no longer be talking to, @@ -532,7 +537,7 @@ static pj_status_t initialize_acc(unsigned acc_id) /* If SIP outbound is enabled, generate instance and reg ID if they are * not specified */ - if (acc_cfg->use_rfc5626) { + if (acc_cfg->use_rfc5626 || acc_cfg->rfc5626_instance_id.slen) { init_outbound_setting(acc); } @@ -2163,6 +2168,7 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc, pjsua_acc_config *acc_cfg = &acc->cfg; const pj_str_t *contact = new_contact ? new_contact : &acc->contact; pj_bool_t need_outbound = PJ_FALSE; + pj_bool_t need_instance; pj_str_t prev_reg_contact = acc->reg_contact; unsigned prev_status = acc->rfc5626_status; const pj_str_t tcp_param = pj_str(";transport=tcp"); @@ -2192,6 +2198,10 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc, need_outbound = PJ_TRUE; done: + /* A configured instance ID is sent without reg-id too, which RFC 5626 + * section 6 allows. The generated one only goes with outbound. + */ + need_instance = need_outbound || acc_cfg->rfc5626_instance_id.slen; { pj_ssize_t len; pj_str_t reg_contact; @@ -2200,8 +2210,8 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc, acc->cfg.contact_params.slen + acc->cfg.reg_contact_params.slen + acc->cfg.reg_contact_uri_params.slen + - (need_outbound? - (acc->rfc5626_instprm.slen + acc->rfc5626_regprm.slen): 0) + + (need_outbound? acc->rfc5626_regprm.slen: 0) + + (need_instance? acc->rfc5626_instprm.slen: 0) + 5; /* allowance */ reg_contact.ptr = (char*) pj_pool_alloc(acc->pool, len); @@ -2276,10 +2286,11 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc, * +sip.instance and reg-id parameters. */ pj_strcat(®_contact, &acc->rfc5626_regprm); - pj_strcat(®_contact, &acc->rfc5626_instprm); } else { acc->rfc5626_status = OUTBOUND_NA; } + if (need_instance) + pj_strcat(®_contact, &acc->rfc5626_instprm); /* Contact params */ pj_strcat(®_contact, &acc->cfg.reg_contact_params); From 36f11fadc97fd04be7c223dc4085f02f3c3ed9b0 Mon Sep 17 00:00:00 2001 From: laconicman Date: Sun, 4 Oct 2026 12:28:29 +0300 Subject: [PATCH 2/6] test(pjsua): cover a configured +sip.instance without reg-id Two SIPp scenarios next to uas-register-outbound-norequire, which keeps asserting that the generated instance ID is dropped with reg-id. - uas-register-instance-norequire: TCP registrar answering 200 without "Require: outbound". The first REGISTER must carry reg-id; the refresh must carry the configured +sip.instance and no reg-id. - uas-register-instance-udp: over UDP, where outbound is never offered, the REGISTER must carry the configured +sip.instance and no reg-id. --- .../uas-register-instance-norequire.py | 13 ++++ .../uas-register-instance-norequire.xml | 69 +++++++++++++++++++ .../scripts-sipp/uas-register-instance-udp.py | 10 +++ .../uas-register-instance-udp.xml | 43 ++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 tests/pjsua/scripts-sipp/uas-register-instance-norequire.py create mode 100644 tests/pjsua/scripts-sipp/uas-register-instance-norequire.xml create mode 100644 tests/pjsua/scripts-sipp/uas-register-instance-udp.py create mode 100644 tests/pjsua/scripts-sipp/uas-register-instance-udp.xml diff --git a/tests/pjsua/scripts-sipp/uas-register-instance-norequire.py b/tests/pjsua/scripts-sipp/uas-register-instance-norequire.py new file mode 100644 index 0000000000..71c8d44e5d --- /dev/null +++ b/tests/pjsua/scripts-sipp/uas-register-instance-norequire.py @@ -0,0 +1,13 @@ +# +# As uas-register-outbound-norequire, with an instance ID configured: the +# refresh keeps +sip.instance. SIPp checks the REGISTERs, see the XML scenario. +# +PJSUA = ['--null-audio ' + '--instance-id=""'] + +# Add the account only once SIPp listens: a start-up REGISTER would be +# refused, and an "rr" racing it could be lost to PJSIP_EBUSY. +PJSUA_EXPECTS = [[0, "", "+a sip:pjsua@127.0.0.1 " + "sip:127.0.0.1:$SIPP_PORT;transport=tcp * pjsua pjsua"]] + +SIPP_TRANSPORT = "t1" diff --git a/tests/pjsua/scripts-sipp/uas-register-instance-norequire.xml b/tests/pjsua/scripts-sipp/uas-register-instance-norequire.xml new file mode 100644 index 0000000000..958b53ece6 --- /dev/null +++ b/tests/pjsua/scripts-sipp/uas-register-instance-norequire.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/pjsua/scripts-sipp/uas-register-instance-udp.py b/tests/pjsua/scripts-sipp/uas-register-instance-udp.py new file mode 100644 index 0000000000..fa6cb0d6d8 --- /dev/null +++ b/tests/pjsua/scripts-sipp/uas-register-instance-udp.py @@ -0,0 +1,10 @@ +# +# pjsua never offers SIP outbound over UDP, so +sip.instance appears here +# only because an instance ID is configured. SIPp checks the REGISTER, see +# the XML scenario. +# +PJSUA = ['--null-audio --id=sip:pjsua@127.0.0.1 --registrar=$SIPP_URI ' + '--realm=* --username=pjsua --password=pjsua ' + '--instance-id=""'] + +PJSUA_EXPECTS = [] diff --git a/tests/pjsua/scripts-sipp/uas-register-instance-udp.xml b/tests/pjsua/scripts-sipp/uas-register-instance-udp.xml new file mode 100644 index 0000000000..a2562ce232 --- /dev/null +++ b/tests/pjsua/scripts-sipp/uas-register-instance-udp.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 808141890918930f0889e1f347d567c04aa0a9ac Mon Sep 17 00:00:00 2001 From: laconicman Date: Sun, 4 Oct 2026 13:01:25 +0300 Subject: [PATCH 3/6] pjsua app: keep an account's own instance ID at startup The startup loop assigned --instance-id to every account, also when the option was not given, wiping a value an application set per account in on_config_init(). Apply it only when given, and only to accounts that have no instance ID of their own. --- pjsip-apps/src/pjsua/pjsua_app.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index 4023071210..952f0ca358 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -2190,7 +2190,11 @@ static pj_status_t app_init(void) app_config_init_video(&app_config.acc_cfg[i]); app_config.acc_cfg[i].txt_red_level = app_config.txt_red_level; - app_config.acc_cfg[i].rfc5626_instance_id = app_config.instance_id; + if (app_config.instance_id.slen && + !app_config.acc_cfg[i].rfc5626_instance_id.slen) + { + app_config.acc_cfg[i].rfc5626_instance_id = app_config.instance_id; + } status = pjsua_acc_add(&app_config.acc_cfg[i], PJ_TRUE, NULL); if (status != PJ_SUCCESS) From 261f5c2ecb3d25da7a90f397397c176a9fa62b1e Mon Sep 17 00:00:00 2001 From: laconicman Date: Thu, 8 Oct 2026 10:24:34 +0300 Subject: [PATCH 4/6] pjsua: document the binding semantics of a configured instance ID Registrars that key bindings on +sip.instance, such as Kamailio and Flexisip, treat contacts with one instance ID as one device and replace the older binding. Say so next to rfc5626_instance_id and sipOutboundInstanceId, and that the ID must be unique to the device and persistent (RFC 5626 section 4.1). Also fix the comment in update_regc_contact()'s outbound branch, which now appends only reg-id. --- pjsip/include/pjsua-lib/pjsua.h | 7 +++++-- pjsip/include/pjsua2/account.hpp | 7 +++++-- pjsip/src/pjsua-lib/pjsua_acc.c | 4 +--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index b59f926f8d..728a797f72 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -4842,8 +4842,11 @@ typedef struct pjsua_acc_config * without the doublequote. * * An instance ID set here is sent in every REGISTER, also without SIP - * outbound. The generated one is sent only with outbound: it is the same - * for all instances on one host, and on iOS ("localhost"). + * outbound. Registrars such as Kamailio and Flexisip then treat contacts + * with the same instance ID as one device and replace the older binding, + * so the ID must be unique to the device and persistent (RFC 5626 + * section 4.1). The generated one is sent only with outbound: it is the + * same for all instances on one host, and on iOS ("localhost"). * * Default: empty */ diff --git a/pjsip/include/pjsua2/account.hpp b/pjsip/include/pjsua2/account.hpp index b81f649db3..1f44a239b7 100644 --- a/pjsip/include/pjsua2/account.hpp +++ b/pjsip/include/pjsua2/account.hpp @@ -839,8 +839,11 @@ struct AccountNatConfig : public PersistentObject * without the double-quotes. * * An instance ID set here is sent in every REGISTER, also without SIP - * outbound. The generated one is sent only with outbound: it is the same - * for all instances on one host, and on iOS ("localhost"). + * outbound. Registrars such as Kamailio and Flexisip then treat contacts + * with the same instance ID as one device and replace the older binding, + * so the ID must be unique to the device and persistent (RFC 5626 + * section 4.1). The generated one is sent only with outbound: it is the + * same for all instances on one host, and on iOS ("localhost"). * * Default: empty */ diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c index 8ea3ae717a..05c996c420 100644 --- a/pjsip/src/pjsua-lib/pjsua_acc.c +++ b/pjsip/src/pjsua-lib/pjsua_acc.c @@ -2282,9 +2282,7 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc, if (need_outbound) { acc->rfc5626_status = OUTBOUND_WANTED; - /* Need to use outbound, append the contact with - * +sip.instance and reg-id parameters. - */ + /* Need to use outbound, append the reg-id parameter */ pj_strcat(®_contact, &acc->rfc5626_regprm); } else { acc->rfc5626_status = OUTBOUND_NA; From 625f9a17e54da16d033e9c55d61dd5d1e9e1f2b9 Mon Sep 17 00:00:00 2001 From: laconicman Date: Thu, 8 Oct 2026 10:24:34 +0300 Subject: [PATCH 5/6] test(pjsua): cover an instance ID with SIP outbound disabled uas-register-instance-nooutbound: TCP, outbound disabled, instance ID configured. The REGISTER must carry +sip.instance, no reg-id and no "outbound" option tag. The pjsua app gets --outb-disable, applied to every account including those added at runtime, since it had no way to turn SIP outbound off. --- pjsip-apps/src/pjsua/pjsua_app.c | 2 + pjsip-apps/src/pjsua/pjsua_app_cli.c | 2 + pjsip-apps/src/pjsua/pjsua_app_common.h | 1 + pjsip-apps/src/pjsua/pjsua_app_config.c | 10 ++++- pjsip-apps/src/pjsua/pjsua_app_legacy.c | 2 + .../uas-register-instance-nooutbound.py | 14 ++++++ .../uas-register-instance-nooutbound.xml | 45 +++++++++++++++++++ 7 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 tests/pjsua/scripts-sipp/uas-register-instance-nooutbound.py create mode 100644 tests/pjsua/scripts-sipp/uas-register-instance-nooutbound.xml diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index 952f0ca358..a09a5530a2 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -2195,6 +2195,8 @@ static pj_status_t app_init(void) { app_config.acc_cfg[i].rfc5626_instance_id = app_config.instance_id; } + if (app_config.outb_disable) + app_config.acc_cfg[i].use_rfc5626 = PJ_FALSE; status = pjsua_acc_add(&app_config.acc_cfg[i], PJ_TRUE, NULL); if (status != PJ_SUCCESS) diff --git a/pjsip-apps/src/pjsua/pjsua_app_cli.c b/pjsip-apps/src/pjsua/pjsua_app_cli.c index b7990fdfe4..ed5e47a4c8 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_cli.c +++ b/pjsip-apps/src/pjsua/pjsua_app_cli.c @@ -844,6 +844,8 @@ static pj_status_t cmd_add_account(pj_cli_cmd_val *cval) acc_cfg.rtp_cfg = app_config.rtp_cfg; acc_cfg.txt_red_level = app_config.txt_red_level; acc_cfg.rfc5626_instance_id = app_config.instance_id; + if (app_config.outb_disable) + acc_cfg.use_rfc5626 = PJ_FALSE; app_config_init_video(&acc_cfg); status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL); diff --git a/pjsip-apps/src/pjsua/pjsua_app_common.h b/pjsip-apps/src/pjsua/pjsua_app_common.h index a2a1eadf32..46bd020d55 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_common.h +++ b/pjsip-apps/src/pjsua/pjsua_app_common.h @@ -90,6 +90,7 @@ typedef struct pjsua_app_config pj_bool_t use_tls; pj_bool_t keep_call_on_tsx_fail; pj_str_t instance_id; + pj_bool_t outb_disable; pjsua_transport_config udp_cfg; pjsua_transport_config rtp_cfg; pj_bool_t enable_rtcp_mux; diff --git a/pjsip-apps/src/pjsua/pjsua_app_config.c b/pjsip-apps/src/pjsua/pjsua_app_config.c index 46383340cc..2a8379c3ea 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_config.c +++ b/pjsip-apps/src/pjsua/pjsua_app_config.c @@ -99,6 +99,7 @@ static void usage(void) puts (" --outb-rid=string Set SIP outbound reg-id (default:1)"); puts (" --instance-id=URN Set the SIP instance ID of all accounts, e.g."); puts (" \"\""); + puts (" --outb-disable Disable SIP outbound (RFC 5626) for all accounts"); puts (" --auto-update-nat=N Enable/disable SIP traversal behind symmetric NAT (def: 1)"); puts (" 0: disabled, 1:enabled with exception, 2: fully enabled"); puts (" --disable-stun Disable STUN for this account"); @@ -411,7 +412,7 @@ static pj_status_t parse_args(int argc, char *argv[], OPT_100REL, OPT_USE_IMS, OPT_REALM, OPT_USERNAME, OPT_PASSWORD, OPT_AKA_OP, OPT_AKA_AMF, OPT_REG_RETRY_INTERVAL, OPT_REG_USE_PROXY, OPT_MWI, OPT_NAMESERVER, OPT_STUN_SRV, OPT_UPNP, OPT_OUTB_RID, - OPT_INSTANCE_ID, + OPT_INSTANCE_ID, OPT_OUTB_DISABLE, OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE, OPT_AUTO_ANSWER, OPT_AUTO_PLAY, OPT_AUTO_PLAY_HANGUP, OPT_AUTO_LOOP, OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_SND_CLOCK_RATE, OPT_STEREO, @@ -600,6 +601,7 @@ static pj_status_t parse_args(int argc, char *argv[], { "timer-min-se", 1, 0, OPT_TIMER_MIN_SE}, { "outb-rid", 1, 0, OPT_OUTB_RID}, { "instance-id", 1, 0, OPT_INSTANCE_ID}, + { "outb-disable", 0, 0, OPT_OUTB_DISABLE}, { "video", 0, 0, OPT_VIDEO}, { "text", 0, 0, OPT_TEXT}, { "text-red", 1, 0, OPT_TEXT_RED}, @@ -919,6 +921,10 @@ static pj_status_t parse_args(int argc, char *argv[], cfg->instance_id = pj_str(pj_optarg); break; + case OPT_OUTB_DISABLE: + cfg->outb_disable = PJ_TRUE; + break; + case OPT_USE_IMS: /* Activate IMS settings */ cur_acc->auth_pref.initial_auth = PJ_TRUE; break; @@ -2411,6 +2417,8 @@ int write_settings(pjsua_app_config *config, char *buf, pj_size_t max) cfg_addf(&cfg, max, "--instance-id %.*s\n", (int)config->instance_id.slen, config->instance_id.ptr); } + if (config->outb_disable) + cfg_add(&cfg, max, "--outb-disable\n"); /* Outbound proxy */ for (i=0; icfg.outbound_proxy_cnt; ++i) { diff --git a/pjsip-apps/src/pjsua/pjsua_app_legacy.c b/pjsip-apps/src/pjsua/pjsua_app_legacy.c index 6e9b4917c9..4a1399244e 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_legacy.c +++ b/pjsip-apps/src/pjsua/pjsua_app_legacy.c @@ -1052,6 +1052,8 @@ static void ui_add_account(pjsua_transport_config *rtp_cfg) acc_cfg.rtp_cfg = *rtp_cfg; acc_cfg.txt_red_level = app_config.txt_red_level; acc_cfg.rfc5626_instance_id = app_config.instance_id; + if (app_config.outb_disable) + acc_cfg.use_rfc5626 = PJ_FALSE; app_config_init_video(&acc_cfg); status = pjsua_acc_add(&acc_cfg, PJ_TRUE, NULL); diff --git a/tests/pjsua/scripts-sipp/uas-register-instance-nooutbound.py b/tests/pjsua/scripts-sipp/uas-register-instance-nooutbound.py new file mode 100644 index 0000000000..198a037a19 --- /dev/null +++ b/tests/pjsua/scripts-sipp/uas-register-instance-nooutbound.py @@ -0,0 +1,14 @@ +# +# An instance ID with SIP outbound disabled, over TCP: the REGISTER carries +# +sip.instance without reg-id and does not offer outbound. SIPp checks the +# REGISTER, see the XML scenario. +# +PJSUA = ['--null-audio --outb-disable ' + '--instance-id=""'] + +# Add the account only once SIPp listens: a start-up REGISTER would be +# refused, and an "rr" racing it could be lost to PJSIP_EBUSY. +PJSUA_EXPECTS = [[0, "", "+a sip:pjsua@127.0.0.1 " + "sip:127.0.0.1:$SIPP_PORT;transport=tcp * pjsua pjsua"]] + +SIPP_TRANSPORT = "t1" diff --git a/tests/pjsua/scripts-sipp/uas-register-instance-nooutbound.xml b/tests/pjsua/scripts-sipp/uas-register-instance-nooutbound.xml new file mode 100644 index 0000000000..7887d76dc2 --- /dev/null +++ b/tests/pjsua/scripts-sipp/uas-register-instance-nooutbound.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 40e1a1a888462d5703255389acf45faa21347a18 Mon Sep 17 00:00:00 2001 From: laconicman Date: Thu, 8 Oct 2026 20:22:03 +0300 Subject: [PATCH 6/6] pjsua app: update the Teluu copyright year in the modified files --- pjsip-apps/src/pjsua/pjsua_app.c | 2 +- pjsip-apps/src/pjsua/pjsua_app_cli.c | 2 +- pjsip-apps/src/pjsua/pjsua_app_common.h | 2 +- pjsip-apps/src/pjsua/pjsua_app_config.c | 2 +- pjsip-apps/src/pjsua/pjsua_app_legacy.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index a09a5530a2..de2178d3cc 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2008-2026 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono * * This program is free software; you can redistribute it and/or modify diff --git a/pjsip-apps/src/pjsua/pjsua_app_cli.c b/pjsip-apps/src/pjsua/pjsua_app_cli.c index ed5e47a4c8..c952cffe2c 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_cli.c +++ b/pjsip-apps/src/pjsua/pjsua_app_cli.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2008-2026 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono * * This program is free software; you can redistribute it and/or modify diff --git a/pjsip-apps/src/pjsua/pjsua_app_common.h b/pjsip-apps/src/pjsua/pjsua_app_common.h index 46bd020d55..145dd952af 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_common.h +++ b/pjsip-apps/src/pjsua/pjsua_app_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2008-2026 Teluu Inc. (http://www.teluu.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/pjsip-apps/src/pjsua/pjsua_app_config.c b/pjsip-apps/src/pjsua/pjsua_app_config.c index 2a8379c3ea..917f155cbd 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_config.c +++ b/pjsip-apps/src/pjsua/pjsua_app_config.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2008-2026 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono * * This program is free software; you can redistribute it and/or modify diff --git a/pjsip-apps/src/pjsua/pjsua_app_legacy.c b/pjsip-apps/src/pjsua/pjsua_app_legacy.c index 4a1399244e..ab2a9efe30 100644 --- a/pjsip-apps/src/pjsua/pjsua_app_legacy.c +++ b/pjsip-apps/src/pjsua/pjsua_app_legacy.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2008-2026 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono * * This program is free software; you can redistribute it and/or modify