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 47
 core
48 48
 ----
49 49
 XXX TCP
50
+- reply_route has been renamed to failure_route -- the old name caused
51
+  too much confusion
50 52
 
51 53
 acc module:
52 54
 -----------
... ...
@@ -94,4 +99,26 @@ tm module:
94 94
 ----------
95 95
 - t_reply_unsafe, used in former versions within reply_routes,
96 96
   is deprecated; now t_reply is used from any places in script
97
-- XXX t_uac/FIFO
97
+- t_on_negative is renamed to t_on_failure -- the old name just
98
+  caused too much confusion
99
+- FIFO t_uac used by some applications (like serweb) has been
100
+  replaced with t_uac_dlg (which allows easier use by dialog-
101
+  oriented applications, like click-to-dial) 
102
+- if you wish to do forward to another destination from 
103
+  failure_route (reply_route formerly), you need to call t_relay
104
+  or t_relay_to explicitely now
105
+
106
+List of new modules:
107
+--------------------
108
+- dbtext -- flat-file database
109
+- domain -- automated domain management
110
+- enum -- ENUM support
111
+- nathelper -- utility for NAT traversal for Cisco ATAs
112
+- pa -- presence agent
113
+- permissions -- ACLs
114
+- vm -- voicemail interface
115
+
116
+List of deprecated modules:
117
+---------------------------
118
+- im (t_uac_dlg is used for sending messages)
119
+- 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 78
 LOG		log
79 79
 ERROR	error
80 80
 ROUTE	route
81
-REPL_ROUTE reply_route
81
+FAILURE_ROUTE failure_route
82
+ONREPLY_ROUTE onreply_route
82 83
 EXEC	exec
83 84
 SETFLAG		setflag
84 85
 RESETFLAG	resetflag
... ...
@@ -106,7 +108,11 @@ MAX_LEN			"max_len"
106 106
 
107 107
 /* condition keywords */
108 108
 METHOD	method
109
-URI		uri
109
+/* hack -- the second element in first line is referrable
110
+   as either uri or status; it only would makes sense to
111
+   call it "uri" from route{} and status from onreply_route{}
112
+*/
113
+URI		"uri"|"status"
110 114
 SRCIP	src_ip
111 115
 SRCPORT	src_port
112 116
 DSTIP	dst_ip
... ...
@@ -206,7 +212,8 @@ EAT_ABLE	[\ \t\b\r]
206 206
 <INITIAL>{ISFLAGSET}	{ count(); yylval.strval=yytext; return ISFLAGSET; }
207 207
 <INITIAL>{LEN_GT}	{ count(); yylval.strval=yytext; return LEN_GT; }
208 208
 <INITIAL>{ROUTE}	{ count(); yylval.strval=yytext; return ROUTE; }
209
-<INITIAL>{REPL_ROUTE}	{ count(); yylval.strval=yytext; return REPL_ROUTE; }
209
+<INITIAL>{ONREPLY_ROUTE}	{ count(); yylval.strval=yytext; return ONREPLY_ROUTE; }
210
+<INITIAL>{FAILURE_ROUTE}	{ count(); yylval.strval=yytext; return FAILURE_ROUTE; }
210 211
 <INITIAL>{EXEC}	{ count(); yylval.strval=yytext; return EXEC; }
211 212
 <INITIAL>{SET_HOST}	{ count(); yylval.strval=yytext; return SET_HOST; }
212 213
 <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 106
 %token LOG_TOK
107 107
 %token ERROR
108 108
 %token ROUTE
109
-%token REPL_ROUTE
109
+%token FAILURE_ROUTE
110
+%token ONREPLY_ROUTE
110 111
 %token EXEC
111 112
 %token SET_HOST
112 113
 %token SET_HOSTPORT
... ...
@@ -221,7 +223,8 @@ statements:	statements statement {}
221 221
 statement:	assign_stm 
222 222
 		| module_stm
223 223
 		| {rt=REQUEST_ROUTE;} route_stm 
224
-		| {rt=REPLY_ROUTE;} reply_route_stm
224
+		| {rt=FAILURE_ROUTE;} failure_route_stm
225
+		| {rt=ONREPLY_ROUTE;} onreply_route_stm
225 226
 
226 227
 		| CR	/* null statement*/
227 228
 	;
... ...
@@ -463,15 +466,26 @@ route_stm:  ROUTE LBRACE actions RBRACE { push($3, &rlist[DEFAULT_RT]); }
463 463
 		| ROUTE error { yyerror("invalid  route  statement"); }
464 464
 	;
