Browse code

s/reply_route/failure_route, onreply_route introduced

Jiri Kuthan authored on 07/04/2003 06:36:56
Showing 15 changed files
... ...
@@ -35,10 +35,13 @@ New features
35 35
 - improved tm/FIFO (external applications, such as
36 36
   click-to-dial can now better initiate transactions)
37 37
   [tm module]
38
+- nathelper utility for Cisco/ATA NAT traversal
38 39
 - powerpc fast locking support
39 40
 - netbsd support
40 41
 - 64 bits arch. support (e.g. netbsd/sparc64).
41 42
 - tcp2udp and udp2tcp stateless forwarding (see forward_udp & forward_tcp)
43
+- rich access control lists [module permissions]
44
+
42 45
 
43 46
 Changes to use of ser scripts
44 47
 =============================
... ...
@@ -47,6 +50,8 @@ Changes to use of ser scripts
47 50
 core
48 51
 ----
49 52
 XXX TCP
53
+- reply_route has been renamed to failure_route -- the old name caused
54
+  too much confusion
50 55
 
51 56
 acc module:
52 57
 -----------
... ...
@@ -94,4 +99,26 @@ tm module:
94 99
 ----------
95 100
 - t_reply_unsafe, used in former versions within reply_routes,
96 101
   is deprecated; now t_reply is used from any places in script
97
-- XXX t_uac/FIFO
102
+- t_on_negative is renamed to t_on_failure -- the old name just
103
+  caused too much confusion
104
+- FIFO t_uac used by some applications (like serweb) has been
105
+  replaced with t_uac_dlg (which allows easier use by dialog-
106
+  oriented applications, like click-to-dial) 
107
+- if you wish to do forward to another destination from 
108
+  failure_route (reply_route formerly), you need to call t_relay
109
+  or t_relay_to explicitely now
110
+
111
+List of new modules:
112
+--------------------
113
+- dbtext -- flat-file database
114
+- domain -- automated domain management
115
+- enum -- ENUM support
116
+- nathelper -- utility for NAT traversal for Cisco ATAs
117
+- pa -- presence agent
118
+- permissions -- ACLs
119
+- vm -- voicemail interface
120
+
121
+List of deprecated modules:
122
+---------------------------
123
+- im (t_uac_dlg is used for sending messages)
124
+- radius_acc (radius accounting now part of acc module)
... ...
@@ -32,6 +32,7 @@
32 32
  *  2003-01-23  mhomed added (jiri)
33 33
  *  2003-03-19  replaced all the mallocs/frees w/ pkg_malloc/pkg_free (andrei)
34 34
  *  2003-04-01  added dst_port, proto (tcp, udp, tls), af(inet, inet6) (andrei)
35
+ *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
35 36
  */
36 37
 
37 38
 
... ...
@@ -78,7 +79,8 @@ SEND_TCP	send_tcp
78 79
 LOG		log
79 80
 ERROR	error
80 81
 ROUTE	route
81
-REPL_ROUTE reply_route
82
+FAILURE_ROUTE failure_route
83
+ONREPLY_ROUTE onreply_route
82 84
 EXEC	exec
83 85
 SETFLAG		setflag
84 86
 RESETFLAG	resetflag
... ...
@@ -106,7 +108,11 @@ MAX_LEN			"max_len"
106 108
 
107 109
 /* condition keywords */
108 110
 METHOD	method
109
-URI		uri
111
+/* hack -- the second element in first line is referrable
112
+   as either uri or status; it only would makes sense to
113
+   call it "uri" from route{} and status from onreply_route{}
114
+*/
115
+URI		"uri"|"status"
110 116
 SRCIP	src_ip
111 117
 SRCPORT	src_port
112 118
 DSTIP	dst_ip
... ...
@@ -206,7 +212,8 @@ EAT_ABLE	[\ \t\b\r]
206 212
 <INITIAL>{ISFLAGSET}	{ count(); yylval.strval=yytext; return ISFLAGSET; }
207 213
 <INITIAL>{LEN_GT}	{ count(); yylval.strval=yytext; return LEN_GT; }
208 214
 <INITIAL>{ROUTE}	{ count(); yylval.strval=yytext; return ROUTE; }
209
-<INITIAL>{REPL_ROUTE}	{ count(); yylval.strval=yytext; return REPL_ROUTE; }
215
+<INITIAL>{ONREPLY_ROUTE}	{ count(); yylval.strval=yytext; return ONREPLY_ROUTE; }
216
+<INITIAL>{FAILURE_ROUTE}	{ count(); yylval.strval=yytext; return FAILURE_ROUTE; }
210 217
 <INITIAL>{EXEC}	{ count(); yylval.strval=yytext; return EXEC; }
211 218
 <INITIAL>{SET_HOST}	{ count(); yylval.strval=yytext; return SET_HOST; }
212 219
 <INITIAL>{SET_HOSTPORT}	{ count(); yylval.strval=yytext; return SET_HOSTPORT; }
... ...
@@ -35,6 +35,7 @@
35 35
  * 2003-03-19  Added support for route type in find_export (janakj)
36 36
  * 2003-03-20  Regex support in modparam (janakj)
37 37
  * 2003-04-01  added dst_port, proto , af (andrei)
38
+ * 2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
38 39
  */
39 40
 
40 41
 
... ...
@@ -106,7 +107,8 @@ int rt;  /* Type of route block for find_export */
106 107
 %token LOG_TOK
107 108
 %token ERROR
108 109
 %token ROUTE
109
-%token REPL_ROUTE
110
+%token FAILURE_ROUTE
111
+%token ONREPLY_ROUTE
110 112
 %token EXEC
111 113
 %token SET_HOST
112 114
 %token SET_HOSTPORT
... ...
@@ -221,7 +223,8 @@ statements:	statements statement {}
221 223
 statement:	assign_stm 
222 224
 		| module_stm
223 225
 		| {rt=REQUEST_ROUTE;} route_stm 
224
-		| {rt=REPLY_ROUTE;} reply_route_stm
226
+		| {rt=FAILURE_ROUTE;} failure_route_stm
227
+		| {rt=ONREPLY_ROUTE;} onreply_route_stm
225 228
 
226 229
 		| CR	/* null statement*/
227 230
 	;
... ...
@@ -463,15 +466,26 @@ route_stm:  ROUTE LBRACE actions RBRACE { push($3, &rlist[DEFAULT_RT]); }
463 466
 		| ROUTE error { yyerror("invalid  route  statement"); }
464 467
 	;
465 468
 
