Skip to content

Comments

b2b_logic bridge max_duration flag fix#3800

Open
ErhanOnur wants to merge 1 commit intoOpenSIPS:masterfrom
ErhanOnur:master
Open

b2b_logic bridge max_duration flag fix#3800
ErhanOnur wants to merge 1 commit intoOpenSIPS:masterfrom
ErhanOnur:master

Conversation

@ErhanOnur
Copy link

Summary
The fix for max_duration flag of the b2b_bridge function in the b2b_logic module

Details
The max_duration flag of the b2b_bridge function in the b2b_logic module was not working as expected because the default max_duration setting was overriding the flag value. This issue has been resolved by introducing a new module parameter.

Solution
When b2b_bridge is triggered , the lifetime of the call was set as 5, because max_duration flag is 5:
Oct 2 07:10:35 [19] ERROR:b2b_logic:b2b_script_bridge: params->lifetime: 5 (max_duration)

When the 200 OK reply of initial INTIVE is arrived, the lifetime is updated again with default lifetime value:
Oct 2 07:10:35 [19] ERROR:b2b_logic:b2b_add_dlginfo: max_duration : 43200 tuple->lifetime 43201

The second update is prevented with the new module parameter.

Compatibility
If the new module parameter is set to false, the code behaves as before. The default value is false.

Closing issues
N/A

@razvancrainea
Copy link
Member

Thanks for your contribution! This looks good, although I'd rather use a flag for the b2b_bridge command(s) that can tune this behavior more granular. Can you adapt this patch to accomodate this behavior?

@NormB
Copy link
Member

NormB commented Feb 13, 2026

Took a look at this since the fix has been idle for a couple weeks. Razvan's ask (per-command flag instead of global modparam) is straightforward to implement using the existing bridge_flags mechanism. Here's a tested approach in case it's helpful.

Design: Instead of adding a new script-visible flag name (which would conflict with internal flags at bits 5-9 due to positional mapping in fixup_named_flags), use an internal flag at bit 10 that gets set automatically when max_duration=N is specified on b2b_bridge(). If you explicitly set a per-bridge duration, it should be respected — no separate boolean flag needed.

Changes (4 files, +30/-8):