465 465
 
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]);
466
+failure_route_stm: FAILURE_ROUTE LBRACK NUMBER RBRACK LBRACE actions RBRACE {
467
+										if (($3<FAILURE_RT_NO)&&($3>=1)){
468
+											push($6, &failure_rlist[$3]);
469 469
 										} else {
470 470
 											yyerror("invalid reply routing"
471 471
 												"table number");
472 472
 											YYABORT; }
473 473
 										}
474
-		| REPL_ROUTE error { yyerror("invalid reply_route statement"); }
474
+		| FAILURE_ROUTE error { yyerror("invalid failure_route statement"); }
475
+	;
476
+
477
+onreply_route_stm: ONREPLY_ROUTE LBRACK NUMBER RBRACK LBRACE actions RBRACE {
478
+										if (($3<ONREPLY_RT_NO)&&($3>=1)){
479
+											push($6, &onreply_rlist[$3]);
480
+										} else {
481
+											yyerror("invalid reply routing"
482
+												"table number");
483
+											YYABORT; }
484
+										}
485
+		| ONREPLY_ROUTE error { yyerror("invalid failure_route statement"); }
475 486
 	;
476 487
 /*
477 488
 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 414
 	   is in additional branches (which may be continuously refilled
415 415
 	*/
416 416
 	if (first_branch==0) {
417
+		try_new=1;
417 418
 		branch_ret=add_uac( t, p_msg, &GET_RURI(p_msg), &GET_NEXT_HOP(p_msg), proxy, proto );
418 419
 		if (branch_ret>=0) 
419 420
 			added_branches |= 1<<branch_ret;
420 421
 		else
421 422
 			lowest_ret=branch_ret;
422
-	}
423
+	} else try_new=0;
423 424
 
424 425
 	init_branch_iterator();
