Browse code

core: new parameter route_locks_size

- if set, kamailio creates a group of recursive locks used to sync on
execution of request_route and reply_route based on hashing ID of
Call-ID header. In other words, if a message has triggered the execution
of request_route or reply_route, any other message with the same Call-ID
waits until the other one finishes the execution.
- it should help when messages belonging to the same dialog come quickly
one after the other and config execution results in sending them out in
reverse order. There are some old UA implementations not able to cope
properly with this case (e.g., pstn gateways).
- be very carefull when eanbling it, it can affect performances, use
only when strictly needed
- note also that hashing over Call-ID means that there could be
collisions and different Call-ID values can result in same hash ID
- default value is 0 - feature not enabled
- set it to a positive integer number, it should be higher than the over
all number of processes created by kamailio, can be much higher

Daniel-Constantin Mierla authored on 12/03/2018 15:44:25
Showing 6 changed files
... ...
@@ -444,6 +444,7 @@ VERSION_TABLE_CFG	"version_table"
444 444
 VERBOSE_STARTUP		"verbose_startup"
445 445
 
446 446
 SERVER_ID     "server_id"
447
+ROUTE_LOCKS_SIZE     "route_locks_size"
447 448
 
448 449
 KEMI     "kemi"
449 450
 ONSEND_ROUTE_CALLBACK	"onsend_route_callback"
... ...
@@ -932,6 +933,7 @@ IMPORTFILE      "import_file"
932 933
 <INITIAL>{VERSION_TABLE_CFG}  { count(); yylval.strval=yytext; return VERSION_TABLE_CFG;}
933 934
 <INITIAL>{VERBOSE_STARTUP}		{	count(); yylval.strval=yytext;
934 935
 									return VERBOSE_STARTUP; }
936
+<INITIAL>{ROUTE_LOCKS_SIZE}  { count(); yylval.strval=yytext; return ROUTE_LOCKS_SIZE; }
935 937
 <INITIAL>{SERVER_ID}  { count(); yylval.strval=yytext; return SERVER_ID;}
936 938
 <INITIAL>{KEMI}  { count(); yylval.strval=yytext; return KEMI;}
937 939
 <INITIAL>{REPLY_ROUTE_CALLBACK}  { count(); yylval.strval=yytext; return REPLY_ROUTE_CALLBACK;}
... ...
@@ -480,6 +480,7 @@ extern char *default_routename;
480 480
 %token HTTP_REPLY_PARSE
481 481
 %token VERSION_TABLE_CFG
482 482
 %token VERBOSE_STARTUP
483
+%token ROUTE_LOCKS_SIZE
483 484
 %token CFG_DESCRIPTION
484 485
 %token SERVER_ID
485 486
 %token KEMI
... ...
@@ -1569,6 +1570,8 @@ assign_stm:
1569 1570
 	| HTTP_REPLY_PARSE EQUAL error { yyerror("boolean value expected"); }
1570 1571
 	| VERBOSE_STARTUP EQUAL NUMBER { ksr_verbose_startup=$3; }
1571 1572
 	| VERBOSE_STARTUP EQUAL error { yyerror("boolean value expected"); }
1573
+	| ROUTE_LOCKS_SIZE EQUAL NUMBER { ksr_route_locks_size=$3; }
1574
+	| ROUTE_LOCKS_SIZE EQUAL error { yyerror("number expected"); }
1572 1575
     | SERVER_ID EQUAL NUMBER { server_id=$3; }
1573 1576
 	| SERVER_ID EQUAL error  { yyerror("number expected"); }
