Commit 8afbd78139 for asterisk.org

commit 8afbd78139be62509468c1cda5573bdf595f5481
Author: Mike Bradeen <mbradeen@sangoma.com>
Date:   Wed Apr 8 11:03:04 2026 -0600

    res_pjsip_outbound_registration: only update the Expires header if the value has changed

    The PJSIP outbound registration API has undocumented behavior when reconfiguring
    the outbound registration if the expires value being set is the same as what was
    previously set.

    In this case PJSIP will remove the Expires header entirely from subsequent
    outbound REGISTER requests. To eliminate this as an issue we now check the current
    expires value against the configured expires value and only apply it if it differs.

    This ensures that outbound REGISTER requests always contain an Expires header.

    Resolves: #1859

diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index 9c66fa7360..21b4640d0c 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -2105,6 +2105,7 @@ static int sip_outbound_registration_perform(void *data)
 	struct sip_outbound_registration *registration = ao2_bump(state->registration);
 	size_t i;
 	int max_delay;
+	pjsip_regc_info info;

 	/* Just in case the client state is being reused for this registration, free the auth information */
 	ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);
@@ -2132,7 +2133,14 @@ static int sip_outbound_registration_perform(void *data)
 	state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
 	max_delay = registration->max_random_initial_delay;

-	pjsip_regc_update_expires(state->client_state->client, registration->expiration);
+	/*
+	 * pjsip_regc_update_expires will remove the Expires header from the REGISTER request if the
+	 * expiration interval is re-set to the same value as the current interval.  We want to avoid
+	 * this so we only call it if the interval has changed.
+	 */
+	if (pjsip_regc_get_info(state->client_state->client, &info) == PJ_SUCCESS && info.interval != (unsigned) registration->expiration) {
+		pjsip_regc_update_expires(state->client_state->client, registration->expiration);
+	}

 	/* n mod 0 is undefined, so don't let that happen */
 	schedule_registration(state->client_state, (max_delay ? ast_random() % max_delay : 0) + 1);