425 426
 	while((current_uri.s=next_branch( &current_uri.len))) {
427
+		try_new++;
426 428
 		branch_ret=add_uac( t, p_msg, &current_uri, 
427 429
 				    (p_msg->dst_uri.len) ? (&p_msg->dst_uri) : &current_uri, 
428 430
 				    proxy, proto);
... ...
@@ -444,10 +447,19 @@ int t_forward_nonack( struct cell *t, struct sip_msg* p_msg ,
444 444
 	/* don't forget to clear all branches processed so far */
445 445
 
446 446
 	/* things went wrong ... no new branch has been fwd-ed at all */
447
-	if (added_branches==0)
447
+	if (added_branches==0) {
448
+		if (try_new==0) {
449
+			LOG(L_ERR, "ERROR: t_forward_nonack: no branched for fwding\n");
450
+			return -1;
451
+		}
452
+		LOG(L_ERR, "ERROR: t_forward_nonack: failure to add branches\n");
448 453
 		return lowest_ret;
454
+	}
449 455
 
450
-	/* if someone set on_negative, store in in T-context */
456
+	/* store script processing value of failure route to transactional
457
+	   context; if currently 0, this forwarding attempt will no longer 
458
+	   result in failure_route on error
459
+	*/
451 460
 	t->on_negative=get_on_negative();
452 461
 
453 462
 	/* 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 1023
 
1024 1024
 				new_cell->method=new_cell->uas.request->first_line.u.request.method;
1025 1025
 				new_cell->is_invite=p_msg->REQ_METHOD==METHOD_INVITE;
1026
+				new_cell->on_negative=get_on_negative();
1027
+				new_cell->on_reply=get_on_reply();
1026 1028
 
1027 1029
 			}
1028 1030
 
... ...
@@ -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 82
 
83 83
 /* where to go if there is no positive reply */
84 84
 static int goto_on_negative=0;
85
+/* where to go on receipt of reply */
86
+static int goto_on_reply=0;
85 87
 
86 88
 
87 89
 /* we store the reply_route # in private memory which is
... ...
@@ -94,10 +97,14 @@ static int goto_on_negative=0;
94 94
 */
95 95
   
96 96
   
97
-int t_on_negative( unsigned int go_to )
97
+void t_on_negative( unsigned int go_to )
98 98
 {
99 99
 	goto_on_negative=go_to;
100
-	return 1;
100
+}
101
+
102
+void t_on_reply( unsigned int go_to )
103
+{
104
+	goto_on_reply=go_to;
101 105
 }
102 106
 
103 107
 
... ...
@@ -105,6 +112,10 @@ unsigned int get_on_negative()
105 105
 {
106 106
 	return goto_on_negative;
107 107
 }
108
+unsigned int get_on_reply()
109
+{
110
+	return goto_on_reply;
111
+}
108 112
 
109 113
 void tm_init_tags()
110 114
 {
... ...
@@ -141,6 +152,16 @@ int unmatched_totag(struct cell *t, struct sip_msg *ack)
141 141
 	return 1;
142 142
 }
143 143
 
144
+static inline void update_local_tags(struct cell *trans, 
145
+				struct bookmark *bm, char *dst_buffer,
146
+				char *src_buffer /* to which bm refers */)
147
+{
148
+	if (bm->to_tag_val.s) {
149
+		trans->uas.local_totag.s=bm->to_tag_val.s-src_buffer+dst_buffer;
150
+		trans->uas.local_totag.len=bm->to_tag_val.len;
151
+	}
152
+}
153
+
144 154
 
145 155
 /* append a newly received tag from a 200/INVITE to 
146 156
  * 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 213
         ACK, ACK_LEN, &to );
214 214
 }
215 215
 
216
+static int _reply_light( struct cell *trans, char* buf, unsigned int len,
217
+			 unsigned int code, char * text, 
218
+			 char *to_tag, unsigned int to_tag_len, int lock,
219
+			 struct bookmark *bm	)
220
+{
221
+	struct retr_buf *rb;
222
+	unsigned int buf_len;
223
+	branch_bm_t cancel_bitmap;
224
+
225
+	if (!buf)
226
+	{
227
+		DBG("DEBUG: t_reply: response building failed\n");
228
+		/* determine if there are some branches to be cancelled */
229
+		if (trans->is_invite) {
230
+			if (lock) LOCK_REPLIES( trans );
231
+			which_cancel(trans, &cancel_bitmap );
232
+			if (lock) UNLOCK_REPLIES( trans );
233
+		}
234
+		/* and clean-up, including cancellations, if needed */
235
+		goto error;
236
+	}
237
+
238
+	cancel_bitmap=0;
239
+	if (lock) LOCK_REPLIES( trans );
240
+	if (trans->is_invite) which_cancel(trans, &cancel_bitmap );
241
+	if (trans->uas.status>=200) {
242
+		LOG( L_ERR, "ERROR: t_reply: can't generate %d reply"
243
+			" when a final %d was sent out\n", code, trans->uas.status);
244
+		goto error2;
245
+	}
246
+
247
+
248
+	rb = & trans->uas.response;
249
+	rb->activ_type=code;
250
+
251
+	trans->uas.status = code;
252
+	buf_len = rb->buffer ? len : len + REPLY_OVERBUFFER_LEN;
253
+	rb->buffer = (char*)shm_resize( rb->buffer, buf_len );
254
+	/* puts the reply's buffer to uas.response */
255
+	if (! rb->buffer ) {
256
+			LOG(L_ERR, "ERROR: t_reply: cannot allocate shmem buffer\n");
257
+			goto error3;
258
+	}
259
+	update_local_tags(trans, bm, rb->buffer, buf);
260
+
261
+	rb->buffer_len = len ;
262
+	memcpy( rb->buffer , buf , len );
263
+	/* needs to be protected too because what timers are set depends
264
+	   on current transactions status */
265
+	/* t_update_timers_after_sending_reply( rb ); */
266
+	update_reply_stats( code );
267
+	trans->relaied_reply_branch=-2;
268
+	tm_stats->replied_localy++;
269
+	if (lock) UNLOCK_REPLIES( trans );
270
+	
271
+	/* do UAC cleanup procedures in case we generated
272
+	   a final answer whereas there are pending UACs */
273
+	if (code>=200) {
274
+		if (trans->local) {
275
+			DBG("DEBUG: local transaction completed from _reply\n");
276
+			callback_event( TMCB_LOCAL_COMPLETED, trans, FAKED_REPLY, code );
277
+			if (trans->completion_cb) 
278
+				trans->completion_cb( trans, FAKED_REPLY, code, 0 /* empty param */);
279
+		} else {
280
+			callback_event( TMCB_RESPONSE_OUT, trans, FAKED_REPLY, code );
281
+		}
282
+
283
+		cleanup_uac_timers( trans );
284
+		if (trans->is_invite) cancel_uacs( trans, cancel_bitmap );
285
+		set_final_timer(  trans );
286
+	}
287
+
288
+	/* send it out */
289
+	/* first check if we managed to resolve topmost Via -- if
290
+	   not yet, don't try to retransmit
291
+	*/
292
+	if (!trans->uas.response.dst.send_sock) {
293
+		LOG(L_ERR, "ERROR: _reply: no resolved dst to send reply to\n");
294
+	} else {
295
+		SEND_PR_BUFFER( rb, buf, len );
296
+		DBG("DEBUG: reply sent out. buf=%p: %.9s..., shmem=%p: %.9s\n", 
297
+			buf, buf, rb->buffer, rb->buffer );
298
+	}
299
+	pkg_free( buf ) ;
300
+	DBG("DEBUG: t_reply: finished\n");
301
+	return 1;
302
+
303
+error3:
304
+error2:
305
+	if (lock) UNLOCK_REPLIES( trans );
306
+	pkg_free ( buf );
307
+error:
308
+	/* do UAC cleanup */
309
+	cleanup_uac_timers( trans );
310
+	if (trans->is_invite) cancel_uacs( trans, cancel_bitmap );
311
+	/* we did not succeed -- put the transaction on wait */
312
+	put_on_wait(trans);
313
+	return -1;
314
+}
315
+
316
+
317
+/* send a UAS reply
318
+ * returns 1 if everything was OK or -1 for error
319
+ */
320
+static int _reply( struct cell *trans, struct sip_msg* p_msg, 
321
+	unsigned int code, char * text, int lock )
322
+{
323
+	unsigned int len;
324
+	char * buf;
325
+	struct bookmark bm;
326
+
327
+	if (code>=200) set_kr(REQ_RPLD);
328
+	/* compute the buffer in private memory prior to entering lock;
329
+	 * create to-tag if needed */
330
+	if (code>=180 && p_msg->to 
331
+				&& (get_to(p_msg)->tag_value.s==0 
332
+			    || get_to(p_msg)->tag_value.len==0)) {
333
+		calc_crc_suffix( p_msg, tm_tag_suffix );
334
+		buf = build_res_buf_from_sip_req(code,text, 
335
+				tm_tags, TOTAG_VALUE_LEN, 
336
+				p_msg,&len, &bm);
337
+
338
+		return _reply_light(trans,buf,len,code,text,
339
+				    tm_tags, TOTAG_VALUE_LEN,
340
+				    lock, &bm);
341
+	} else {
342
+		buf = build_res_buf_from_sip_req(code,text, 0,0, /* no to-tag */
343
+			p_msg,&len, &bm);
344
+
345
+		return _reply_light(trans,buf,len,code,text,
346
+				    0,0, /* no to-tag */
347
+				    lock, &bm);
348
+	}
349
+}
350
+
216 351
 