466
-reply_route_stm: REPL_ROUTE LBRACK NUMBER RBRACK LBRACE actions RBRACE {
467
-										if (($3<REPLY_RT_NO)&&($3>=1)){
468
-											push($6, &reply_rlist[$3]);
469
+failure_route_stm: FAILURE_ROUTE LBRACK NUMBER RBRACK LBRACE actions RBRACE {
470
+										if (($3<FAILURE_RT_NO)&&($3>=1)){
471
+											push($6, &failure_rlist[$3]);
469 472
 										} else {
470 473
 											yyerror("invalid reply routing"
471 474
 												"table number");
472 475
 											YYABORT; }
473 476
 										}
474
-		| REPL_ROUTE error { yyerror("invalid reply_route statement"); }
477
+		| FAILURE_ROUTE error { yyerror("invalid failure_route statement"); }
478
+	;
479
+
480
+onreply_route_stm: ONREPLY_ROUTE LBRACK NUMBER RBRACK LBRACE actions RBRACE {
481
+										if (($3<ONREPLY_RT_NO)&&($3>=1)){
482
+											push($6, &onreply_rlist[$3]);
483
+										} else {
484
+											yyerror("invalid reply routing"
485
+												"table number");
486
+											YYABORT; }
487
+										}
488
+		| ONREPLY_ROUTE error { yyerror("invalid failure_route statement"); }
475 489
 	;
476 490
 /*
477 491
 rules:	rules rule { push($2, &$1); $$=$1; }
... ...
@@ -50,7 +50,8 @@
50 50
 #define CHILD_NO    8
51 51
 
52 52
 #define RT_NO 10 /* routing tables number */
53
-#define REPLY_RT_NO 10 /* reply routing tables number */
53
+#define FAILURE_RT_NO RT_NO /* on_failure routing tables number */
54
+#define ONREPLY_RT_NO RT_NO /* on_reply routing tables number */
54 55
 #define DEFAULT_RT 0 /* default routing table */
55 56
 
56 57
 #define MAX_REC_LEV 100 /* maximum number of recursive calls */
... ...
@@ -39,20 +39,20 @@ route{
39 39
 	seturi("sip:nobody@iptel.org");
40 40
 	append_branch("sip:parallel@iptel.org:9");
41 41
 	# if we do not get a positive reply, continue at reply_route[1]
42
-	t_on_negative("1");
42
+	t_on_failure("1");
43 43
 	# forward the request to all destinations in destination set now 
44 44
 	t_relay();
45 45
 }
46 46
 
47
-reply_route[1] {
47
+failure_route[1] {
48 48
 	# forwarding failed -- try again at another destination 
49 49
 	append_branch("sip:nonsense@iptel.org");
50 50
 	log(1,"first redirection\n");
51 51
 	# if this alternative destination fails too, proceed to reply_route[2] 
52
-	t_on_negative("2");
52
+	t_on_failure("2");
53 53
 }
54 54
 
55
-reply_route[2] {
55
+failure_route[2] {
56 56
 	# try out the last resort destination
57 57
 	append_branch("sip:foo@iptel.org");
58 58
 	log(1, "second redirection\n");
... ...
@@ -225,6 +225,8 @@ typedef struct cell
225 225
 
226 226
 	/* the route to take if no final positive reply arrived */
227 227
 	unsigned int on_negative;
228
+	/* the onreply_route to be processed if registered to do so */
229
+	unsigned int on_reply;
228 230
 	/* set to one if you want to disallow silent transaction
229 231
 	   dropping when C timer hits
230 232
 	*/
... ...
@@ -386,6 +386,7 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
386 386
 	int i;
387 387
 	struct cell *t_invite;
388 388
 	int success_branch;
389
+	int try_new;
389 390
 
390 391
 	/* make -Wall happy */
391 392
 	current_uri.s=0;
... ...
@@ -414,15 +415,17 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
414 415
 	   is in additional branches (which may be continuously refilled
415 416
 	*/
416 417
 	if (first_branch==0) {
418
+		try_new=1;
417 419
 		branch_ret=add_uac( t, p_msg, &GET_RURI(p_msg), &GET_NEXT_HOP(p_msg), proxy, proto );
418 420
 		if (branch_ret>=0) 
419 421
 			added_branches |= 1<<branch_ret;
420 422
 		else
421 423
 			lowest_ret=branch_ret;
422
-	}
424
+	} else try_new=0;
423 425
 
424 426
 	init_branch_iterator();
425 427
 	while((current_uri.s=next_branch( &current_uri.len))) {
428
+		try_new++;
426 429
 		branch_ret=add_uac( t, p_msg, &current_uri, 
427 430
 				    (p_msg->dst_uri.len) ? (&p_msg->dst_uri) : &current_uri, 
428 431
 				    proxy, proto);
... ...
@@ -444,10 +447,19 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
444 447
 	/* don't forget to clear all branches processed so far */
445 448
 
446 449
 	/* things went wrong ... no new branch has been fwd-ed at all */
447
-	if (added_branches==0)
450
+	if (added_branches==0) {
451
+		if (try_new==0) {
452
+			LOG(L_ERR, "ERROR: t_forward_nonack: no branched for fwding\n");
453
+			return -1;
454
+		}
455
+		LOG(L_ERR, "ERROR: t_forward_nonack: failure to add branches\n");
448 456
 		return lowest_ret;
457
+	}
449 458
 
450
-	/* if someone set on_negative, store in in T-context */
459
+	/* store script processing value of failure route to transactional
460
+	   context; if currently 0, this forwarding attempt will no longer 
461
+	   result in failure_route on error
462
+	*/
451 463
 	t->on_negative=get_on_negative();
452 464
 
453 465
 	/* send them out now */
... ...
@@ -67,6 +67,8 @@
67 67
  * 2003-03-30  set_kr for requests only (jiri)
68 68
  * 2003-04-04  bug_fix: RESPONSE_IN callback not called for local
69 69
  *             UAC transactions (jiri)
70
+ * 2003-04-07  new transactions inherit on_negative and on_relpy from script
71
+ *             variables on instatntiation (jiri)
70 72
  */
71 73
 
72 74
 
... ...
@@ -1023,6 +1025,8 @@ int t_newtran( struct sip_msg* p_msg )
1023 1025
 
1024 1026
 				new_cell->method=new_cell->uas.request->first_line.u.request.method;
1025 1027
 				new_cell->is_invite=p_msg->REQ_METHOD==METHOD_INVITE;
1028
+				new_cell->on_negative=get_on_negative();
1029
+				new_cell->on_reply=get_on_reply();
1026 1030
 
1027 1031
 			}
1028 1032
 
... ...
@@ -41,6 +41,7 @@
41 41
  *  2003-03-16  removed _TOTAG (jiri)
42 42
  *  2003-03-31  200 for INVITE/UAS resent even for UDP (jiri)
43 43
  *  2003-03-31  removed msg->repl_add_rm (andrei)
44
+ *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
44 45
  */
45 46
 
46 47
 
... ...
@@ -82,6 +83,8 @@ static char *tm_tag_suffix;
82 83
 
83 84
 /* where to go if there is no positive reply */
84 85
 static int goto_on_negative=0;
86
+/* where to go on receipt of reply */
87
+static int goto_on_reply=0;
85 88
 
86 89
 
87 90
 /* we store the reply_route # in private memory which is
... ...
@@ -94,10 +97,14 @@ static int goto_on_negative=0;
94 97
 */
95 98
   
96 99
   
97
-int t_on_negative( unsigned int go_to )
100
+void t_on_negative( unsigned int go_to )
98 101
 {
99 102
 	goto_on_negative=go_to;
100
-	return 1;
103
+}
104
+
105
+void t_on_reply( unsigned int go_to )
106
+{
107
+	goto_on_reply=go_to;
101 108
 }
102 109
 
103 110
 
... ...
@@ -105,6 +112,10 @@ unsigned int get_on_negative()
105 112
 {
106 113
 	return goto_on_negative;
107 114
 }
115
+unsigned int get_on_reply()
116
+{
117
+	return goto_on_reply;
118
+}
108 119
 
109 120
 void tm_init_tags()
110 121
 {
... ...
@@ -141,6 +152,16 @@ int unmatched_totag(struct cell *t, struct sip_msg *ack)
141 152
 	return 1;
142 153
 }
143 154
 
155
+static inline void update_local_tags(struct cell *trans, 
156
+				struct bookmark *bm, char *dst_buffer,
157
+				char *src_buffer /* to which bm refers */)
158
+{
159
+	if (bm->to_tag_val.s) {
160
+		trans->uas.local_totag.s=bm->to_tag_val.s-src_buffer+dst_buffer;
161
+		trans->uas.local_totag.len=bm->to_tag_val.len;
162
+	}
163
+}
164
+
144 165
 
145 166
 /* append a newly received tag from a 200/INVITE to 
146 167
  * transaction's set; (only safe if called from within
... ...
@@ -213,6 +234,141 @@ static char *build_ack(struct sip_msg* rpl,struct cell *trans,int branch,
213 234
         ACK, ACK_LEN, &to );
214 235
 }
215 236
 
237
+static int _reply_light( struct cell *trans, char* buf, unsigned int len,
238
+			 unsigned int code, char * text, 
239
+			 char *to_tag, unsigned int to_tag_len, int lock,
240
+			 struct bookmark *bm	)
241
+{
242
+	struct retr_buf *rb;
243
+	unsigned int buf_len;
244
+	branch_bm_t cancel_bitmap;
245
+
246
+	if (!buf)
247
+	{
248
+		DBG("DEBUG: t_reply: response building failed\n");
249
+		/* determine if there are some branches to be cancelled */
250
+		if (trans->is_invite) {
251
+			if (lock) LOCK_REPLIES( trans );
252
+			which_cancel(trans, &cancel_bitmap );
253
+			if (lock) UNLOCK_REPLIES( trans );
254
+		}
255
+		/* and clean-up, including cancellations, if needed */
256
+		goto error;
257
+	}
258
+
259
+	cancel_bitmap=0;
260
+	if (lock) LOCK_REPLIES( trans );
261
+	if (trans->is_invite) which_cancel(trans, &cancel_bitmap );
262
+	if (trans->uas.status>=200) {
263
+		LOG( L_ERR, "ERROR: t_reply: can't generate %d reply"
264
+			" when a final %d was sent out\n", code, trans->uas.status);
265
+		goto error2;
266
+	}
267
+
268
+
269
+	rb = & trans->uas.response;
270
+	rb->activ_type=code;
271
+
272
+	trans->uas.status = code;
273
+	buf_len = rb->buffer ? len : len + REPLY_OVERBUFFER_LEN;
274
+	rb->buffer = (char*)shm_resize( rb->buffer, buf_len );
275
+	/* puts the reply's buffer to uas.response */
276
+	if (! rb->buffer ) {
277
+			LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n");
278
+			goto error3;
279
+	}
280
+	update_local_tags(trans, bm, rb->buffer, buf);
281
+
282
+	rb->buffer_len = len ;
283
+	memcpy( rb->buffer , buf , len );
284
+	/* needs to be protected too because what timers are set depends
285
+	   on current transactions status */
286
+	/* t_update_timers_after_sending_reply( rb ); */
287
+	update_reply_stats( code );
288
+	trans->relaied_reply_branch=-2;
289
+	tm_stats->replied_localy++;
290
+	if (lock) UNLOCK_REPLIES( trans );
291
+	
292
+	/* do UAC cleanup procedures in case we generated
293
+	   a final answer whereas there are pending UACs */
294
+	if (code>=200) {
295
+		if (trans->local) {
296
+			DBG("DEBUG: local transaction completed from _reply\n");
297
+			callback_event( TMCB_LOCAL_COMPLETED, trans, FAKED_REPLY, code );
298
+			if (trans->completion_cb) 
299
+				trans->completion_cb( trans, FAKED_REPLY, code, 0 /* empty param */);
300
+		} else {
301
+			callback_event( TMCB_RESPONSE_OUT, trans, FAKED_REPLY, code );
302
+		}
303
+
304
+		cleanup_uac_timers( trans );
305
+		if (trans->is_invite) cancel_uacs( trans, cancel_bitmap );
306
+		set_final_timer(  trans );
307
+	}
308
+
309
+	/* send it out */
310
+	/* first check if we managed to resolve topmost Via -- if
311
+	   not yet, don't try to retransmit
312
+	*/
313
+	if (!trans->uas.response.dst.send_sock) {
314
+		LOG(L_ERR, "ERROR: _reply: no resolved dst to send reply to\n");
315
+	} else {
316
+		SEND_PR_BUFFER( rb, buf, len );
317
+		DBG("DEBUG: reply sent out. buf=%p: %.9s..., shmem=%p: %.9s\n", 
318
+			buf, buf, rb->buffer, rb->buffer );
319
+	}
320
+	pkg_free( buf ) ;
321
+	DBG("DEBUG: t_reply: finished\n");
322
+	return 1;
323
+
324
+error3:
325
+error2:
326
+	if (lock) UNLOCK_REPLIES( trans );
327
+	pkg_free ( buf );
328
+error:
329
+	/* do UAC cleanup */
330
+	cleanup_uac_timers( trans );
331
+	if (trans->is_invite) cancel_uacs( trans, cancel_bitmap );
332
+	/* we did not succeed -- put the transaction on wait */
333
+	put_on_wait(trans);
334
+	return -1;
335
+}
336
+
337
+
338
+/* send a UAS reply
339
+ * returns 1 if everything was OK or -1 for error
340
+ */
341
+static int _reply( struct cell *trans, struct sip_msg* p_msg, 
342
+	unsigned int code, char * text, int lock )
343
+{
344
+	unsigned int len;
345
+	char * buf;
346
+	struct bookmark bm;
347
+
348
+	if (code>=200) set_kr(REQ_RPLD);
349
+	/* compute the buffer in private memory prior to entering lock;
350
+	 * create to-tag if needed */
351
+	if (code>=180 && p_msg->to 
352
+				&& (get_to(p_msg)->tag_value.s==0 
353
+			    || get_to(p_msg)->tag_value.len==0)) {
354
+		calc_crc_suffix( p_msg, tm_tag_suffix );
355
+		buf = build_res_buf_from_sip_req(code,text, 
356
+				tm_tags, TOTAG_VALUE_LEN, 
357
+				p_msg,&len, &bm);
358
+
359
+		return _reply_light(trans,buf,len,code,text,
360
+				    tm_tags, TOTAG_VALUE_LEN,
361
+				    lock, &bm);
362
+	} else {
363
+		buf = build_res_buf_from_sip_req(code,text, 0,0, /* no to-tag */
364
+			p_msg,&len, &bm);
365
+
366
+		return _reply_light(trans,buf,len,code,text,
367
+				    0,0, /* no to-tag */
368
+				    lock, &bm);
369
+	}
370
+}
371
+
216 372
 
217 373
 /* create a temporary faked message environment in which a conserved
218 374
  * t->uas.request in shmem is partially duplicated to pkgmem
... ...
@@ -257,7 +413,7 @@ static int faked_env(struct sip_msg *fake,
257 413
 	 * for example t_reply needs to know that
258 414
 	 */
259 415
 	backup_mode=rmode;
260
-	rmode=MODE_ONREPLY_REQUEST;
416
+	rmode=MODE_ONFAILURE;
261 417
 	/* also, tm actions look in beginning whether tranaction is
262 418
 	 * set -- whether we are called from a reply-processing 
263 419
 	 * or a timer process, we need to set current transaction;
... ...
@@ -309,11 +465,68 @@ restore:
309 465
 	return 0;
310 466
 }
311 467
 
468
+/* return 1 if a failure_route processes */
469
+int failure_route(struct cell *t)
470
+{
471
+	struct sip_msg faked_msg;
472
+
473
+	/* don't do anything if we don't have to */
474
+	if (!t->on_negative) return 0;
475
+
476
+	/* if fake message creation failes, return error too */
477
+	if (!faked_env(&faked_msg, t, t->uas.request, 0 /* create fake */ )) {
478
+		LOG(L_ERR, "ERROR: on_negative_reply: faked_env failed\n");
479
+		return 0;
480
+	}
481
+
482
+	/* avoid recursion -- if failure_route forwards, and does not 
483
+	 * set next failure route, failure_route will not be rentered
484
+	 * on failure */
485
+	t_on_negative(0);
486
+	/* run a reply_route action if some was marked */
487
+	if (run_actions(failure_rlist[t->on_negative], &faked_msg)<0)
488
+		LOG(L_ERR, "ERROR: on_negative_reply: "
489
+			"Error in do_action\n");
490
+	/* restore original environment */
491
+	faked_env(&faked_msg, 0, 0, 1 );
492
+	return 1;
493
+}
312 494
 
313 495
 
314
-/* the main code of stateful replying */
315
-static int _reply( struct cell *t, struct sip_msg* p_msg, unsigned int code,
316
-    char * text, int lock );
496
+/* select a branch for forwarding; returns:
497
+ * 0..X ... branch number
498
+ * -1   ... error
499
+ * -2   ... can't decide yet -- incomplete branches present
500
+ */
501
+static int pick_branch( int inc_branch, int inc_code, 
502
+			struct cell *t, int *res_code)
503
+{
504
+	int lowest_b, lowest_s, b;
505
+
506
+	lowest_b=-1; lowest_s=999;
507
+	for ( b=0; b<t->nr_of_outgoings ; b++ ) {
508
+		/* "fake" for the currently processed branch */
509
+		if (b==inc_branch) {
510
+			if (inc_code<lowest_s) {
511
+				lowest_b=b;
512
+				lowest_s=inc_code;
513
+			}
514
+			continue;
515
+		}
516
+		/* skip 'empty branches' */
517
+		if (!t->uac[b].request.buffer) continue;
518
+		/* there is still an unfinished UAC transaction; wait now! */
519
+		if ( t->uac[b].last_received<200 ) 
520
+			return -2;
521
+		if ( t->uac[b].last_received<lowest_s ) {
522
+			lowest_b =b;
523
+			lowest_s = t->uac[b].last_received;
524
+		}
525
+	} /* find lowest branch */
526
+
527
+	*res_code=lowest_s;
528
+	return lowest_b;
529
+}
317 530
 
318 531
 /* This is the neuralgical point of reply processing -- called
319 532
  * from within a REPLY_LOCK, t_should_relay_response decides
... ...
@@ -330,9 +543,10 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
330 543
 	int branch , int *should_store, int *should_relay,
331 544
 	branch_bm_t *cancel_bitmap, struct sip_msg *reply )
332 545
 {
333
-	int b, lowest_b, lowest_s, dummy;
334
-	struct sip_msg faked_msg, *origin_rq;
335
-	unsigned int on_neg;
546
+	
547
+	int branch_cnt;
548
+	int picked_branch;
549
+	int picked_code;
336 550
 
337 551
 	/* note: this code never lets replies to CANCEL go through;
338 552
 	   we generate always a local 200 for CANCEL; 200s are
... ...
@@ -378,63 +592,31 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
378 592
 		}
379 593
 
380 594
 		Trans->uac[branch].last_received=new_code;
595
+
596
+
381 597
 		/* if all_final return lowest */
382
-		lowest_b=-1; lowest_s=999;
383
-		for ( b=0; b<Trans->nr_of_outgoings ; b++ ) {
384
-			/* "fake" for the currently processed branch */
385
-			if (b==branch) {
386
-				if (new_code<lowest_s) {
387
-					lowest_b=b;
388
-					lowest_s=new_code;
389
-				}
390
-				continue;
391
-			}
392
-			/* skip 'empty branches' */
393
-			if (!Trans->uac[b].request.buffer) continue;
394
-			/* there is still an unfinished UAC transaction; wait now! */
395
-			if ( Trans->uac[b].last_received<200 ) {
396
-				*should_store=1;	
397
-				*should_relay=-1;
398
-				return RPS_STORE;
399
-			}
400
-			if ( Trans->uac[b].last_received<lowest_s )
401
-			{
402
-				lowest_b =b;
403
-				lowest_s = Trans->uac[b].last_received;
404
-			}
405
-		} /* find lowest branch */
406
-		if (lowest_b==-1) {
598
+		picked_branch=pick_branch(branch,new_code, Trans, &picked_code);
599
+		if (picked_branch==-2) { /* branches open yet */
600
+			*should_store=1;	
601
+			*should_relay=-1;
602
+			return RPS_STORE;
603
+		}
604
+		if (picked_branch==-1) {
407 605
 			LOG(L_CRIT, "ERROR: t_should_relay_response: lowest==-1\n");
606
+			goto error;
408 607
 		}
608
+
409 609
 		/* no more pending branches -- try if that changes after
410
-		   a callback
610
+		   a callback; save banch count to be able to determine
611
+		   later if new branches were initiated
411 612
 		*/
613
+		branch_cnt=Trans->nr_of_outgoings;
412 614
 		callback_event( TMCB_ON_FAILURE, Trans, 
413
-			lowest_b==branch?reply:Trans->uac[lowest_b].reply, 
414
-			lowest_s );
415
-
615
+			picked_branch==branch?reply:Trans->uac[picked_branch].reply, 
616
+			picked_code);
416 617
 		/* here, we create a faked environment, from which we
417 618
 		 * return to request processing, if marked to do so */
418
-		origin_rq=Trans->uas.request;
419
-		on_neg=Trans->on_negative;
420
-		if (on_neg) {
421
-			DBG("DBG: on_negative_reply processed for transaction %p\n", 
422
-					Trans);
423
-			if (faked_env(&faked_msg, Trans, Trans->uas.request, 
424
-									0 /* create fake */ )) 
425
-			{
426
-				/* use the faked message later in forwarding */
427
-				origin_rq=&faked_msg;
428
-	  		 	/* run a reply_route action if some was marked */
429
-				if (run_actions(reply_rlist[on_neg], &faked_msg )<0)
430
-					LOG(L_ERR, "ERROR: on_negative_reply: "
431
-						"Error in do_action\n");
432
-			} else { /* faked_env creation error */
433
-				LOG(L_ERR, "ERROR: on_negative_reply: faked_env failed\n");
434
-				on_neg=0;
435
-			} 
436
-		} /* if (on_neg) */
437
-
619
+		failure_route(Trans);
438 620
 
439 621
 		/* look if the callback perhaps replied transaction; it also
440 622
 		   covers the case in which a transaction is replied localy
... ...
@@ -450,34 +632,19 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
450 632
 			   put it on wait again; perhaps splitting put_on_wait
451 633
 			   from send_reply or a new RPS_ code would be healthy
452 634
 			*/
453
-			if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
454 635
 			return RPS_COMPLETED;
455 636
 		}
456
-		/* look if the callback introduced new branches ... */
457
-		init_branch_iterator();
458
-		if (next_branch(&dummy)) {
459
-			if (t_forward_nonack(Trans, origin_rq,
460
-						(struct proxy_l *) 0,
461
-						Trans->uas.response.dst.proto)<0) {
462
-				/* error ... behave as if we did not try to
463
-				   add a new branch */
464
-				*should_store=0;
465
-				*should_relay=lowest_b;
466
-				if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
467
-				return RPS_COMPLETED;
468
-			}
469
-			/* we succeded to launch new branches -- await
470
-			   result
471
-			*/
637
+		/* look if the callback/failure_route introduced new branches ... */
638
+		if (branch_cnt<Trans->nr_of_outgoings)  {
639
+			/* await then result of new branches */
472 640
 			*should_store=1;
473 641
 			*should_relay=-1;
474
-			if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
475 642
 			return RPS_STORE;
476 643
 		}
644
+
477 645
 		/* really no more pending branches -- return lowest code */
478 646
 		*should_store=0;
479
-		*should_relay=lowest_b;
480
-		if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
647
+		*should_relay=picked_branch;
481 648
 		/* we dont need 'which_cancel' here -- all branches 
482 649
 		   known to have completed */
483 650
 		/* which_cancel( Trans, cancel_bitmap ); */
... ...
@@ -496,6 +663,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
496 663
 		} else return RPS_PROVISIONAL;
497 664
 	}
498 665
 
666
+error:
499 667
 	/* reply_status didn't match -- it must be something weird */
500 668
 	LOG(L_CRIT, "ERROR: Oh my gooosh! We don't know whether to relay %d\n",
501 669
 		new_code);
... ...
@@ -567,150 +735,8 @@ int t_reply_unsafe( struct cell *t, struct sip_msg* p_msg, unsigned int code,
567 735
 }
568 736
 
569 737
 
570
-static inline void update_local_tags(struct cell *trans, 
571
-				struct bookmark *bm, char *dst_buffer,
572
-				char *src_buffer /* to which bm refers */)
573
-{
574
-	if (bm->to_tag_val.s) {
575
-		trans->uas.local_totag.s=bm->to_tag_val.s-src_buffer+dst_buffer;
576
-		trans->uas.local_totag.len=bm->to_tag_val.len;
577
-	}
578
-}
579
-
580
-
581
-static int _reply_light( struct cell *trans, char* buf, unsigned int len,
582
-			 unsigned int code, char * text, 
583
-			 char *to_tag, unsigned int to_tag_len, int lock,
584
-			 struct bookmark *bm	)
585
-{
586
-	struct retr_buf *rb;
587
-	unsigned int buf_len;
588
-	branch_bm_t cancel_bitmap;
589
-
590
-	if (!buf)
591
-	{
592
-		DBG("DEBUG: t_reply: response building failed\n");
593
-		/* determine if there are some branches to be cancelled */
594
-		if (trans->is_invite) {
595
-			if (lock) LOCK_REPLIES( trans );
596
-			which_cancel(trans, &cancel_bitmap );
597
-			if (lock) UNLOCK_REPLIES( trans );
598
-		}
599
-		/* and clean-up, including cancellations, if needed */
600
-		goto error;
601
-	}
602
-
603
-	cancel_bitmap=0;
604
-	if (lock) LOCK_REPLIES( trans );
605
-	if (trans->is_invite) which_cancel(trans, &cancel_bitmap );
606
-	if (trans->uas.status>=200) {
607
-		LOG( L_ERR, "ERROR: t_reply: can't generate %d reply"
608
-			" when a final %d was sent out\n", code, trans->uas.status);
609
-		goto error2;
610
-	}
611
-
612 738
 
613
-	rb = & trans->uas.response;
614
-	rb->activ_type=code;
615 739
 
616
-	trans->uas.status = code;
617
-	buf_len = rb->buffer ? len : len + REPLY_OVERBUFFER_LEN;
618
-	rb->buffer = (char*)shm_resize( rb->buffer, buf_len );
619
-	/* puts the reply's buffer to uas.response */
620
-	if (! rb->buffer ) {
621
-			LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n");
622
-			goto error3;
623
-	}
624
-	update_local_tags(trans, bm, rb->buffer, buf);
625
-
626
-	rb->buffer_len = len ;
627
-	memcpy( rb->buffer , buf , len );
628
-	/* needs to be protected too because what timers are set depends
629
-	   on current transactions status */
630
-	/* t_update_timers_after_sending_reply( rb ); */
631
-	update_reply_stats( code );
632
-	trans->relaied_reply_branch=-2;
633
-	tm_stats->replied_localy++;
634
-	if (lock) UNLOCK_REPLIES( trans );
635
-	
636
-	/* do UAC cleanup procedures in case we generated
637
-	   a final answer whereas there are pending UACs */
638
-	if (code>=200) {
639
-		if (trans->local) {
640
-			DBG("DEBUG: local transaction completed from _reply\n");
641
-			callback_event( TMCB_LOCAL_COMPLETED, trans, FAKED_REPLY, code );
642
-			if (trans->completion_cb) 
643
-				trans->completion_cb( trans, FAKED_REPLY, code, 0 /* empty param */);
644
-		} else {
645
-			callback_event( TMCB_RESPONSE_OUT, trans, FAKED_REPLY, code );
646
-		}
647
-
648
-		cleanup_uac_timers( trans );
649
-		if (trans->is_invite) cancel_uacs( trans, cancel_bitmap );
650
-		set_final_timer(  trans );
651
-	}
652
-
653
-	/* send it out */
654
-	/* first check if we managed to resolve topmost Via -- if
655
-	   not yet, don't try to retransmit
656
-	*/
657
-	if (!trans->uas.response.dst.send_sock) {
658
-		LOG(L_ERR, "ERROR: _reply: no resolved dst to send reply to\n");
659
-	} else {
660
-		SEND_PR_BUFFER( rb, buf, len );
661
-		DBG("DEBUG: reply sent out. buf=%p: %.9s..., shmem=%p: %.9s\n", 
662
-			buf, buf, rb->buffer, rb->buffer );
663
-	}
664
-	pkg_free( buf ) ;
665
-	DBG("DEBUG: t_reply: finished\n");
666
-	return 1;
667
-
668
-error3:
669
-error2:
670
-	if (lock) UNLOCK_REPLIES( trans );
671
-	pkg_free ( buf );
672
-error:
673
-	/* do UAC cleanup */
674
-	cleanup_uac_timers( trans );
675
-	if (trans->is_invite) cancel_uacs( trans, cancel_bitmap );
676
-	/* we did not succeed -- put the transaction on wait */
677
-	put_on_wait(trans);
678
-	return -1;
679
-}
680
-
681
-/* send a UAS reply
682
- * returns 1 if everything was OK or -1 for error
683
- */
684
-static int _reply( struct cell *trans, struct sip_msg* p_msg, 
685
-	unsigned int code, char * text, int lock )
686
-{
687
-	unsigned int len;
688
-	char * buf;
689
-	struct bookmark bm;
690
-
691
-	if (code>=200) set_kr(REQ_RPLD);
692
-	/* compute the buffer in private memory prior to entering lock;
693
-	 * create to-tag if needed */
694
-	if (code>=180 && p_msg->to 
695
-				&& (get_to(p_msg)->tag_value.s==0 
696
-			    || get_to(p_msg)->tag_value.len==0)) {
697
-		calc_crc_suffix( p_msg, tm_tag_suffix );
698
-		buf = build_res_buf_from_sip_req(code,text, 
699
-				tm_tags, TOTAG_VALUE_LEN, 
700
-				p_msg,&len, &bm);
701
-
702
-		return _reply_light(trans,buf,len,code,text,
703
-				    tm_tags, TOTAG_VALUE_LEN,
704
-				    lock, &bm);
705
-	} else {
706
-		buf = build_res_buf_from_sip_req(code,text, 0,0, /* no to-tag */
707
-			p_msg,&len, &bm);
708
-
709
-		return _reply_light(trans,buf,len,code,text,
710
-				    0,0, /* no to-tag */
711
-				    lock, &bm);
712
-	}
713
-}
714 740
 
715 741
 void set_final_timer( /* struct s_table *h_table, */ struct cell *t )
716 742
 {
... ...
@@ -1017,7 +1043,7 @@ error:
1017 1043
   *  Returns :   0 - core router stops
1018 1044
   *              1 - core router relay statelessly
1019 1045
   */
1020
-int t_on_reply( struct sip_msg  *p_msg )
1046
+int reply_received( struct sip_msg  *p_msg )
1021 1047
 {
1022 1048
 
1023 1049
 	int msg_status;
... ...
@@ -1068,6 +1094,13 @@ int t_on_reply( struct sip_msg  *p_msg )
1068 1094
 	if ( msg_status >= 200 )
1069 1095
 		reset_timer( &uac->request.fr_timer);
1070 1096
 
1097
+	/* processing of on_reply block */
1098
+	if (t->on_reply) {
1099
+		rmode=MODE_ONREPLY;
1100
+	 	if (run_actions(onreply_rlist[t->on_reply], p_msg)<0) 
1101
+			LOG(L_ERR, "ERROR: on_reply processing failed\n");
1102
+	}
1103
+
1071 1104
 	LOCK_REPLIES( t );
1072 1105
 	if (t->local) {
1073 1106
 		reply_status=local_reply( t, p_msg, branch, msg_status, &cancel_bitmap );
... ...
@@ -51,7 +51,7 @@ enum rps {
51 51
 	RPS_PROVISIONAL
52 52
 };
53 53
 
54
-enum route_mode { MODE_REQUEST=1, MODE_ONREPLY_REQUEST };
54
+enum route_mode { MODE_REQUEST=1, MODE_ONREPLY, MODE_ONFAILURE };
55 55
 extern enum route_mode rmode;
56 56
 
57 57
 /* has this to-tag been never seen in previous 200/INVs? */
... ...
@@ -74,7 +74,7 @@ typedef int (*treply_wb_f)( struct cell* trans,
74 74
  * Returns :   0 - core router stops
75 75
  *             1 - core router relay statelessly
76 76
  */
77
-int t_on_reply( struct sip_msg  *p_msg ) ;
77
+int reply_received( struct sip_msg  *p_msg ) ;
78 78
 
79 79
 
80 80
 /* Retransmits the last sent inbound reply.
... ...
@@ -126,8 +126,10 @@ void on_negative_reply( struct cell* t, struct sip_msg* msg,
126 126
 /* set which 'reply' structure to take if only negative
127 127
    replies arrive 
128 128
 */
129
-int t_on_negative( unsigned int go_to );
129
+void t_on_negative( unsigned int go_to );
130 130
 unsigned int get_on_negative();
131
+void t_on_reply( unsigned int go_to );
132
+unsigned int get_on_reply();
131 133
 
132 134
 int t_retransmit_reply( struct cell *t );
133 135
 
... ...
@@ -62,6 +62,7 @@
62 62
  *  2003-03-16  flags export parameter added (janakj)
63 63
  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
64 64
  *  2003-03-30  set_kr for requests only (jiri)
65
+ *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
65 66
  */
66 67
 
67 68
 
... ...
@@ -125,6 +126,7 @@ inline static int w_t_forward_nonack_udp(struct sip_msg* msg, char* str,char*);
125 126
 inline static int w_t_forward_nonack_tcp(struct sip_msg* msg, char* str,char*);
126 127
 inline static int fixup_hostport2proxy(void** param, int param_no);
127 128
 inline static int w_t_on_negative( struct sip_msg* msg, char *go_to, char *foo );
129
+inline static int w_t_on_reply( struct sip_msg* msg, char *go_to, char *foo );
128 130
 
129 131
 
130 132
 static int mod_init(void);
... ...
@@ -135,23 +137,29 @@ static int child_init(int rank);
135 137
 static cmd_export_t cmds[]={
136 138
 	{"t_newtran",          w_t_newtran,             0, 0,                    REQUEST_ROUTE},
137 139
 	{"t_lookup_request",   w_t_check,               0, 0,                    REQUEST_ROUTE},
138
-	{T_REPLY,              w_t_reply,               2, fixup_t_send_reply,   REQUEST_ROUTE},
140
+	{T_REPLY,              w_t_reply,               2, fixup_t_send_reply,   
141
+			REQUEST_ROUTE | FAILURE_ROUTE },
139 142
 	{"t_retransmit_reply", w_t_retransmit_reply,    0, 0,                    REQUEST_ROUTE},
140 143
 	{"t_release",          w_t_release,             0, 0,                    REQUEST_ROUTE},
141
-	{T_RELAY_TO,           w_t_relay_to,            2, fixup_hostport2proxy, REQUEST_ROUTE},
144
+	{T_RELAY_TO,           w_t_relay_to,            2, fixup_hostport2proxy, 
145
+			REQUEST_ROUTE | FAILURE_ROUTE },
142 146
 	{T_RELAY_TO_UDP,       w_t_relay_to_udp,        2, fixup_hostport2proxy, REQUEST_ROUTE},
143 147
 	{T_RELAY_TO_TCP,       w_t_relay_to_tcp,        2, fixup_hostport2proxy, REQUEST_ROUTE},
144 148
 	{"t_replicate",        w_t_replicate,           2, fixup_hostport2proxy, REQUEST_ROUTE},
145 149
 	{"t_replicate_udp",    w_t_replicate_udp,       2, fixup_hostport2proxy, REQUEST_ROUTE},
146 150
 	{"t_replicate_tcp",    w_t_replicate_tcp,       2, fixup_hostport2proxy, REQUEST_ROUTE},
147
-	{T_RELAY,              w_t_relay,               0, 0,                    REQUEST_ROUTE},
151
+	{T_RELAY,              w_t_relay,               0, 0,                    
152
+			REQUEST_ROUTE | FAILURE_ROUTE },
148 153
 	{T_RELAY_UDP,          w_t_relay_udp,           0, 0,                    REQUEST_ROUTE},
149 154
 	{T_RELAY_TCP,          w_t_relay_tcp,           0, 0,                    REQUEST_ROUTE},
150 155
 	{T_FORWARD_NONACK,     w_t_forward_nonack,      2, fixup_hostport2proxy, REQUEST_ROUTE},
151 156
 	{T_FORWARD_NONACK_UDP, w_t_forward_nonack_udp,  2, fixup_hostport2proxy, REQUEST_ROUTE},
152 157
 	{T_FORWARD_NONACK_TCP, w_t_forward_nonack_tcp,  2, fixup_hostport2proxy, REQUEST_ROUTE},
153
-	{"t_on_negative",      w_t_on_negative,         1, fixup_str2int,        REQUEST_ROUTE},
154
-	/* not applicable from the script -- ugly hack */
158
+	{"t_on_failure",       w_t_on_negative,         1, fixup_str2int,
159
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
160
+	{"t_on_reply",         w_t_on_reply,            1, fixup_str2int,
161
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
162
+	/* not applicable from the script */
155 163
 	{"register_tmcb",      (cmd_function)register_tmcb,     NO_SCRIPT,     0, 0},
156 164
 	{T_UAC_DLG,            (cmd_function)t_uac_dlg,         NO_SCRIPT,     0, 0},
157 165
 	{"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,     0, 0},
... ...
@@ -191,7 +199,7 @@ struct module_exports exports= {
191 199
 	params,
192 200
 	
193 201
 	mod_init, /* module initialization function */
194
-	(response_function) t_on_reply,
202
+	(response_function) reply_received,
195 203
 	(destroy_function) tm_shutdown,
196 204
 	0, /* w_onbreak, */
197 205
 	child_init /* per-child init function */
... ...
@@ -234,9 +242,12 @@ static int script_init( struct sip_msg *foo, void *bar)
234 242
 	   		message's t_on_negative value
235 243
 		*/
236 244
 		t_on_negative( 0 );
237
-
245
+		t_on_reply(0);
238 246
 		/* reset the kr status */
239 247
 		set_kr(0);
248
+		/* set request mode so that multiple-mode actions know
249
+		 * how to behave */
250
+		rmode=MODE_REQUEST;
240 251
 	}
241 252
 
242 253
 	return 1;
... ...
@@ -456,11 +467,14 @@ inline static int w_t_reply(struct sip_msg* msg, char* str, char* str2)
456 467
 	 * is called; we are already in a mutex and another mutex in
457 468
 	 * the safe version would lead to a deadlock
458 469
 	 */
459
-	if (rmode==MODE_ONREPLY_REQUEST) { 
470
+	if (rmode==MODE_ONFAILURE) { 
460 471
 		DBG("DEBUG: t_reply_unsafe called from w_t_reply\n");
461 472
 		return t_reply_unsafe(t, msg, (unsigned int)(long) str, str2);
462
-	} else {
473
+	} else if (rmode==MODE_REQUEST) {
463 474
 		return t_reply( t, msg, (unsigned int)(long) str, str2);
475
+	} else {
476
+		LOG(L_CRIT, "BUG: w_t_reply entered in unsupported mode\n");
477
+		return -1;
464 478
 	}
465 479
 }
466 480
 
... ...
@@ -516,15 +530,74 @@ inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar )
516 530
 
517 531
 inline static int w_t_on_negative( struct sip_msg* msg, char *go_to, char *foo )
518 532
 {
519
-	return t_on_negative( (unsigned int )(long) go_to );
533
+	struct cell *t;
534
+
535
+	if (rmode==MODE_REQUEST || rmode==MODE_ONFAILURE) {
536
+		t_on_negative( (unsigned int )(long) go_to );
537
+		return 1;
538
+	}
539
+	if (rmode==MODE_ONREPLY ) {
540
+		/* transaction state is established */
541
+		t=get_t();
542
+		if (!t || t==T_UNDEFINED) {
543
+			LOG(L_CRIT, "BUG: w_t_on_negative entered without t\n");
544
+			return -1;
545
+		}
546
+		t->on_negative=(unsigned int)(long)go_to;
547
+		return 1;
548
+	}
549
+	LOG(L_CRIT, "BUG: w_t_on_negative entered in unsupported mode\n");
550
+	return -1;
551
+}
552
+inline static int w_t_on_reply( struct sip_msg* msg, char *go_to, char *foo )
553
+{
554
+	struct cell *t;
555
+
556
+	if (rmode==MODE_REQUEST) {
557
+		/* it's still in initial request processing stage, transaction
558
+		 * state is not estabslihed yet, store it in private memory ...
559
+		 * it will be copied to transaction state when it is set up */
560
+		t_on_reply( (unsigned int )(long) go_to );
561
+		return 1;
562
+	}
563
+	if (rmode==MODE_ONREPLY || rmode==MODE_ONFAILURE) {
564
+		/* transaction state is established */
565
+		t=get_t();
566
+		if (!t || t==T_UNDEFINED) {
567
+			LOG(L_CRIT, "BUG: w_t_on_reply entered without t\n");
568
+			return -1;
569
+		}
570
+		t->on_reply=(unsigned int) (long)go_to;
571
+		return 1;
572
+	}
573
+	LOG(L_CRIT, "BUG: w_t_on_reply entered in unsupported mode\n");
574
+	return -1;
520 575
 }
521 576
 
522 577
 inline static int w_t_relay_to( struct sip_msg  *p_msg , 
523 578
 	char *proxy, /* struct proxy_l *proxy expected */
524 579
 	char *_foo       /* nothing expected */ )
525 580
 {
526
-	return t_relay_to( p_msg, ( struct proxy_l *) proxy, p_msg->rcv.proto,
527
-	0 /* no replication */ );
581
+	struct cell *t;
582
+
583
+	if (rmode==MODE_ONFAILURE) { 
584
+		t=get_t();
585
+		if (!t || t==T_UNDEFINED) {
586
+			LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n");
587
+			return -1;
588
+		}
589
+		if (t_forward_nonack(t, p_msg, 
590
+				( struct proxy_l *) proxy, p_msg->rcv.proto)<=0 ) {
591
+			LOG(L_ERR, "ERROR: failure_route: t_relay_to failed\n");
592
+			return -1;
593
+		}
594
+		return 1;
595
+	}
596
+	if (rmode==MODE_REQUEST) 
597
+		return t_relay_to( p_msg, ( struct proxy_l *) proxy, p_msg->rcv.proto,
598
+			0 /* no replication */ );
599
+	LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
600
+	return 0;
528 601
 }
529 602
 
530 603
 inline static int w_t_relay_to_udp( struct sip_msg  *p_msg , 
... ...
@@ -571,9 +644,26 @@ inline static int w_t_replicate_tcp( struct sip_msg  *p_msg ,
571 644
 inline static int w_t_relay( struct sip_msg  *p_msg , 
572 645
 						char *_foo, char *_bar)
573 646
 {
574
-	return t_relay_to( p_msg, 
647
+	struct cell *t;
648
+
649
+	if (rmode==MODE_ONFAILURE) { 
650
+		t=get_t();
651
+		if (!t || t==T_UNDEFINED) {
652
+			LOG(L_CRIT, "BUG: w_t_relay: undefined T\n");
653
+			return -1;
654
+		} 
655
+		if (t_forward_nonack(t, p_msg, ( struct proxy_l *) 0, p_msg->rcv.proto)<=0) {
656
+			LOG(L_ERR, "ERROR: w_t_relay (failure mode): forwarding failed\n");
657
+			return -1;
658
+		}
659
+		return 1;
660
+	}
661
+	if (rmode==MODE_REQUEST) 
662
+		return t_relay_to( p_msg, 
575 663
 		(struct proxy_l *) 0 /* no proxy */, p_msg->rcv.proto,
576 664
 		0 /* no replication */ );
665
+	LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
666
+	return 0;
577 667
 }
578 668
 
579 669
 
... ...
@@ -322,6 +322,9 @@ int t_uac_dlg(str* msg,                     /* Type of the message - MESSAGE, OP
322 322
 				|| !to || !to->s ) {
323 323
 		LOG(L_ERR, "ERROR: t_uac_dlg: invalid parameters\n");
324 324
 		ser_error = ret = E_INVALID_PARAMS;
325
+#ifdef XL_DEBUG
326
+		abort();
327
+#endif
325 328
 		goto done;
326 329
 	}
327 330
 
... ...
@@ -35,6 +35,7 @@
35 35
  *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
36 36
  *  2003-04-01  added dst_port, proto, af; renamed comp_port to comp_no,
37 37
  *               inlined all the comp_* functions (andrei)
38
+ *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
38 39
  */
39 40
 
40 41
  
... ...
@@ -63,7 +64,8 @@
63 64
 /* main routing script table  */
64 65
 struct action* rlist[RT_NO];
65 66
 /* reply routing table */
66
-struct action* reply_rlist[REPLY_RT_NO];
67
+struct action* onreply_rlist[ONREPLY_RT_NO];
68
+struct action* failure_rlist[FAILURE_RT_NO];
67 69
 
68 70
 
69 71
 static int fix_actions(struct action* a); /*fwd declaration*/
... ...
@@ -559,9 +561,16 @@ int fix_rls()
559 561
 			}
560 562
 		}
561 563
 	}
562
-	for(i=0;i<REPLY_RT_NO;i++){
563
-		if(reply_rlist[i]){
564
-			if ((ret=fix_actions(reply_rlist[i]))!=0){
564
+	for(i=0;i<ONREPLY_RT_NO;i++){
565
+		if(onreply_rlist[i]){
566
+			if ((ret=fix_actions(onreply_rlist[i]))!=0){
567
+				return ret;
568
+			}
569
+		}
570
+	}
571
+	for(i=0;i<FAILURE_RT_NO;i++){
572
+		if(failure_rlist[i]){
573
+			if ((ret=fix_actions(failure_rlist[i]))!=0){
565 574
 				return ret;
566 575
 			}
567 576
 		}
... ...
@@ -587,13 +596,22 @@ void print_rl()
587 596
 		}
588 597
 		DBG("\n");
589 598
 	}
590
-	for(j=0; j<REPLY_RT_NO; j++){
591
-		if (reply_rlist[j]==0){
592
-			if (j==0) DBG("WARNING: the main reply routing table is empty\n");
599
+	for(j=0; j<ONREPLY_RT_NO; j++){
600
+		if (onreply_rlist[j]==0){
593 601
 			continue;
594 602
 		}
595
-		DBG("routing table %d:\n",j);
596
-		for (t=reply_rlist[j],i=0; t; i++, t=t->next){
603
+		DBG("onreply routing table %d:\n",j);
604
+		for (t=onreply_rlist[j],i=0; t; i++, t=t->next){
605
+			print_action(t);
606
+		}
607
+		DBG("\n");
608
+	}
609
+	for(j=0; j<FAILURE_RT_NO; j++){
610
+		if (failure_rlist[j]==0){
611
+			continue;
612
+		}
613
+		DBG("failure routing table %d:\n",j);
614
+		for (t=failure_rlist[j],i=0; t; i++, t=t->next){
597 615
 			print_action(t);
598 616
 		}
599 617
 		DBG("\n");
... ...
@@ -44,7 +44,8 @@
44 44
 /* main "script table" */
45 45
 extern struct action* rlist[RT_NO];
46 46
 /* main reply route table */
47
-extern struct action* reply_rlist[RT_NO];
47
+extern struct action* onreply_rlist[RT_NO];
48
+extern struct action* failure_rlist[RT_NO];
48 49
 
49 50
 
50 51
 void push(struct action* a, struct action** head);
... ...
@@ -32,6 +32,7 @@
32 32
  *  2003-03-10  changed module exports interface: added struct cmd_export
33 33
  *               and param_export (andrei)
34 34
  *  2003-03-16  Added flags field to cmd_export_ (janakj)
35
+ *  2003-04-05  s/reply_route/failure_route, onreply_route introduced (jiri)
35 36
  */
36 37
 
37 38
 
... ...
@@ -55,8 +56,9 @@ typedef enum {
55 56
 	INT_PARAM,  /* Integer parameter type */
56 57
 } modparam_t;       /* Allowed types of parameters */
57 58
 
58
-#define REQUEST_ROUTE 1         /* Function can be used in request route blocks */
59
-#define REPLY_ROUTE 2           /* Function can be used in reply route blocks */
59
+#define REQUEST_ROUTE 1  /* Function can be used in request route blocks */
60
+#define FAILURE_ROUTE 2  /* Function can be used in reply route blocks */
61
+#define ONREPLY_ROUTE 4  /* Function can be used in on_reply */
60 62
 
61 63
 /* Macros - used as rank in child_init function */
62 64
 #define PROC_MAIN      0  /* Main ser process */