Browse code

tsilo: Add support of a lookup and branch creating by contact

Improvement of the TSILO module, which allows to run a lookup using the provided RURI,
but only to create a new branch for the Contact, which is set in the currently processed REGISTER.
Or optionally a Contact URI value given as a parameter to the function.
If the Contact URI for a lookup, is given as a parameter,
it is possible to provide it as a pseudo-variable.

Hence it is now possible to append new branch(es) for only UAC(s)
getting REGISTERED at the moment of calling 'ts_append_by_contact()'.

Previously it was only possible to call 'ts_append()' and create new branches
for all previously present location records (for this specific URI), which was in some circumstsances undersired.

New script functions introduced:
- ts_append_by_contact(table, ruri [, contact])

New module functions introduced:
- w_ts_append_by_contact2() / ki_ts_append_by_contact()
- w_ts_append_by_contact3 / ki_ts_append_by_contact_uri()
- ts_append_by_contact() / ts_append_by_contact_to()

Backwards compatibility is saved, the new functionality is not overlapping with
the previously existing implementation, hence it only acts when the new script function
ts_append_by_contact() is used.

The documentation has been updated accordingly.

Donat Zenichev authored on 12/11/2021 13:30:44
Showing 5 changed files
... ...
@@ -23,6 +23,11 @@
23 23
 		<surname>Cabiddu</surname>
24 24
 		<email>federico.cabiddu@gmail.com</email>
25 25
 	    </editor>
26
+	    <editor>
27
+		<firstname>Donat</firstname>
28
+		<surname>Zenichev</surname>
29
+		<email>dzenichev@sipwise.com</email>
30
+	    </editor>
26 31
 	</authorgroup>
27 32
 	<copyright>
28 33
 	    <year>2015</year>
... ...
@@ -181,6 +181,60 @@ if (is_method("REGISTER")) {
181 181
 	ts_append("location", "$tu");
182 182
 }
183 183
 ...
184
+</programlisting>
185
+		</example>
186
+	</section>
187
+	<section id="tsilo.f.ts_append_by_contact">
188
+		<title><function moreinfo="none">ts_append_by_contact(domain, ruri [, contact])</function></title>
189
+		<para>
190
+		Has almost the same intention as the ts_append(),
191
+		but gives a possibility to append branches
192
+		only for a specific location record (Contact URI).
193
+		The contact's URI value can be either taken from the currently processed REGISTER
194
+		or (optionally) given as a third parameter.
195
+		If the Contact URI for a lookup is given as the parameter,
196
+		it is possible to provide it as a pseudo-variable.
197
+
198
+		The contact lookup is performed on the table specified by the domain parameter.
199
+		The method should be called when a REGISTER request is received.
200
+		</para>
201
+		<para>Meaning of the parameters is as follows:</para>
202
+		<itemizedlist>
203
+		<listitem>
204
+			<para>
205
+			<emphasis>domain</emphasis> - Name of table that should be used for looking
206
+			up new contacts for r-uri.
207
+			</para>
208
+		</listitem>
209
+		<listitem>
210
+			<para>
211
+			<emphasis>ruri</emphasis> - The r-uri for which we want to check existing
212
+			transactions and add them new branches. Can be a static string value or a
213
+			dynamic string with pseudo-variables.
214
+			</para>
215
+		</listitem>
216
+		<listitem>
217
+			<para>
218
+			<emphasis>contact</emphasis> - Optional, a value of the location record
219
+			(contact URI) based on which to perform the branch appending.
220
+			If not given, the value will be taken from the currently processed REGISTER.
221
+			If a location lookup based on this Contact URI fails (no location record found),
222
+			then the branch append will not happen.
223
+			</para>
224
+		</listitem>
225
+		</itemizedlist>
226
+		<para>
227
+		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.
228
+		</para>
229
+		<example>
230
+		<title><function>ts_append_by_contact</function> usage</title>
231
+		<programlisting format="linespecific">
232
+...
233
+if (is_method("REGISTER")) {
234
+	$var(formated_ct) = $(x_hdr(Contact){nameaddr.uri});
235
+	ts_append_by_contact("location", "$tu", "$var(formated_ct)");
236
+}
237
+...
184 238
 </programlisting>
185 239
 		</example>
186 240
 	</section>
... ...
@@ -139,3 +139,119 @@ done:
139 139
 
140 140
 	return ret;
141 141
 }
142
+
143
+int ts_append_by_contact(struct sip_msg* msg, str *ruri, str *contact, char *table) {
144
+	ts_urecord_t* _r;
145
+	ts_transaction_t* ptr;
146
+
147
+	struct sip_uri p_uri;
148
+	struct sip_uri c_uri;
149
+	str *t_uri;
150
+
151
+	int res;
152
+	int appended;
153
+
154
+	/* parse R-URI */
155
+	if (use_domain) {
156
+		t_uri = ruri;
157
+	} else {
158
+		if (parse_uri(ruri->s, ruri->len, &p_uri) < 0) {
159
+			LM_ERR("tsilo: failed to parse uri %.*s\n", ruri->len, ruri->s);
160
+			return -1;
161
+		}
162
+		t_uri = &p_uri.user;
163
+	}
164
+
165
+	/* parse contact */
166
+	if (parse_uri(contact->s, contact->len, &c_uri) < 0) {
167
+		LM_ERR("tsilo: failed to parse contact %.*s\n", ruri->len, ruri->s);
168
+		return -1;
169
+	}
170
+
171
+	/* find urecord in TSILO cache */
172
+	lock_entry_by_ruri(t_uri);
173
+	res = get_ts_urecord(t_uri, &_r);
174
+
175
+	if (res != 0) {
176
+		LM_ERR("tsilo: failed to retrieve record for %.*s\n", t_uri->len, t_uri->s);
177
+		unlock_entry_by_ruri(t_uri);
178
+		return -1;
179
+	}
180
+
181
+	/* cycle through existing transactions */
182
+	ptr = _r->transactions;
183
+	while(ptr) {
184
+		LM_DBG("tsilo: transaction %u:%u found for %.*s, going to append branches\n",
185
+						ptr->tindex, ptr->tlabel, t_uri->len, t_uri->s);
186
+		/* append only if the desired contact has been found in locations */
187
+		appended = ts_append_by_contact_to(msg, ptr->tindex, ptr->tlabel, table, ruri, contact);
188
+		if (appended > 0)
189
+			update_stat(added_branches, appended);
190
+		ptr = ptr->next;
191
+	}
192
+
193
+	unlock_entry_by_ruri(t_uri);
194
+
195
+	return 1;
196
+}
197
+
198
+int ts_append_by_contact_to(struct sip_msg* msg, int tindex, int tlabel, char *table, str *uri, str *contact) {
199
+	struct cell     *t=0;
200
+	struct cell     *orig_t;	/* a pointer to an existing transaction or 0 if lookup fails*/
201
+	struct sip_msg *orig_msg;
202
+	int ret;
203
+	str stable;
204
+
205
+	LM_DBG("tsilo: trying to append based on contact <%.*s>\n", contact->len, contact->s);
206
+
207
+	/* lookup a transaction based on its identifier (hash_index:label) */
208
+	orig_t = _tmb.t_gett();
209
+	if(_tmb.t_lookup_ident(&t, tindex, tlabel) < 0)
210
+	{
211
+		LM_ERR("tsilo: transaction [%u:%u] not found\n", tindex, tlabel);
212
+		ret = -1;
213
+		goto done;
214
+	}
215
+
216
+	/* check if the dialog is still in the early stage */
217
+	if (t->flags & T_CANCELED) {
218
+		LM_DBG("tsilo: trasaction [%u:%u] was cancelled\n", tindex, tlabel);
219
+		ret = -2;
220
+		goto done;
221
+	}
222
+	if (t->uas.status >= 200) {
223
+		LM_DBG("tsilo: trasaction [%u:%u] sent out a final response already - %d\n",
224
+					tindex, tlabel, t->uas.status);
225
+		ret = -3;
226
+		goto done;
227
+	}
228
+
229
+	/* get original (very first) request of the transaction */
230
+	orig_msg = t->uas.request;
231
+	stable.s = table;
232
+	stable.len = strlen(stable.s);
233
+
234
+	if(uri==NULL || uri->s==NULL || uri->len<=0) {
235
+		ret = _regapi.lookup_to_dset(orig_msg, &stable, NULL);
236
+	} else {
237
+		ret = _regapi.lookup_to_dset(orig_msg, &stable, uri);
238
+	}
239
+
240
+	if(ret != 1) {
241
+		LM_ERR("tsilo: transaction %u:%u: error updating dset (%d)\n", tindex, tlabel, ret);
242
+		ret = -4;
243
+		goto done;
244
+	}
245
+
246
+	/* start the transaction only for the desired contact
247
+		contact must be of syntax: sip:<user>@<host>:<port> with no parameters list*/
248
+	ret = _tmb.t_append_branch_by_contact(contact);
249
+
250
+done:
251
+	/* unref the transaction which had been referred by t_lookup_ident() call.
252
+	 * Restore the original transaction (if any) */
253
+	if(t) _tmb.unref_cell(t);
254
+	_tmb.t_sett(orig_t, T_BR_UNDEFINED);
255
+
256
+	return ret;
257
+}
... ...
@@ -24,5 +24,7 @@
24 24
 
25 25
 int ts_append(struct sip_msg* msg, str *ruri, char *table);
26 26
 int ts_append_to(struct sip_msg* msg, int tindex, int tlabel, char *table, str *uri);
27
+int ts_append_by_contact(struct sip_msg* msg, str *ruri, str *contact, char *table);
28
+int ts_append_by_contact_to(struct sip_msg* msg, int tindex, int tlabel, char *table, str *uri, str *contact);
27 29
 
28 30
 #endif
... ...
@@ -34,6 +34,8 @@
34 34
 #include "../../core/rpc_lookup.h"
35 35
 #include "../../core/kemi.h"
36 36
 
37
+#include "../../core/parser/contact/parse_contact.h"
38
+
37 39
 #include "ts_hash.h"
38 40
 #include "ts_handlers.h"
39 41
 #include "ts_append.h"
... ...
@@ -61,7 +63,9 @@ static int w_ts_append_to2(struct sip_msg* msg, char *idx, char *lbl, char *d, c
61 63
 static int fixup_ts_append_to(void** param, int param_no);
62 64
 static int w_ts_append(struct sip_msg* _msg, char *_table, char *_ruri);
63 65
 static int fixup_ts_append(void** param, int param_no);
64
-
66
+static int w_ts_append_by_contact2(struct sip_msg* _msg, char *_table, char *_ruri);
67
+static int w_ts_append_by_contact3(struct sip_msg* _msg, char *_table, char *_ruri, char *_contact);
68
+static int fixup_ts_append_by_contact(void** param, int param_no);
65 69
 static int w_ts_store(struct sip_msg* msg, char *p1, char *p2);
66 70
 static int w_ts_store1(struct sip_msg* msg, char *_ruri, char *p2);
67 71
 
... ...
@@ -78,6 +82,10 @@ static cmd_export_t cmds[]={
78 82
 		fixup_ts_append_to, 0, REQUEST_ROUTE | FAILURE_ROUTE },
79 83
 	{"ts_append", (cmd_function)w_ts_append,  2,
80 84
 		fixup_ts_append, 0, REQUEST_ROUTE | FAILURE_ROUTE },
85
+	{"ts_append_by_contact", (cmd_function)w_ts_append_by_contact2,  2,	/* for two parameters */
86
+		fixup_ts_append_by_contact, 0, REQUEST_ROUTE | FAILURE_ROUTE },
87
+	{"ts_append_by_contact", (cmd_function)w_ts_append_by_contact3,  3,	/* for three parameters */
88
+		fixup_ts_append_by_contact, 0, REQUEST_ROUTE | FAILURE_ROUTE },
81 89
 	{"ts_store", (cmd_function)w_ts_store,  0,
82 90
 		0 , 0, REQUEST_ROUTE | FAILURE_ROUTE },
83 91
 	{"ts_store", (cmd_function)w_ts_store1,  1,
... ...
@@ -241,6 +249,23 @@ static int fixup_ts_append(void** param, int param_no)
241 249
 	return 0;
242 250
 }
243 251
 
252
+static int fixup_ts_append_by_contact(void** param, int param_no)
253
+{
254
+	if (param_no==1) {
255
+		if(strlen((char*)*param)<=1 && (*(char*)(*param)==0 || *(char*)(*param)=='0')) {
256
+			*param = (void*)0;
257
+			LM_ERR("empty table name\n");
258
+			return -1;
259
+		}
260
+	}
261
+
262
+	if (param_no==2 || param_no==3) {
263
+		return fixup_spve_null(param, 1);
264
+	}
265
+
266
+	return 0;
267
+}
268
+
244 269
 /**
245 270
  *
246 271
  */
... ...
@@ -357,6 +382,238 @@ static int ki_ts_append_to_uri(sip_msg_t* _msg, int tindex, int tlabel,
357 382
 			_table->s, _uri);
358 383
 }
359 384
 
385
+/**
386
+ *
387
+ */
388
+static int w_ts_append_by_contact2(struct sip_msg* _msg, char *_table, char *_ruri) {
389
+	str ruri = STR_NULL;
390
+	str ruri_fixed = STR_NULL;
391
+
392
+	str contact = STR_NULL;
393
+	str tmp_contact = STR_NULL;
394
+	struct sip_uri curi;
395
+
396
+	int rc;
397
+
398
+	/* parse R-URI */
399
+	if (fixup_get_svalue(_msg, (gparam_t*)_ruri, &ruri_fixed)!=0) {
400
+		LM_ERR("failed to convert r-uri parameter\n");
401
+		return -1;
402
+	}
403
+
404
+	if (_ruri==NULL || strlen(_ruri) <= 0 || ruri_fixed.len <= 0) {
405
+		LM_ERR("tsilo: invalid ruri parameter (empty or zero length).\n");
406
+		return -1;
407
+	}
408
+
409
+	if (pkg_str_dup(&ruri, &ruri_fixed) < 0) {
410
+		LM_ERR("failed to copy r-uri parameter\n");
411
+		return -1;
412
+	}
413
+
414
+	if (ts_check_uri(&ruri) < 0) {
415
+		LM_ERR("tsilo: failed to parse R-URI.\n");
416
+		return -1;
417
+	}
418
+
419
+	/* parse Contact header */
420
+	if ((!_msg->contact && parse_headers(_msg, HDR_CONTACT_F, 0) != 0)
421
+			|| !_msg->contact) {
422
+		LM_WARN("tsilo: missing contact header or the value is empty/malformed.\n");
423
+		return -1;
424
+	}
425
+	if (_msg->contact) {
426
+		if (parse_contact(_msg->contact) < 0) {
427
+			LM_WARN("tsilo: failed to parse Contact header.\n");
428
+			return -1;
429
+		}
430
+		if (parse_uri(
431
+						((struct contact_body*)_msg->contact->parsed)->contacts->uri.s,
432
+						((struct contact_body*)_msg->contact->parsed)->contacts->uri.len,
433
+						&curi) != 0 ) {
434
+			if (ts_check_uri(&_msg->contact->body) < 0) {	/* one more attempt */
435
+				LM_WARN("tsilo: failed to parse Contact header.\n");
436
+				return -1;
437
+			}
438
+		}
439
+
440
+		tmp_contact.len = ((struct contact_body*)_msg->contact->parsed)->contacts->uri.len;
441
+		tmp_contact.s = (char*)pkg_malloc(tmp_contact.len+1);
442
+		if (tmp_contact.s == NULL) {
443
+			PKG_MEM_ERROR;
444
+			return -1;
445
+		}
446
+		memcpy(tmp_contact.s, ((struct contact_body*)_msg->contact->parsed)->contacts->uri.s, tmp_contact.len);
447
+		tmp_contact.s[tmp_contact.len] = '\0';
448
+
449
+		if (pkg_str_dup(&contact, &tmp_contact) < 0) {
450
+			if (pkg_str_dup(&contact, &_msg->contact->body) < 0) { /* one more attempt */
451
+				LM_ERR("tsilo: problems when calling ts_append_contact(), cannot copy Contact parameter.\n");
452
+				return -1;
453
+			}
454
+		}
455
+	}
456
+
457
+	/* contact must be of syntax: sip:<user>@<host>:<port> with no parameters list */
458
+	rc = ts_append_by_contact(_msg, &ruri, &contact, _table);
459
+
460
+	/* free previously used memory */
461
+	pkg_free(ruri.s);
462
+	pkg_free(contact.s);
463
+	pkg_free(tmp_contact.s);
464
+
465
+	return rc;
466
+}
467
+
468
+/**
469
+ *
470
+ */
471
+static int ki_ts_append_by_contact(sip_msg_t* _msg, str *_table, str *_ruri) {
472
+	str ruri = STR_NULL;
473
+	str contact = STR_NULL;
474
+	str tmp_contact = STR_NULL;
475
+	struct sip_uri curi;
476
+	int rc;
477
+
478
+	/* parse R-URI */
479
+	if (ts_check_uri(_ruri) < 0)
480
+		return -1;
481
+	if (pkg_str_dup(&ruri, _ruri) < 0)
482
+		return -1;
483
+
484
+	/* parse Contact header */
485
+	if ((!_msg->contact && parse_headers(_msg, HDR_CONTACT_F, 0) != 0) || !_msg->contact)
486
+		return -1;
487
+
488
+	if (_msg->contact) {
489
+		if (parse_contact(_msg->contact) < 0)
490
+			return -1;
491
+		if (parse_uri(
492
+						((struct contact_body*)_msg->contact->parsed)->contacts->uri.s,
493
+						((struct contact_body*)_msg->contact->parsed)->contacts->uri.len,
494
+						&curi) != 0 ) {
495
+			if (ts_check_uri(&_msg->contact->body) < 0) /* one more attempt */
496
+				return -1;
497
+		}
498
+
499
+		tmp_contact.len = ((struct contact_body*)_msg->contact->parsed)->contacts->uri.len;
500
+		tmp_contact.s = (char*)pkg_malloc(tmp_contact.len+1);
501
+		if (tmp_contact.s == NULL) {
502
+			PKG_MEM_ERROR;
503
+			return -1;
504
+		}
505
+		memcpy(tmp_contact.s, ((struct contact_body*)_msg->contact->parsed)->contacts->uri.s, tmp_contact.len);
506
+		tmp_contact.s[tmp_contact.len] = '\0';
507
+
508
+		if (pkg_str_dup(&contact, &tmp_contact) < 0) {
509
+			if (pkg_str_dup(&contact, &_msg->contact->body) < 0) /* one more attempt */
510
+				return -1;
511
+		}
512
+	}
513
+
514
+	/* contact must be of syntax: sip:<user>@<host>:<port> with no parameters list */
515
+	rc = ts_append_by_contact(_msg, &ruri, &contact, _table->s);
516
+
517
+	pkg_free(ruri.s);
518
+	pkg_free(contact.s);
519
+	pkg_free(tmp_contact.s);
520
+
521
+	return rc;
522
+}
523
+
524
+/**
525
+ *
526
+ */
527
+static int w_ts_append_by_contact3(struct sip_msg* _msg, char *_table, char *_ruri, char *_contact) {
528
+	str ruri = STR_NULL;
529
+	str ruri_fixed = STR_NULL;
530
+
531
+	str contact = STR_NULL;
532
+	str contact_fixed = STR_NULL;
533
+
534
+	int rc;
535
+
536
+	/* parse R-URI */
537
+	if (fixup_get_svalue(_msg, (gparam_t*)_ruri, &ruri_fixed)!=0) {
538
+		LM_ERR("failed to convert r-uri parameter\n");
539
+		return -1;
540
+	}
541
+
542
+	if (_ruri==NULL || strlen(_ruri) <= 0 || ruri_fixed.len <= 0) {
543
+		LM_ERR("tsilo: invalid ruri parameter.\n");
544
+		return -1;
545
+	}
546
+
547
+	if (pkg_str_dup(&ruri, &ruri_fixed) < 0) {
548
+		LM_ERR("failed to copy r-uri parameter\n");
549
+		return -1;
550
+	}
551
+
552
+	if (ts_check_uri(&ruri) < 0) {
553
+		LM_ERR("tsilo: failed to parse R-URI.\n");
554
+		return -1;
555
+	}
556
+
557
+	/* parse Contact header */
558
+	if (fixup_get_svalue(_msg, (gparam_t*)_contact, &contact_fixed)!=0) {
559
+		LM_ERR("failed to convert contact parameter\n");
560
+		return -1;
561
+	}
562
+
563
+	if (_contact==NULL || strlen(_contact) <= 0 || contact_fixed.len <= 0) {
564
+		LM_ERR("tsilo: invalid contact parameter.\n");
565
+		return -1;
566
+	}
567
+
568
+	if (pkg_str_dup(&contact, &contact_fixed) < 0) {
569
+		LM_ERR("failed to copy r-uri parameter\n");
570
+		return -1;
571
+	}
572
+
573
+	if (ts_check_uri(&contact) < 0) {
574
+		LM_ERR("tsilo: failed to parse Contact parameter.\n");
575
+		return -1;
576
+	}
577
+
578
+	/* contact must be of syntax: sip:<user>@<host>:<port> with no parameters list */
579
+	rc = ts_append_by_contact(_msg, &ruri, &contact, _table);
580
+
581
+	pkg_free(ruri.s);
582
+	pkg_free(contact.s);
583
+
584
+	return rc;
585
+}
586
+
587
+/**
588
+ *
589
+ */
590
+static int ki_ts_append_by_contact_uri(sip_msg_t* _msg, str *_table, str *_ruri, str *_contact) {
591
+	str ruri = STR_NULL;
592
+	str contact = STR_NULL;
593
+
594
+	int rc;
595
+
596
+	/* parse R-URI */
597
+	if(ts_check_uri(_ruri) < 0)
598
+		return -1;
599
+	if (pkg_str_dup(&ruri, _ruri) < 0)
600
+		return -1;
601
+
602
+	/* parse Contact header */
603
+	if (ts_check_uri(_contact) < 0)
604
+		return -1;
605
+	if (pkg_str_dup(&contact, _contact) < 0)
606
+		return -1;
607
+
608
+	/* contact must be of syntax: sip:<user>@<host>:<port> with no parameters list */
609
+	rc = ts_append_by_contact(_msg, &ruri, &contact, _table->s);
610
+
611
+	pkg_free(ruri.s);
612
+	pkg_free(contact.s);
613
+
614
+	return rc;
615
+}
616
+
360 617
 /**
361 618
  *
362 619
  */
... ...
@@ -417,6 +674,16 @@ static sr_kemi_t sr_kemi_tsilo_exports[] = {
417 674
 		{ SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_STR,
418 675
 			SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE }
419 676
 	},
677
+	{ str_init("tsilo"), str_init("ts_append_by_contact"),
678
+		SR_KEMIP_INT, ki_ts_append_by_contact,
679
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
680
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
681
+	},
682
+	{ str_init("tsilo"), str_init("ts_append_by_contact_uri"),
683
+		SR_KEMIP_INT, ki_ts_append_by_contact_uri,
684
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
685
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
686
+	},
420 687
 
421 688
 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
422 689
 };