217 352
 /* create a temporary faked message environment in which a conserved
218 353
  * t->uas.request in shmem is partially duplicated to pkgmem
... ...
@@ -257,7 +413,7 @@ static int faked_env(struct sip_msg *fake,
257 257
 	 * for example t_reply needs to know that
258 258
 	 */
259 259
 	backup_mode=rmode;
260
-	rmode=MODE_ONREPLY_REQUEST;
260
+	rmode=MODE_ONFAILURE;
261 261
 	/* also, tm actions look in beginning whether tranaction is
262 262
 	 * set -- whether we are called from a reply-processing 
263 263
 	 * or a timer process, we need to set current transaction;
... ...
@@ -309,11 +465,68 @@ restore:
309 309
 	return 0;
310 310
 }
311 311
 
312
+/* return 1 if a failure_route processes */
313
+int failure_route(struct cell *t)
314
+{
315
+	struct sip_msg faked_msg;
316
+
317
+	/* don't do anything if we don't have to */
318
+	if (!t->on_negative) return 0;
319
+
320
+	/* if fake message creation failes, return error too */
321
+	if (!faked_env(&faked_msg, t, t->uas.request, 0 /* create fake */ )) {
322
+		LOG(L_ERR, "ERROR: on_negative_reply: faked_env failed\n");
323
+		return 0;
324
+	}
325
+
326
+	/* avoid recursion -- if failure_route forwards, and does not 
327
+	 * set next failure route, failure_route will not be rentered
328
+	 * on failure */
329
+	t_on_negative(0);
330
+	/* run a reply_route action if some was marked */
331
+	if (run_actions(failure_rlist[t->on_negative], &faked_msg)<0)
332
+		LOG(L_ERR, "ERROR: on_negative_reply: "
333
+			"Error in do_action\n");
334
+	/* restore original environment */
335
+	faked_env(&faked_msg, 0, 0, 1 );
336
+	return 1;
337
+}
312 338
 
313 339
 
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 );
340
+/* select a branch for forwarding; returns:
341
+ * 0..X ... branch number
342
+ * -1   ... error
343
+ * -2   ... can't decide yet -- incomplete branches present
344
+ */
345
+static int pick_branch( int inc_branch, int inc_code, 
346
+			struct cell *t, int *res_code)
347
+{
348
+	int lowest_b, lowest_s, b;
349
+
350
+	lowest_b=-1; lowest_s=999;
351
+	for ( b=0; b<t->nr_of_outgoings ; b++ ) {
352
+		/* "fake" for the currently processed branch */
353
+		if (b==inc_branch) {
354
+			if (inc_code<lowest_s) {
355
+				lowest_b=b;
356
+				lowest_s=inc_code;
357
+			}
358
+			continue;
359
+		}
360
+		/* skip 'empty branches' */
361
+		if (!t->uac[b].request.buffer) continue;
362
+		/* there is still an unfinished UAC transaction; wait now! */
363
+		if ( t->uac[b].last_received<200 ) 
364
+			return -2;
365
+		if ( t->uac[b].last_received<lowest_s ) {
366
+			lowest_b =b;
367
+			lowest_s = t->uac[b].last_received;
368
+		}
369
+	} /* find lowest branch */
370
+
371
+	*res_code=lowest_s;
372
+	return lowest_b;
373
+}
317 374
 