1574 1577
 	| KEMI DOT ONSEND_ROUTE_CALLBACK EQUAL STRING {
... ...
@@ -204,6 +204,7 @@ extern int rt_timer2_policy; /* "slow" timer, SCHED_OTHER */
204 204
 extern int http_reply_parse;
205 205
 extern int _sr_ip_free_bind;
206 206
 extern int ksr_verbose_startup;
207
+extern int ksr_route_locks_size;
207 208
 
208 209
 #ifdef USE_DNS_CACHE
209 210
 extern int dns_cache_init; /* if 0, the DNS cache is not initialized at startup */
... ...
@@ -69,6 +69,36 @@ str default_global_port = {0, 0};
69 69
 str default_via_address = {0, 0};
70 70
 str default_via_port = {0, 0};
71 71
 
72
+int ksr_route_locks_size = 0;
73
+static rec_lock_set_t* ksr_route_locks_set = NULL;
74
+
75
+int ksr_route_locks_set_init(void)
76
+{
77
+	if(ksr_route_locks_set!=NULL || ksr_route_locks_size<=0)
78
+		return 0;
79
+
80
+	ksr_route_locks_set = rec_lock_set_alloc(ksr_route_locks_size);
81
+	if(ksr_route_locks_set) {
82
+		LM_ERR("failed to allocate route locks set\n");
83
+		return -1;
84
+	}
85
+	if(rec_lock_set_init(ksr_route_locks_set)==NULL) {
86
+		LM_ERR("failed to init route locks set\n");
87
+		return -1;
88
+	}
89
+	return 0;
90
+}
91
+
92
+void ksr_route_locks_set_destroy(void)
93
+{
94
+	if(ksr_route_locks_set==NULL)
95
+		return;
96
+
97
+	rec_lock_set_destroy(ksr_route_locks_set);
98
+	rec_lock_set_dealloc(ksr_route_locks_set);
99
+	ksr_route_locks_set = NULL;
100
+}
101
+
72 102
 /**
73 103
  * increment msg_no and return the new value
74 104
  */
... ...
@@ -137,6 +167,8 @@ int receive_msg(char *buf, unsigned int len, struct receive_info *rcv_info)
137 167
 	sr_net_info_t netinfo;
138 168
 	sr_kemi_eng_t *keng = NULL;
139 169
 	sr_event_param_t evp = {0};
170
+	unsigned int cidlockidx = 0;
171
+	unsigned int cidlockset = 0;
140 172
 
141 173
 	if(sr_event_enabled(SREV_NET_DATA_RECV)) {
142 174
 		if(sip_check_fline(buf, len) == 0) {
... ...
@@ -210,6 +242,13 @@ int receive_msg(char *buf, unsigned int len, struct receive_info *rcv_info)
210 242
 	/* ... clear branches from previous message */
211 243
 	clear_branches();
212 244
 
245
+	if(ksr_route_locks_set!=NULL && msg->callid && msg->callid->body.s
246
+			&& msg->callid->body.len >0) {
247
+		cidlockidx = get_hash1_raw(msg->callid->body.s, msg->callid->body.len);
248
+		cidlockidx = cidlockidx % ksr_route_locks_set->size;
249
+		cidlockset = 1;
250
+	}
251
+
213 252
 	if(msg->first_line.type == SIP_REQUEST) {
214 253
 		ruri_mark_new(); /* ruri is usable for forking (not consumed yet) */
215 254
 		if(!IS_SIP(msg)) {
... ...
@@ -270,14 +309,24 @@ int receive_msg(char *buf, unsigned int len, struct receive_info *rcv_info)
270 309
 				LM_ERR("no config routing engine registered\n");
271 310
 				goto error_req;
272 311
 			}
312
+			if(cidlockset)
313
+				rec_lock_set_get(ksr_route_locks_set, cidlockidx);
273 314
 			if(keng->froute(msg, REQUEST_ROUTE, NULL, NULL) < 0) {
274 315
 				LM_NOTICE("negative return code from engine function\n");
275 316
 			}
317
+			if(cidlockset)
318
+				rec_lock_set_release(ksr_route_locks_set, cidlockidx);
276 319
 		} else {
320
+			if(cidlockset)
321
+				rec_lock_set_get(ksr_route_locks_set, cidlockidx);
277 322
 			if(run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0) < 0) {
323
+				if(cidlockset)
324
+					rec_lock_set_release(ksr_route_locks_set, cidlockidx);
278 325
 				LM_WARN("error while trying script\n");
279 326
 				goto error_req;
280 327
 			}
328
+			if(cidlockset)
329
+				rec_lock_set_release(ksr_route_locks_set, cidlockidx);
281 330
 		}
282 331
 
283 332
 		if(is_printable(cfg_get(core, core_cfg, latency_cfg_log))
... ...
@@ -336,10 +385,18 @@ int receive_msg(char *buf, unsigned int len, struct receive_info *rcv_info)
336 385
 				bctx = sr_kemi_act_ctx_get();
337 386
 				init_run_actions_ctx(&ctx);
338 387
 				sr_kemi_act_ctx_set(&ctx);
388
+				if(cidlockset)
389
+					rec_lock_set_get(ksr_route_locks_set, cidlockidx);
339 390
 				ret = keng->froute(msg, CORE_ONREPLY_ROUTE, NULL, NULL);
391
+				if(cidlockset)
392
+					rec_lock_set_release(ksr_route_locks_set, cidlockidx);
340 393
 				sr_kemi_act_ctx_set(bctx);
341 394
 			} else {
395
+				if(cidlockset)
396
+					rec_lock_set_get(ksr_route_locks_set, cidlockidx);
342 397
 				ret = run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, &ctx);
398
+				if(cidlockset)
399
+					rec_lock_set_release(ksr_route_locks_set, cidlockidx);
343 400
 			}
344 401
 #ifndef NO_ONREPLY_ROUTE_ERROR
345 402
 			if(unlikely(ret < 0)) {
... ...
@@ -35,4 +35,7 @@ int receive_msg(char* buf, unsigned int len, struct receive_info *ri);
35 35
 unsigned int inc_msg_no(void);
36 36
 void ksr_msg_env_reset(void);
37 37
 
38
+int ksr_route_locks_set_init(void);
39
+void ksr_route_locks_set_destroy(void);
40
+
38 41
 #endif
... ...
@@ -135,6 +135,7 @@
135 135
 #include "core/dset.h"
136 136
 #include "core/timer_proc.h"
137 137
 #include "core/srapi.h"
138
+#include "core/receive.h"
138 139
 
139 140
 #ifdef DEBUG_DMALLOC
140 141
 #include <dmalloc.h>
... ...
@@ -554,6 +555,7 @@ void cleanup(int show_status)
554 555
 #endif
555 556
 	destroy_timer();
556 557
 	pv_destroy_api();
558
+	ksr_route_locks_set_destroy();
557 559
 	destroy_script_cb();
558 560
 	destroy_nonsip_hooks();
559 561
 	destroy_routes();
... ...
@@ -2324,6 +2326,9 @@ try_again:
2324 2326
 	if (pv_reinit_buffer()<0)
2325 2327
 		goto error;
2326 2328
 
2329
+	if (ksr_route_locks_set_init()<0)
2330
+		goto error;
2331
+
2327 2332
 	/* init lookup for core event routes */
2328 2333
 	sr_core_ert_init();
2329 2334