From: Victor Seva <vseva@sipwise.com>
Date: Thu, 17 Sep 2020 14:48:49 +0200
Subject: lcr: stopper_mode parameter

if set to something different from 0 it will get all matches_gws
but will sort them first before stopping
---
 src/modules/lcr/lcr_mod.c | 42 +++++++++++++++++++++++++++++++++++++++---
 src/modules/lcr/lcr_mod.h |  1 +
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/src/modules/lcr/lcr_mod.c b/src/modules/lcr/lcr_mod.c
index 2e33df0..fa5cac5 100644
--- a/src/modules/lcr/lcr_mod.c
+++ b/src/modules/lcr/lcr_mod.c
@@ -205,6 +205,10 @@ static unsigned int priority_ordering_param = 0;
 /* mtree tree name */
 str mtree_param = {"lcr", 3};
 
+/* stopper mode */
+#define DEF_LCR_STOPPER_MODE 0
+unsigned int stopper_mode_param = DEF_LCR_STOPPER_MODE;
+
 /*
  * Other module types and variables
  */
@@ -357,6 +361,7 @@ static param_export_t params[] = {
     {"ping_valid_reply_codes",   PARAM_STR, &ping_valid_reply_codes_param},
     {"ping_from",                PARAM_STR, &ping_from_param},
     {"ping_socket",              PARAM_STR, &ping_socket_param},
+    {"stopper_mode",             PARAM_INT, &stopper_mode_param},
     {0, 0, 0}
 };
 
@@ -2227,6 +2232,8 @@ int load_gws_dummy(int lcr_id, str *ruri_user, str *from_uri, str *request_uri,
 				matched_gws[gw_index].priority = t->priority;
 				matched_gws[gw_index].weight = t->weight * (kam_rand() >> 8);
 				matched_gws[gw_index].duplicate = 0;
+				if(stopper_mode_param != 0)
+					matched_gws[gw_index].stopper = rule->stopper;
 				LM_DBG("added matched_gws[%d]=[%u, %u, %u, %u]\n", gw_index,
 						t->gw_index, pl->prefix_len, t->priority,
 						matched_gws[gw_index].weight);
@@ -2234,8 +2241,10 @@ int load_gws_dummy(int lcr_id, str *ruri_user, str *from_uri, str *request_uri,
 			skip_gw:
 				t = t->next;
 			}
-			if(rule->stopper == 1)
+			if(stopper_mode_param == 0 && rule->stopper == 1) {
+				LM_DBG("lcr_rule[%d] has stopper\n", rule->rule_id);
 				goto done;
+			}
 
 		next:
 			rule = rule->next;
@@ -2262,6 +2271,11 @@ done:
 		if(matched_gws[i].duplicate == 1)
 			continue;
 		gw_indexes[j] = matched_gws[i].gw_index;
+		if(stopper_mode_param != 0 && matched_gws[i].stopper == 1){
+			LM_DBG("lcr_rule[%d] has stopper, skip the rest\n",
+				matched_gws[i].rule_id);
+			i = -1;
+		}
 		j++;
 	}
 
@@ -2277,7 +2291,7 @@ static int ki_load_gws_furi(
 {
 	str *request_uri;
 	int i, j;
-	unsigned int gw_index, now, dex;
+	unsigned int gw_index, now, dex, stopper_flag;
 	int_str val;
 	struct matched_gw_info matched_gws[MAX_NO_OF_GWS + 1];
 	struct rule_info **rules, *rule, *pl;
@@ -2392,6 +2406,8 @@ static int ki_load_gws_furi(
 				matched_gws[gw_index].priority = t->priority;
 				matched_gws[gw_index].weight = t->weight * (kam_rand() >> 8);
 				matched_gws[gw_index].duplicate = 0;
+				if(stopper_mode_param != 0)
+					matched_gws[gw_index].stopper = rule->stopper;
 				LM_DBG("added matched_gws[%d]=[%u, %u, %u, %u]\n", gw_index,
 						t->gw_index, pl->prefix_len, t->priority,
 						matched_gws[gw_index].weight);
@@ -2400,8 +2416,10 @@ static int ki_load_gws_furi(
 				t = t->next;
 			}
 			/* Do not look further if this matching rule was stopper */
-			if(rule->stopper == 1)
+			if(stopper_mode_param == 0 && rule->stopper == 1) {
+				LM_DBG("lcr_rule[%d] has stopper\n", rule->rule_id);
 				goto done;
+			}
 
 		next:
 			rule = rule->next;
@@ -2426,6 +2444,24 @@ done:
 		}
 	}
 
+	if(stopper_mode_param != 0) {
+		/* mark as duplicate any other rule after a stopper rule,
+		   this is needed due to avp are stored in backwards order of priority
+		 */
+		stopper_flag = 0;
+		for(i = gw_index - 1; i >= 0; i--) {
+			if(matched_gws[i].duplicate == 1)
+				continue;
+			if(stopper_flag) {
+				matched_gws[i].duplicate = 1;
+			} else if(matched_gws[i].stopper == 1) {
+				stopper_flag = 1;
+				LM_DBG("lcr_rule[%d] has stopper, skip the rest\n",
+					matched_gws[i].rule_id);
+			}
+		}
+	}
+
 	/* Add gateways into gw_uris_avp */
 	add_gws_into_avps(gws, matched_gws, gw_index, ruri_user);
 
diff --git a/src/modules/lcr/lcr_mod.h b/src/modules/lcr/lcr_mod.h
index 421fe68..193e216 100644
--- a/src/modules/lcr/lcr_mod.h
+++ b/src/modules/lcr/lcr_mod.h
@@ -85,6 +85,7 @@ struct matched_gw_info
 	unsigned short priority;
 	unsigned int weight;
 	unsigned short duplicate;
+	unsigned short stopper;
 };
 
 struct target