318 375
 /* This is the neuralgical point of reply processing -- called
319 376
  * 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 330
 	int branch , int *should_store, int *should_relay,
331 331
 	branch_bm_t *cancel_bitmap, struct sip_msg *reply )
332 332
 {
333
-	int b, lowest_b, lowest_s, dummy;
334
-	struct sip_msg faked_msg, *origin_rq;
335
-	unsigned int on_neg;
333
+	
334
+	int branch_cnt;
335
+	int picked_branch;
336
+	int picked_code;
336 337
 
337 338
 	/* note: this code never lets replies to CANCEL go through;
338 339
 	   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 378
 		}
379 379
 
380 380
 		Trans->uac[branch].last_received=new_code;
381
+
382
+
381 383
 		/* 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) {
384
+		picked_branch=pick_branch(branch,new_code, Trans, &picked_code);
385
+		if (picked_branch==-2) { /* branches open yet */
386
+			*should_store=1;	
387
+			*should_relay=-1;
388
+			return RPS_STORE;
389
+		}
390
+		if (picked_branch==-1) {
407 391
 			LOG(L_CRIT, "ERROR: t_should_relay_response: lowest==-1\n");
392
+			goto error;
408 393
 		}
394
+
409 395
 		/* no more pending branches -- try if that changes after
410
-		   a callback
396
+		   a callback; save banch count to be able to determine
397
+		   later if new branches were initiated
411 398
 		*/
399
+		branch_cnt=Trans->nr_of_outgoings;
412 400
 		callback_event( TMCB_ON_FAILURE, Trans, 
413
-			lowest_b==branch?reply:Trans->uac[lowest_b].reply, 
414
-			lowest_s );
415
-
401
+			picked_branch==branch?reply:Trans->uac[picked_branch].reply, 
402
+			picked_code);
416 403
 		/* here, we create a faked environment, from which we
417 404
 		 * 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
-
405
+		failure_route(Trans);
438 406
 
439 407
 		/* look if the callback perhaps replied transaction; it also
440 408
 		   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 450
 			   put it on wait again; perhaps splitting put_on_wait
451 451
 			   from send_reply or a new RPS_ code would be healthy
452 452
 			*/
453
-			if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
454 453
 			return RPS_COMPLETED;
455 454
 		}
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
-			*/
455
+		/* look if the callback/failure_route introduced new branches ... */
456
+		if (branch_cnt<Trans->nr_of_outgoings)  {
457
+			/* await then result of new branches */
472 458
 			*should_store=1;
473 459
 			*should_relay=-1;
474
-			if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
475 460
 			return RPS_STORE;
476 461
 		}
462
+
477 463
 		/* really no more pending branches -- return lowest code */
478 464
 		*should_store=0;
479
-		*should_relay=lowest_b;
480
-		if (on_neg) faked_env(&faked_msg, 0, 0, 1 );
465
+		*should_relay=picked_branch;
481 466
 		/* we dont need 'which_cancel' here -- all branches 
482 467
 		   known to have completed */
483 468
 		/* which_cancel( Trans, cancel_bitmap ); */
... ...
@@ -496,6 +663,7 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
496 496
 		} else return RPS_PROVISIONAL;
497 497
 	}
498 498
 
499
+error:
499 500
 	/* reply_status didn't match -- it must be something weird */
500 501
 	LOG(L_CRIT, "ERROR: Oh my gooosh! We don't know whether to relay %d\n",
501 502
 		new_code);
... ...
@@ -567,150 +735,8 @@ int t_reply_unsafe( struct cell *t, struct sip_msg* p_msg, unsigned int code,
567 567
 }
568 568
 
569 569
 
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 570
 
613
-	rb = & trans->uas.response;
614
-	rb->activ_type=code;
615 571
 
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 572
 
715 573
 void set_final_timer( /* struct s_table *h_table, */ struct cell *t )