diff --git a/modules/b2b_logic/b2b_logic.h b/modules/b2b_logic/b2b_logic.h
index 6db886651..bd5237510 100644
--- a/modules/b2b_logic/b2b_logic.h
+++ b/modules/b2b_logic/b2b_logic.h
@@ -81,6 +81,12 @@ enum b2b_tuple_state {
 #define B2BL_BR_FLAG_PENDING_SDP                   (1<<8)
 #define B2BL_BR_FLAG_BR_MSG_LATE_BYE               (1<<9)
 
+/* Internal flag: set when a per-bridge lifetime was explicitly provided
+ * via the max_duration flag on b2b_bridge(). Prevents b2b_add_dlginfo()
+ * from overwriting the per-bridge lifetime with the global max_duration
+ * modparam value when the bridged call is confirmed (200 OK). */
+#define B2BL_BR_FLAG_EXPLICIT_LIFETIME             (1<<10)
+
 /* reply flags */
 #define B2BL_RPL_FLAG_PASS_CONTACT                 (1<<0)
 
diff --git a/modules/b2b_logic/bridging.c b/modules/b2b_logic/bridging.c
index 30d37865a..f2c88d87f 100644
--- a/modules/b2b_logic/bridging.c
+++ b/modules/b2b_logic/bridging.c
@@ -1643,8 +1643,11 @@ int b2bl_bridge(struct sip_msg* msg, b2bl_tuple_t* tuple,
 
 	if (lifetime)
 	{
-		tuple->lifetime = lifetime + get_ticks();
-		LM_DBG("Lifetime defined = [%d]\n", tuple->lifetime);
+		unsigned int ticks = get_ticks();
+		tuple->lifetime = lifetime + ticks;
+		tuple->bridge_flags |= B2BL_BR_FLAG_EXPLICIT_LIFETIME;
+		LM_DBG("Per-bridge lifetime set = [%u] (duration=%d, ticks=%u)\n",
+			tuple->lifetime, lifetime, ticks);
 	}
 	else
 		tuple->lifetime = -1;
@@ -1989,6 +1992,9 @@ int b2bl_bridge_2calls(str* key1, str* key2)
 	}
 	e1->sdp_type = B2BL_SDP_LATE;
 	e1->state = 0;
+	/* Clear any per-bridge lifetime from a previous b2b_bridge() call;
+	 * this bridge path always uses the global max_duration */
+	tuple->bridge_flags &= ~B2BL_BR_FLAG_EXPLICIT_LIFETIME;
 	tuple->state = B2B_BRIDGING_STATE;
 	if(max_duration)
 		tuple->lifetime = get_ticks() + max_duration;
@@ -2375,6 +2379,9 @@ int b2bl_bridge_msg(struct sip_msg* msg, str* key, int entity_no,
 	}
 	bridging_entity->sdp_type = B2BL_SDP_NORMAL;
 	bridging_entity->state = 0;
+	/* Clear any per-bridge lifetime from a previous b2b_bridge() call;
+	 * this bridge path always uses the global max_duration */
+	tuple->bridge_flags &= ~B2BL_BR_FLAG_EXPLICIT_LIFETIME;
 	if(max_duration)
 		tuple->lifetime = get_ticks() + max_duration;
 	else
diff --git a/modules/b2b_logic/doc/b2b_logic_admin.xml b/modules/b2b_logic/doc/b2b_logic_admin.xml
index 75bec56c5..9456faa3d 100644
--- a/modules/b2b_logic/doc/b2b_logic_admin.xml
+++ b/modules/b2b_logic/doc/b2b_logic_admin.xml
@@ -309,7 +309,10 @@ modparam("b2b_logic", "update_period", 60)
 	<section id="param_max_duration" xreflabel="max_duration">
 		<title><varname>max_duration</varname> (int)</title>
 		<para>
-			The maximum duration of a call.
+			The maximum duration of a call. This value is applied as the default
+			lifetime for all B2B sessions. It can be overridden on a per-bridge
+			basis by using the <emphasis>max_duration</emphasis> flag of the
+			<xref linkend="func_b2b_bridge"/> function.
 		</para>
 		<para>
 		<emphasis>Default value is <quote>12 * 3600 (12 hours)</quote>.</emphasis>
@@ -744,7 +747,9 @@ b2b_client_new("client1", "sip:alice@opensips.org");
 					<listitem><para>
 					<emphasis>max_duration=[nn]</emphasis> - Maximum duration of the B2B
 					session. If the lifetime expires, the B2BUA will send BYE messages to both
-					ends and delete the record. Example: "max_duration=300".
+					ends and delete the record. This per-bridge value takes precedence over the
+					global <xref linkend="param_max_duration"/> module parameter.
+					Example: "max_duration=300".
 					</para></listitem>
 					<listitem><para>
 					<emphasis>notify</emphasis> - Enable rfc3515 NOTIFY to inform the agent
diff --git a/modules/b2b_logic/logic.c b/modules/b2b_logic/logic.c
index 2642b2f9f..16fb74681 100644
--- a/modules/b2b_logic/logic.c
+++ b/modules/b2b_logic/logic.c
@@ -161,10 +161,19 @@ int b2b_add_dlginfo(str* key, str* entity_key, int src, b2b_dlginfo_t* dlginfo,
 		return -1;
 	}
 	/* a connected call */
-	if(max_duration)
-		tuple->lifetime = get_ticks() + max_duration;
-	else
-		tuple->lifetime = 0;
+	if (tuple->bridge_flags & B2BL_BR_FLAG_EXPLICIT_LIFETIME) {
+		/* A per-bridge lifetime was set via the max_duration flag on
+		 * b2b_bridge(); preserve it instead of overwriting with the
+		 * global max_duration modparam */
+		LM_DBG("Preserving per-bridge lifetime [%u] for tuple [%.*s]\n",
+			tuple->lifetime, tuple->key ? tuple->key->len : 0,
+			tuple->key ? tuple->key->s : "");
+	} else {
+		if(max_duration)
+			tuple->lifetime = get_ticks() + max_duration;
+		else
+			tuple->lifetime = 0;
+	}
 	entity = b2bl_search_entity(tuple, entity_key, src, &ent_head);
 	if(entity == NULL)
 	{

Tested on master (4.0.0-dev, dbfac4e) with modparam("b2b_logic", "max_duration", 60) and b2b_bridge("peer", "new_target", , "max_duration=10"):

DBG:b2b_logic:b2bl_bridge: Per-bridge lifetime set = [28] (duration=10, ticks=18)
DBG:b2b_logic:b2b_add_dlginfo: Preserving per-bridge lifetime [28] for tuple [149.0]

Lifetime stays at 28 (10+18), not overwritten to 78 (60+18). Initial bridge without the flag correctly uses global max_duration.

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