Repository navigation
pjsua: send a configured +sip.instance without SIP outbound too - #25
laconicman wants to merge 5 commits into
Conversation
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.
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.
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.
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.
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.
| if (config->instance_id.slen) { | ||
| cfg_addf(&cfg, max, "--instance-id %.*s\n", | ||
| (int)config->instance_id.slen, config->instance_id.ptr); | ||
| } |
There was a problem hiding this comment.
🟡 Account-specific instance IDs lost on reload
When an account overrides rfc5626_instance_id, write_settings saves only config->instance_id. Reloading assigns the global ID instead, so the account registers under a different device identity.
Learn more
An application can set a separate instance ID on an account through on_config_init; the startup loop preserves that override. The settings writer serializes account options before global options, but write_account_settings never writes the account's instance ID. Reloading therefore leaves the override empty, and the global ID fills it during account creation.
Example: A callback sets account A's ID to <urn:uuid:aaaa> and the global ID to <urn:uuid:bbbb>. Saving then reloading retains only bbbb, so A registers as bbbb, not aaaa.
Recommended fix: Serialize per-account instance IDs where account options are written, and parse them as account-scoped values. Preserve the global fallback separately so saving and reloading an overridden account produces the same registration identity.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Declined. on_config_init() runs in app_init() on every start, after the settings file is read (pjsua_app.c, just before the accounts are added), so a per-account instance ID it sets is applied again each time; saving and reloading cannot lose it. The settings file has no per-account instance-ID option to write it to, and adding one would be a new feature of its own; values that only code sets are not written today either (rfc5626_reg_id set through --outb-rid is not written back, for example).
|
Landed upstream as |
Implements the proposal in pjsip#5292: an instance ID the application configured is sent in every REGISTER, also without SIP outbound.
pjsua appends
+sip.instanceto the registration Contact only together withreg-id, while SIP outbound is wanted, and drops both when the registrar does not confirm outbound (the 2010 design, which pjsip#5281 made take effect on the next refresh). RFC 5626 §6 allows an instance ID withoutreg-id, and registrars such as Kamailio and Flexisip key a binding on it alone, as does IMS (3GPP TS 24.229 §5.1.1.2.1).update_regc_contact(): ifrfc5626_instance_idis set, appendsrfc5626_instprmwhether or not outbound is wanted, andrfc5626_regprmonly while it is. That covers UDP,use_rfc5626disabled, a 2xx withoutRequire: outbound, and the retry after a 439. The generated instance ID is sent as before, only with outbound.init_outbound_setting()also runs for an account that sets an instance ID withuse_rfc5626disabled, and marks outbound as wanted only ifuse_rfc5626is set, so the status of such an account never says outbound is wanted (defence in depth:pjsua_regc_init()resets it anyway). It logs a configured instance ID once (Acc N: instance ID … is sent in every REGISTER): when that line is missing, the application's setting did not arrive.rfc5626_instance_id(pjsua2:sipOutboundInstanceId) is the opt-in; with it empty nothing changes. The docs of both now say that a configured ID goes into every REGISTER, that Kamailio and Flexisip treat contacts with one instance ID as one device and replace the older binding, so the ID must be unique to the device and persistent (RFC 5626 §4.1), and why the generated one stays outbound-only.--instance-id=URN, applied to every account that has no instance ID of its own, including one added at runtime with+a, and--outb-disable, which turns SIP outbound off for every account (the app had no way to). Both reach+aaccounts, which is how the TCP scenarios avoid a start-up REGISTER racing SIPp, asuas-register-outbound-norequiredoes.Why only a configured instance ID
An earlier version added an account switch that also sent the generated instance ID without outbound. The generated value is a 32-bit hash of the host name, so it is the same for every pjsua instance on one host, and on every iPhone (
gethostname()returnslocalhost). Sent everywhere, two processes or two phones on one AOR would advertise one instance ID, and a registrar that keys bindings on it would let one replace the other. Only an ID the application chose is now sent beyond outbound.The default itself is left alone. Changing how it is generated would change the instance ID every existing deployment sends, so registrars would see a new device after an upgrade. pjlib has no persistent store to keep a random one in, and the stable identifiers on phones are not reachable from C, so the application has to supply the ID.
Contact on the wire
Require: outbound: first / refresh;reg-id=1;+sip.instance=<generated>/ neither;reg-id=1;+sip.instance=…/;+sip.instance=…Require: outboundon the first 200 only: REGISTER after the 200 without it;+sip.instance=…Supported: path;+sip.instance=…,Supported: path;+sip.instance=…use_rfc5626disabledSupported: outbound;+sip.instance=…, noreg-id, noSupported: outboundVerification
uas-register-instance-norequire,uas-register-instance-udpuas-register-instance-nooutbound--instance-idremoved, the third with--outb-disableremoved (scratch copies)SIPp returned error 1: At least one call faileduas-register-instance-nooutboundagainst a build without theinit_outbound_setting()guardpjsua_regc_init()starts withdestroy_regc(), which clearsacc->contactand resets the status, soupdate_regc_contact()always runs beforeSupportedis built. The scenario covers that wire row; the guard is defence in depthuas-register-outbound-norequire(generated ID still dropped withreg-id)uas-norefersub,uas-authmakeRun locally on macOS with SIPp 3.7.7 (
/usr/bin/python3 run.py -e <pjsua> mod_sipp.py scripts-sipp/<scenario>.xml).Not verified here: Linux and Windows, real registrars.
This touches
update_regc_contact(), as pjsip#5311 does; the two merge cleanly in either order.Patch size: +41 code, +15 comment lines in source (contrib loc), plus three SIPp scenarios.