716 574
 {
... ...
@@ -1017,7 +1043,7 @@ error:
1017 1017
   *  Returns :   0 - core router stops
1018 1018
   *              1 - core router relay statelessly
1019 1019
   */
1020
-int t_on_reply( struct sip_msg  *p_msg )
1020
+int reply_received( struct sip_msg  *p_msg )
1021 1021
 {
1022 1022
 
1023 1023
 	int msg_status;
... ...
@@ -1068,6 +1094,13 @@ int t_on_reply( struct sip_msg  *p_msg )
1068 1068
 	if ( msg_status >= 200 )
1069 1069
 		reset_timer( &uac->request.fr_timer);
1070 1070
 
1071
+	/* processing of on_reply block */
1072
+	if (t->on_reply) {
1073
+		rmode=MODE_ONREPLY;
1074
+	 	if (run_actions(onreply_rlist[t->on_reply], p_msg)<0) 
1075
+			LOG(L_ERR, "ERROR: on_reply processing failed\n");
1076
+	}
1077
+
1071 1078
 	LOCK_REPLIES( t );
1072 1079
 	if (t->local) {
1073 1080
 		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 125
 inline static int w_t_forward_nonack_tcp(struct sip_msg* msg, char* str,char*);
126 126
 inline static int fixup_hostport2proxy(void** param, int param_no);
127 127
 inline static int w_t_on_negative( struct sip_msg* msg, char *go_to, char *foo );
128
+inline static int w_t_on_reply( struct sip_msg* msg, char *go_to, char *foo );
128 129
 
129 130
 
130 131
 static int mod_init(void);
... ...
@@ -135,23 +137,29 @@ static int child_init(int rank);
135 135
 static cmd_export_t cmds[]={
136 136
 	{"t_newtran",          w_t_newtran,             0, 0,                    REQUEST_ROUTE},
137 137
 	{"t_lookup_request",   w_t_check,               0, 0,                    REQUEST_ROUTE},
138
-	{T_REPLY,              w_t_reply,               2, fixup_t_send_reply,   REQUEST_ROUTE},
138
+	{T_REPLY,              w_t_reply,               2, fixup_t_send_reply,   
139
+			REQUEST_ROUTE | FAILURE_ROUTE },
139 140
 	{"t_retransmit_reply", w_t_retransmit_reply,    0, 0,                    REQUEST_ROUTE},
140 141
 	{"t_release",          w_t_release,             0, 0,                    REQUEST_ROUTE},
141
-	{T_RELAY_TO,           w_t_relay_to,            2, fixup_hostport2proxy, REQUEST_ROUTE},
142
+	{T_RELAY_TO,           w_t_relay_to,            2, fixup_hostport2proxy, 
143
+			REQUEST_ROUTE | FAILURE_ROUTE },
142 144
 	{T_RELAY_TO_UDP,       w_t_relay_to_udp,        2, fixup_hostport2proxy, REQUEST_ROUTE},
143 145
 	{T_RELAY_TO_TCP,       w_t_relay_to_tcp,        2, fixup_hostport2proxy, REQUEST_ROUTE},
144 146
 	{"t_replicate",        w_t_replicate,           2, fixup_hostport2proxy, REQUEST_ROUTE},
145 147
 	{"t_replicate_udp",    w_t_replicate_udp,       2, fixup_hostport2proxy, REQUEST_ROUTE},
146 148
 	{"t_replicate_tcp",    w_t_replicate_tcp,       2, fixup_hostport2proxy, REQUEST_ROUTE},
147
-	{T_RELAY,              w_t_relay,               0, 0,                    REQUEST_ROUTE},
149
+	{T_RELAY,              w_t_relay,               0, 0,                    
150
+			REQUEST_ROUTE | FAILURE_ROUTE },
148 151
 	{T_RELAY_UDP,          w_t_relay_udp,           0, 0,                    REQUEST_ROUTE},
149 152
 	{T_RELAY_TCP,          w_t_relay_tcp,           0, 0,                    REQUEST_ROUTE},
150 153
 	{T_FORWARD_NONACK,     w_t_forward_nonack,      2, fixup_hostport2proxy, REQUEST_ROUTE},
151 154
 	{T_FORWARD_NONACK_UDP, w_t_forward_nonack_udp,  2, fixup_hostport2proxy, REQUEST_ROUTE},
152 155
 	{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 */
156
+	{"t_on_failure",       w_t_on_negative,         1, fixup_str2int,
157
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
158
+	{"t_on_reply",         w_t_on_reply,            1, fixup_str2int,
159
+			REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
160
+	/* not applicable from the script */
155 161
 	{"register_tmcb",      (cmd_function)register_tmcb,     NO_SCRIPT,     0, 0},
156 162
 	{T_UAC_DLG,            (cmd_function)t_uac_dlg,         NO_SCRIPT,     0, 0},
157 163
 	{"load_tm",            (cmd_function)load_tm,           NO_SCRIPT,     0, 0},
... ...
@@ -191,7 +199,7 @@ struct module_exports exports= {
191 191
 	params,
192 192
 	
193 193
 	mod_init, /* module initialization function */
194
-	(response_function) t_on_reply,
194
+	(response_function) reply_received,
195 195
 	(destroy_function) tm_shutdown,
196 196
 	0, /* w_onbreak, */
197 197
 	child_init /* per-child init function */
... ...
@@ -234,9 +242,12 @@ static int script_init( struct sip_msg *foo, void *bar)
234 234
 	   		message's t_on_negative value
235 235
 		*/
236 236
 		t_on_negative( 0 );
237
-
237
+		t_on_reply(0);
238 238
 		/* reset the kr status */
239 239
 		set_kr(0);
240
+		/* set request mode so that multiple-mode actions know
241
+		 * how to behave */
242
+		rmode=MODE_REQUEST;
240 243
 	}
241 244
 
242 245
 	return 1;
... ...
@@ -456,11 +467,14 @@ inline static int w_t_reply(struct sip_msg* msg, char* str, char* str2)
456 456
 	 * is called; we are already in a mutex and another mutex in
457 457
 	 * the safe version would lead to a deadlock
458 458
 	 */
459
-	if (rmode==MODE_ONREPLY_REQUEST) { 
459
+	if (rmode==MODE_ONFAILURE) { 
460 460
 		DBG("DEBUG: t_reply_unsafe called from w_t_reply\n");
461 461
 		return t_reply_unsafe(t, msg, (unsigned int)(long) str, str2);
462
-	} else {
462
+	} else if (rmode==MODE_REQUEST) {
463 463
 		return t_reply( t, msg, (unsigned int)(long) str, str2);
464
+	} else {
465
+		LOG(L_CRIT, "BUG: w_t_reply entered in unsupported mode\n");
466
+		return -1;
464 467
 	}
465 468
 }
466 469
 
... ...
@@ -516,15 +530,74 @@ inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar )
516 516
 
517 517
 inline static int w_t_on_negative( struct sip_msg* msg, char *go_to, char *foo )
518 518
 {
519
-	return t_on_negative( (unsigned int )(long) go_to );
519
+	struct cell *t;
520
+
521
+	if (rmode==MODE_REQUEST || rmode==MODE_ONFAILURE) {
522
+		t_on_negative( (unsigned int )(long) go_to );
523
+		return 1;
524
+	}
525
+	if (rmode==MODE_ONREPLY ) {
526
+		/* transaction state is established */
527
+		t=get_t();
528
+		if (!t || t==T_UNDEFINED) {
529
+			LOG(L_CRIT, "BUG: w_t_on_negative entered without t\n");
530
+			return -1;
531
+		}
532
+		t->on_negative=(unsigned int)(long)go_to;
533
+		return 1;
534
+	}
535
+	LOG(L_CRIT, "BUG: w_t_on_negative entered in unsupported mode\n");
536
+	return -1;
537
+}
538
+inline static int w_t_on_reply( struct sip_msg* msg, char *go_to, char *foo )
539
+{
540
+	struct cell *t;
541
+
542
+	if (rmode==MODE_REQUEST) {
543
+		/* it's still in initial request processing stage, transaction
544
+		 * state is not estabslihed yet, store it in private memory ...
545
+		 * it will be copied to transaction state when it is set up */
546
+		t_on_reply( (unsigned int )(long) go_to );
547
+		return 1;
548
+	}
549
+	if (rmode==MODE_ONREPLY || rmode==MODE_ONFAILURE) {
550
+		/* transaction state is established */
551
+		t=get_t();
552
+		if (!t || t==T_UNDEFINED) {
553
+			LOG(L_CRIT, "BUG: w_t_on_reply entered without t\n");
554
+			return -1;
555
+		}
556
+		t->on_reply=(unsigned int) (long)go_to;
557
+		return 1;
558
+	}
559
+	LOG(L_CRIT, "BUG: w_t_on_reply entered in unsupported mode\n");
560
+	return -1;
520 561
 }
521 562
 
522 563
 inline static int w_t_relay_to( struct sip_msg  *p_msg , 
523 564
 	char *proxy, /* struct proxy_l *proxy expected */
524 565
 	char *_foo       /* nothing expected */ )
525 566
 {
526
-	return t_relay_to( p_msg, ( struct proxy_l *) proxy, p_msg->rcv.proto,
527
-	0 /* no replication */ );
567
+	struct cell *t;
568
+
569
+	if (rmode==MODE_ONFAILURE) { 
570
+		t=get_t();
571
+		if (!t || t==T_UNDEFINED) {
572
+			LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n");
573
+			return -1;
574
+		}
575
+		if (t_forward_nonack(t, p_msg, 
576
+				( struct proxy_l *) proxy, p_msg->rcv.proto)<=0 ) {
577
+			LOG(L_ERR, "ERROR: failure_route: t_relay_to failed\n");
578
+			return -1;
579
+		}
580
+		return 1;
581
+	}
582
+	if (rmode==MODE_REQUEST) 
583
+		return t_relay_to( p_msg, ( struct proxy_l *) proxy, p_msg->rcv.proto,
584
+			0 /* no replication */ );
585
+	LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
586
+	return 0;
528 587
 }
529 588
 
530 589
 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 571
 inline static int w_t_relay( struct sip_msg  *p_msg , 
572 572
 						char *_foo, char *_bar)
573 573
 {
574
-	return t_relay_to( p_msg, 
574
+	struct cell *t;
575
+
576
+	if (rmode==MODE_ONFAILURE) { 
577
+		t=get_t();
578
+		if (!t || t==T_UNDEFINED) {
579
+			LOG(L_CRIT, "BUG: w_t_relay: undefined T\n");
580
+			return -1;
581
+		} 
582
+		if (t_forward_nonack(t, p_msg, ( struct proxy_l *) 0, p_msg->rcv.proto)<=0) {
583
+			LOG(L_ERR, "ERROR: w_t_relay (failure mode): forwarding failed\n");
584
+			return -1;
585
+		}
586
+		return 1;
587
+	}
588
+	if (rmode==MODE_REQUEST) 
589
+		return t_relay_to( p_msg, 
575 590
 		(struct proxy_l *) 0 /* no proxy */, p_msg->rcv.proto,
576 591
 		0 /* no replication */ );
592
+	LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
593
+	return 0;
577 594
 }
578 595
 
579 596
 
... ...
@@ -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 63
 /* main routing script table  */
64 64
 struct action* rlist[RT_NO];
65 65
 /* reply routing table */
66
-struct action* reply_rlist[REPLY_RT_NO];
66
+struct action* onreply_rlist[ONREPLY_RT_NO];
67
+struct action* failure_rlist[FAILURE_RT_NO];
67 68
 
68 69
 
69 70
 static int fix_actions(struct action* a); /*fwd declaration*/
... ...
@@ -559,9 +561,16 @@ int fix_rls()
559 559
 			}
560 560
 		}
561 561
 	}
562
-	for(i=0;i<REPLY_RT_NO;i++){
563
-		if(reply_rlist[i]){
564
-			if ((ret=fix_actions(reply_rlist[i]))!=0){
562
+	for(i=0;i<ONREPLY_RT_NO;i++){
563
+		if(onreply_rlist[i]){
564
+			if ((ret=fix_actions(onreply_rlist[i]))!=0){
565
+				return ret;
566
+			}
567
+		}
568
+	}
569
+	for(i=0;i<FAILURE_RT_NO;i++){
570
+		if(failure_rlist[i]){
571
+			if ((ret=fix_actions(failure_rlist[i]))!=0){
565 572
 				return ret;
566 573
 			}
567 574
 		}
... ...
@@ -587,13 +596,22 @@ void print_rl()
587 587
 		}
588 588
 		DBG("\n");
589 589
 	}
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");
590
+	for(j=0; j<ONREPLY_RT_NO; j++){
591
+		if (onreply_rlist[j]==0){
593 592
 			continue;
594 593
 		}
595
-		DBG("routing table %d:\n",j);
596
-		for (t=reply_rlist[j],i=0; t; i++, t=t->next){
594
+		DBG("onreply routing table %d:\n",j);
595
+		for (t=onreply_rlist[j],i=0; t; i++, t=t->next){
596
+			print_action(t);
597
+		}
598
+		DBG("\n");
599
+	}
600
+	for(j=0; j<FAILURE_RT_NO; j++){
601
+		if (failure_rlist[j]==0){
602
+			continue;
603
+		}
604
+		DBG("failure routing table %d:\n",j);
605
+		for (t=failure_rlist[j],i=0; t; i++, t=t->next){
597 606
 			print_action(t);
598 607
 		}
599 608
 		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 55
 	INT_PARAM,  /* Integer parameter type */
56 56
 } modparam_t;       /* Allowed types of parameters */
57 57
 
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 */
58
+#define REQUEST_ROUTE 1  /* Function can be used in request route blocks */
59
+#define FAILURE_ROUTE 2  /* Function can be used in reply route blocks */
60
+#define ONREPLY_ROUTE 4  /* Function can be used in on_reply */
60 61
 
61 62
 /* Macros - used as rank in child_init function */
62 63
 #define PROC_MAIN      0  /* Main ser process */