Skip to content

refactor(pjsua): commit the new Contact in update_regc_contact() - #5311

Merged
nanangizz merged 1 commit into
pjsip:masterfrom
laconicman:refactor/regc-contact-rollback
Oct 8, 2026
Merged

nanangizz merged 1 commit into
pjsip:masterfrom
laconicman:refactor/regc-contact-rollback

Conversation

@laconicman

@laconicman laconicman commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up to #5281, as agreed in its review.

  • update_regc_contact() takes the candidate Contact and commits it to acc->contact only after the regc accepts it, so the rollback is in one place; acc_check_nat_addr() and auto_rereg_timer_cb() no longer save and restore acc->contact (review).
  • So acc_check_nat_addr() no longer captures prev_contact after destroy_regc() has cleared it in UNREGISTER mode (review).
  • The dead else that aliased reg_contact to contact is removed (len always exceeds acc->contact.slen), together with the OUTBOUND_WANTED store it left dead. Its body is dedented, so the diff reads best with whitespace hidden.

No behaviour change intended.

Verified on macOS arm64 (Apple clang 21), each build against the previous one (unpatched master, then the first review round):

Check Result
make -j3 no new warnings
pjsip-test pjsua_acc_test pass
SIPp uas-register-outbound-norequire (tests/pjsua) pass
Scripted TCP registrar: 200 without Require: outbound, ACTIVE -> NA, 439 failover, initial 439, NAT rewrite, NAT rewrite after 401 REGISTERs identical

Not run here: Linux and Windows builds, and the full test suites.

@nanangizz
nanangizz requested a review from sauwming October 7, 2026 04:41
Comment thread pjsip/src/pjsua-lib/pjsua_acc.c Outdated
* With push, also load it into the regc; pass PJ_FALSE where the regc takes
* it from pjsip_regc_init() or regc_tsx_cb()'s param->contact instead.
* Returns PJ_FALSE if the regc refused it, leaving reg_contact as it was.
* Returns PJ_FALSE if the regc refused it, leaving the account as it was;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"leaving the account as it was" only holds with push=PJ_TRUE. With push=PJ_FALSE the function always returns PJ_TRUE and commits acc->contact/acc->reg_contact before the regc has seen them, e.g. in pjsua_regc_init() where pjsip_regc_init() may still reject reg_contact afterwards, or in the ALWAYS_UPDATE path where regc_tsx_cb hands param->contact over later. Should the comment say the refusal guarantee only applies to push?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes: only a push can be refused. The comment now says so, and that without push the Contact is committed before the regc has seen it.

Comment thread pjsip/src/pjsua-lib/pjsua_acc.c Outdated
@@ -2294,14 +2299,6 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc, pj_bool_t push)
acc->index,
(int)acc->reg_contact.slen,
acc->reg_contact.ptr));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Contact for acc %d updated" is logged before the regc push below, which can still refuse and roll back. On a refusal the log shows the new Contact followed by "Failed updating registration Contact", while the account keeps the old one. Maybe move the log after the push succeeds?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved after the push, so a refusal now logs only "Failed updating registration Contact".

pj_strdup_with_null(acc->pool, &acc->contact, &tmp_contact);
if (!update_regc_contact(acc, PJ_TRUE))
acc->contact = prev_contact;
update_regc_contact(acc, &tmp_contact, PJ_TRUE);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return value is ignored here, so if the regc refuses the new Contact we go on to re-register with the old one and don't retry. Same at update_rfc5626_status() (line 3023). The old code behaved the same way, so this isn't a regression. Now that the helper reports refusal explicitly, is ignoring it intended here, or should this site e.g. schedule_reregistration() like the reinit failure branch above?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intended; there is now a one-line comment at the call. set_contact() refuses only a Contact that does not parse (PJSIP_EINVALIDURI), so the result depends on the input alone: rescheduling would just repeat the refusal and never send a REGISTER, while carrying on re-registers with the Contact the regc kept (it validates before touching its list), under the same retry rules as any other REGISTER. In update_rfc5626_status() the candidate is the already accepted Contact minus reg-id and +sip.instance, so a refusal is not expected there.

}
}
if (new_contact)
pj_strdup_with_null(acc->pool, &acc->contact, new_contact);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: if a future caller passes &acc->contact as new_contact (the doc's "NULL: acc->contact" sort of invites it), pj_strdup_with_null() copies onto itself: dst->ptr is set to a fresh buffer before copying from src->ptr, which is now that same buffer, so the Contact becomes uninitialised bytes. No current caller does this. Maybe pj_assert(new_contact != &acc->contact), or treat it like NULL?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Treated like NULL now. An assert would compile out in release builds and still copy garbage.

Comment thread pjsip/src/pjsua-lib/pjsua_acc.c Outdated
@@ -2191,20 +2196,20 @@ static pj_bool_t update_regc_contact(pjsua_acc *acc, pj_bool_t push)
pj_str_t reg_contact;

acc->rfc5626_status = OUTBOUND_WANTED;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: with the else branch gone, this store is dead. The status is always overwritten below (WANTED at 2274 or NA at 2282). Could drop it, and the bare { } block it leaves, so the status is set once from need_outbound.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped, together with the bare block. Its body is dedented, so the diff reads best with whitespace hidden.

Comment thread pjsip/src/pjsua-lib/pjsua_acc.c Outdated
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_str_t prev_contact = acc->reg_contact;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: prev_contact holds the previous acc->reg_contact, not acc->contact. With contact and new_contact also in scope now, prev_reg_contact would make it clearer which one the refusal path restores.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed.

Pass the candidate Contact into update_regc_contact() and commit it to
acc->contact only after the regc has accepted it, so the rollback lives
in one place instead of in acc_check_nat_addr() and
auto_rereg_timer_cb(). This also drops acc_check_nat_addr()'s
prev_contact, which in UNREGISTER mode was captured after
destroy_regc() had already cleared acc->contact.

Remove the else branch that aliased reg_contact to contact: len always
exceeds acc->contact.slen, so it never ran. The OUTBOUND_WANTED store
it left dead goes too.

Log the new Contact only once the regc has accepted it, and treat
&acc->contact as new_contact like NULL.

No change on the wire.
@laconicman
laconicman force-pushed the refactor/regc-contact-rollback branch from e18e575 to 1fe52ea Compare October 8, 2026 08:17
@nanangizz
nanangizz merged commit 98f3145 into pjsip:master Oct 8, 2026
67 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants