Browse code

tm: API improvement, new function introduced: t_append_branch_by_contact()

New module functions introduced:
- t_append_branch_by_contact()

This commit introduces a possibility of TM's API to append a branch
based on specific location (Contact's URI).

Indeed the 't_append_branch_by_contact()' is a corrected copy of
the 't_append_branches()', which instead takes Contact as a parameter
of str type.

The separate function has been introduced, in order to save full
back-compatibility, and not affect existing implementation.

Donat Zenichev authored on 12/11/2021 15:16:37
Showing 4 changed files
... ...
@@ -237,3 +237,209 @@ done:
237 237
 	}
238 238
 	return ret;
239 239
 }
240
+
241
+/* append a new transaction based on desired Contact hf value
242
+ * contact parameter must be of syntax (no hf parameters):
243
+ * sip:<user>@<host>:<port> */
244
+int t_append_branch_by_contact(str * contact) {
245
+	struct cell *t = NULL;
246
+	struct sip_msg *orig_msg = NULL;
247
+	struct sip_msg *faked_req;
248
+	int faked_req_len = 0;
249
+
250
+	short outgoings;
251
+
252
+	int success_branch;
253
+
254
+	str current_uri;
255
+	str dst_uri, path, instance, ruid, location_ua;
256
+	struct socket_info* si;
257
+	int q, i, found, append;
258
+	flag_t backup_bflags = 0;
259
+	flag_t bflags = 0;
260
+	int new_branch, branch_ret, lowest_ret;
261
+	branch_bm_t	added_branches;
262
+	int replies_locked = 0;
263
+	int ret = 0;
264
+
265
+	t = get_t();
266
+	if(t == NULL)
267
+	{
268
+		LM_ERR("cannot get transaction\n");
269
+		return -1;
270
+	}
271
+
272
+	LM_DBG("transaction %u:%u in status %d\n", t->hash_index, t->label, t->uas.status);
273
+
274
+	/* test if transaction has already been canceled */
275
+	if (t->flags & T_CANCELED) {
276
+		ser_error=E_CANCELED;
277
+		return -1;
278
+	}
279
+
280
+	if ((t->uas.status >= 200 && t->uas.status<=399)
281
+			|| ((t->uas.status >= 600 && t->uas.status)
282
+				&& !(t->flags & (T_6xx | T_DISABLE_6xx))) ) {
283
+		LM_DBG("transaction %u:%u in status %d: cannot append new branch\n",
284
+				t->hash_index, t->label, t->uas.status);
285
+		return -1;
286
+	}
287
+
288
+	/* set the lock on the transaction here */
289
+	LOCK_REPLIES(t);
290
+	replies_locked = 1;
291
+	outgoings = t->nr_of_outgoings;
292
+	orig_msg = t->uas.request;
293
+
294
+	LM_DBG("Call %.*s: %d (%d) outgoing branches\n",orig_msg->callid->body.len,
295
+			orig_msg->callid->body.s,outgoings, nr_branches);
296
+
297
+	lowest_ret=E_UNSPEC;
298
+	added_branches=0;
299
+
300
+	/* it's a "late" branch so the on_branch variable has already been
301
+	reset by previous execution of t_forward_nonack: we use the saved
302
+	   value  */
303
+	if (t->on_branch_delayed) {
304
+		/* tell add_uac that it should run branch route actions */
305
+		set_branch_route(t->on_branch_delayed);
306
+	}
307
+	faked_req = fake_req(orig_msg, 0, NULL,	&faked_req_len);
308
+	if (faked_req==NULL) {
309
+		LM_ERR("fake_req failed\n");
310
+		return -1;
311
+	}
312
+
313
+	/* fake also the env. conforming to the fake msg */
314
+	faked_env( t, faked_req, 0);
315
+
316
+	/* DONE with faking ;-) -> run the failure handlers */
317
+	init_branch_iterator();
318
+
319
+	while((current_uri.s=next_branch( &current_uri.len, &q, &dst_uri, &path,
320
+										&bflags, &si, &ruid, &instance, &location_ua))) {
321
+		LM_DBG("Current uri %.*s\n",current_uri.len, current_uri.s);
322
+
323
+		append = 1;
324
+		if (strstr(current_uri.s, contact->s) == NULL) {
325
+			append = 0;
326
+		}
327
+
328
+		/* do not append the branch if a contact does not match */
329
+		if (!append)
330
+			continue;
331
+
332
+		LM_DBG("Branch will be appended for contact <%.*s>\n", contact->len, contact->s);
333
+
334
+		found = 0;
335
+		for (i=0; i<outgoings; i++) {
336
+			if (t->uac[i].ruid.len == ruid.len
337
+					&& !memcmp(t->uac[i].ruid.s, ruid.s, ruid.len)
338
+					&& t->uac[i].uri.len == current_uri.len
339
+					&& !memcmp(t->uac[i].uri.s, current_uri.s, current_uri.len)) {
340
+				LM_DBG("branch already added [%.*s]\n", ruid.len, ruid.s);
341
+				found = 1;
342
+				break;
343
+			}
344
+		}
345
+		if (found)
346
+			continue;
347
+
348
+		setbflagsval(0, bflags);
349
+		new_branch=add_uac( t, faked_req, &current_uri,
350
+					(dst_uri.len) ? (&dst_uri) : &current_uri,
351
+					&path, 0, si, faked_req->fwd_send_flags,
352
+					PROTO_NONE, (dst_uri.len)?0:UAC_SKIP_BR_DST_F, &instance,
353
+					&ruid, &location_ua);
354
+
355
+		LM_DBG("added branch [%.*s] with ruid [%.*s]\n",
356
+				current_uri.len, current_uri.s, ruid.len, ruid.s);
357
+
358
+		/* test if cancel was received meanwhile */
359
+		if (t->flags & T_CANCELED) goto canceled;
360
+
361
+		if (new_branch>=0)
362
+			added_branches |= 1<<new_branch;
363
+		else
364
+			lowest_ret=MIN_int(lowest_ret, new_branch);
365
+	}
366
+
367
+	clear_branches();
368
+
369
+	LM_DBG("Call %.*s: %d (%d) outgoing branches after clear_branches()\n",
370
+			orig_msg->callid->body.len, orig_msg->callid->body.s,outgoings, nr_branches);
371
+	setbflagsval(0, backup_bflags);
372
+
373
+	/* update message flags, if changed in branch route */
374
+	t->uas.request->flags = faked_req->flags;
375
+
376
+	if (added_branches==0) {
377
+		if(lowest_ret!=E_CFG)
378
+			LM_ERR("failure to add branches (%d)\n", lowest_ret);
379
+		ser_error=lowest_ret;
380
+		ret = lowest_ret;
381
+		goto done;
382
+	}
383
+
384
+	ser_error=0; /* clear branch adding errors */
385
+	/* send them out now */
386
+	success_branch=0;
387
+	/* since t_append_branch can only be called from REQUEST_ROUTE, always lock replies */
388
+
389
+	for (i=outgoings; i<t->nr_of_outgoings; i++) {
390
+		if (added_branches & (1<<i)) {
391
+			branch_ret=t_send_branch(t, i, faked_req , 0, 0 /* replies are already locked */ );
392
+			if (branch_ret>=0){ /* some kind of success */
393
+				if (branch_ret==i) { /* success */
394
+					success_branch++;
395
+					if (unlikely(has_tran_tmcbs(t, TMCB_REQUEST_OUT)))
396
+						run_trans_callbacks_with_buf( TMCB_REQUEST_OUT,
397
+								&t->uac[nr_branches].request,
398
+								faked_req, 0, TMCB_NONE_F);
399
+				}
400
+				else /* new branch added */
401
+					added_branches |= 1<<branch_ret;
402
+			}
403
+		}
404
+	}
405
+	if (success_branch<=0) {
406
+		/* return always E_SEND for now
407
+		 * (the real reason could be: denied by onsend routes, blocklisted,
408
+		 *  send failed or any of the errors listed before + dns failed
409
+		 *  when attempting dns failover) */
410
+		ser_error=E_SEND;
411
+		/* else return the last error (?) */
412
+		ret = -1;
413
+		goto done;
414
+	}
415
+
416
+	ser_error=0; /* clear branch send errors, we have overall success */
417
+	set_kr(REQ_FWDED);
418
+	ret = success_branch;
419
+	goto done;
420
+
421
+canceled:
422
+	LM_DBG("cannot append branches to a canceled transaction\n");
423
+	/* reset processed branches */
424
+	clear_branches();
425
+	/* restore backup flags from initial env */
426
+	setbflagsval(0, backup_bflags);
427
+	/* update message flags, if changed in branch route */
428
+	t->uas.request->flags = faked_req->flags;
429
+	/* if needed unlock transaction's replies */
430
+		/* restore the number of outgoing branches
431
+		 * since new branches have not been completed */
432
+	t->nr_of_outgoings = outgoings;
433
+	ser_error=E_CANCELED;
434
+	ret = -1;
435
+done:
436
+	/* restore original environment and free the fake msg */
437
+	faked_env( t, 0, 0);
438
+	free_faked_req(faked_req, faked_req_len);
439
+
440
+	if (likely(replies_locked)) {
441
+		replies_locked = 0;
442
+		UNLOCK_REPLIES(t);
443
+	}
444
+	return ret;
445
+}
240 446
\ No newline at end of file
... ...
@@ -34,4 +34,8 @@
34 34
 int t_append_branches(void);
35 35
 typedef int (*t_append_branches_f)(void);
36 36
 
37
+/* append a new transaction based on desired Contact hf value */
38
+int t_append_branch_by_contact(str * contact);
39
+typedef int (*t_append_branch_by_contact_f)(str * contact);
40
+
37 41
 #endif
... ...
@@ -134,6 +134,7 @@ int load_tm( struct tm_binds *tmb)
134 134
 	tmb->tm_ctx_get = tm_ctx_get;
135 135
 #endif
136 136
 	tmb->t_append_branches = t_append_branches;
137
+	tmb->t_append_branch_by_contact = t_append_branch_by_contact;
137 138
 	tmb->t_load_contacts = t_load_contacts;
138 139
 	tmb->t_next_contacts = t_next_contacts;
139 140
 	tmb->set_fr = t_set_fr;
... ...
@@ -117,6 +117,7 @@ struct tm_binds {
117 117
 	void* reserved5;
118 118
 #endif
119 119
 	t_append_branches_f	t_append_branches;
120
+	t_append_branch_by_contact_f	t_append_branch_by_contact;
120 121
 	cmd_function	t_load_contacts;
121 122
 	cmd_function	t_next_contacts;
122 123
 	tset_fr_f set_fr;