From 1bb45e28f8f596dfc7f5b336aa1791ca9c38e348 Mon Sep 17 00:00:00 2001
From: Wenpeng Song <wenpeng.song@iopsys.eu>
Date: Mon, 3 Mar 2025 16:24:56 +0000
Subject: [PATCH] Fix issues in registration retry mechanism, REF 15851

* 408 response received from the server should be handled the same as other codes like 503
* Introduce response code 444 from pjsip while no response been received to differentiate
  it with 408 which is from the server
* there should have no retry during recovery flow if no retry-after, retry should only
  happened during the first round if no retry-after.
---
 res/res_pjsip_outbound_registration.c         | 12 +++---
 ...n-444-while-register-request-timeout.patch | 43 +++++++++++++++++++
 2 files changed, 49 insertions(+), 6 deletions(-)
 create mode 100644 third-party/pjproject/patches/0020-return-444-while-register-request-timeout.patch

diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index 44df5800f3..7fb72de4df 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -1833,7 +1833,7 @@ static int handle_registration_response(void *data)
 		}
 	}
 
-	if (response->code == 408 || response->code == 503 || response->code == 500 || response->code == 504 || response->code == 600) {
+	if (response->code == 408 || response->code == 444 || response->code == 503 || response->code == 500 || response->code == 504 || response->code == 600) {
 		int retry = 1;
 		int waiting_time = registration->retry_after;
 
@@ -1862,8 +1862,8 @@ static int handle_registration_response(void *data)
 
 		if (response->retry_after){
 			waiting_time = response->retry_after;
-		} else if (response->code == 408 || client_state->attempts >= 2) {
-			/* failover when 408, or received twice with other response */
+		} else if (response->code == 444 || client_state->attempts >= 2 || client_state->waiting_time_upper_bound) {
+			/* failover directly when not received any response(444 from pjsip), or received twice with other response, or under recovery-flow(second round) */
 			client_state->attempts = 0;
 			retry = sip_registration_failover(response);
 		}
@@ -1873,7 +1873,7 @@ static int handle_registration_response(void *data)
 			update_client_state_status(client_state, SIP_REGISTRATION_REJECTED_TEMPORARY);
 			sip_outbound_registration_send_ubus_event("UNREGISTERED", response->expiration, client_uri);
 
-			if (response->code == 408 || client_state->attempts == 0){
+			if (response->code == 444 || client_state->attempts == 0){
 				ast_debug(1, "%s: Registration re-try to the next address immediately.\n", client_state->registration_name);
 				registration_resend(response);
 			} else {
@@ -2084,7 +2084,7 @@ static int handle_registration_response(void *data)
 		/* If we have been instructed to retry after a period of time, schedule it as such */
 		schedule_retry(response, response->retry_after, server_uri, client_uri, client_num);
 	} else if (client_state->failover_max_retries &&
-			(response->code == 408 || response->code == 503 || response->code == 500)) {
+			(response->code == 408 || response->code == 444 || response->code == 503 || response->code == 500)) {
 		if (client_state->failover_max_retries >= 0 &&
 				client_state->failover_retries >= client_state->failover_max_retries) {
 			update_client_state_status(client_state, SIP_REGISTRATION_REJECTED_PERMANENT);
@@ -2132,7 +2132,7 @@ static int handle_registration_response(void *data)
 			client_state->retries++;
 			schedule_retry(response, client_state->retry_interval, server_uri, client_uri, client_num);
 		}
-	} else if (response->code == 408 || response->code == 503 || response->code == 500 || response->code == 504 || response->code == 600) {
+	} else if (response->code == 408 || response->code == 444 || response->code == 503 || response->code == 500 || response->code == 504 || response->code == 600) {
 		int waiting_time = registration->retry_after;
 
 		// All addresses had been tried, now try transport2 if possible
diff --git a/third-party/pjproject/patches/0020-return-444-while-register-request-timeout.patch b/third-party/pjproject/patches/0020-return-444-while-register-request-timeout.patch
new file mode 100644
index 0000000000..bd1f918824
--- /dev/null
+++ b/third-party/pjproject/patches/0020-return-444-while-register-request-timeout.patch
@@ -0,0 +1,43 @@
+From 42a3189210f3790acdd128845403b96c5d03d090 Mon Sep 17 00:00:00 2001
+From: "wenpeng.song" <wenpeng.song@iopsys.eu>
+Date: Mon, 3 Mar 2025 12:48:19 +0100
+Subject: [PATCH] return 444 while register request timeout
+
+---
+ pjsip/src/pjsip/sip_msg.c         | 2 ++
+ pjsip/src/pjsip/sip_transaction.c | 6 +++++-
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/pjsip/src/pjsip/sip_msg.c b/pjsip/src/pjsip/sip_msg.c
+index c375ca9b1..7a67783c4 100644
+--- a/pjsip/src/pjsip/sip_msg.c
++++ b/pjsip/src/pjsip/sip_msg.c
+@@ -243,6 +243,8 @@ static int init_status_phrase()
+     pj_strset2( &status_phrase[702], "Unable to resolve destination server");
+     pj_strset2( &status_phrase[703], "Error sending message to destination server");
+ 
++    pj_strset2( &status_phrase[444], "No response received");
++
+     return 1;
+ }
+ 
+diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
+index cf9795dbb..7d3ebe258 100644
+--- a/pjsip/src/pjsip/sip_transaction.c
++++ b/pjsip/src/pjsip/sip_transaction.c
+@@ -2630,7 +2630,11 @@ static pj_status_t tsx_on_state_calling( pjsip_transaction *tsx,
+         tsx->transport_flag &= ~(TSX_HAS_PENDING_RESCHED);
+ 
+         /* Set status code */
+-        tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL);
++        if(tsx->method.id == PJSIP_REGISTER_METHOD){
++            tsx_set_status_code(tsx, 444, NULL);
++        } else {
++            tsx_set_status_code(tsx, PJSIP_SC_TSX_TIMEOUT, NULL);
++        }
+ 
+         /* Inform TU. */
+         tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED,
+-- 
+2.43.0
+
-- 
GitLab