Browse code

modules/tm: Initial revision of branch_failure_route

- New branch_failure_route defined
- cfg route is called but xlog() causes segfault

Hugh Waite authored on 19/03/2013 15:41:55
Showing 9 changed files
... ...
@@ -249,6 +249,8 @@ typedef struct ua_client
249 249
 #endif
250 250
 	/* the route to take if no final positive reply arrived */
251 251
 	unsigned short on_failure;
252
+	/* the route to take for each downstream branch failure */
253
+	unsigned short on_branch_failure;
252 254
 	/* the onreply_route to be processed if registered to do so */
253 255
 	unsigned short on_reply;
254 256
 }ua_client_type;
... ...
@@ -441,6 +443,8 @@ typedef struct cell
441 443
 	unsigned short on_reply;
442 444
 	 /* The route to take for each downstream branch separately */
443 445
 	unsigned short on_branch;
446
+	 /* The route to take for each downstream branch failure */
447
+	unsigned short on_branch_failure;
444 448
 
445 449
 	/* place holder for MD5checksum  (meaningful only if syn_branch=0) */
446 450
 	char md5[0]; /* if syn_branch==0 then MD5_LEN bytes are extra alloc'ed*/
... ...
@@ -420,6 +420,7 @@ static int prepare_new_uac( struct cell *t, struct sip_msg *i_req,
420 420
 	/* Set on_reply and on_negative handlers for this branch to the handlers in the transaction */
421 421
 	t->uac[branch].on_reply = t->on_reply;
422 422
 	t->uac[branch].on_failure = t->on_failure;
423
+	t->uac[branch].on_branch_failure = t->on_branch_failure;
423 424
 
424 425
 	/* check if send_sock is ok */
425 426
 	if (t->uac[branch].request.dst.send_sock==0) {
... ...
@@ -82,7 +82,9 @@ struct cell;
82 82
 #endif
83 83
 #define TMCB_REQUEST_SENT_N     22
84 84
 #define TMCB_RESPONSE_SENT_N    23
85
-#define TMCB_MAX_N              23
85
+#define TMCB_ON_BRANCH_FAILURE_RO_N 24
86
+#define TMCB_ON_BRANCH_FAILURE_N 25
87
+#define TMCB_MAX_N              25
86 88
 
87 89
 
88 90
 #define TMCB_REQUEST_IN       (1<<TMCB_REQUEST_IN_N)
... ...
@@ -111,6 +113,8 @@ struct cell;
111 113
 #endif
112 114
 #define TMCB_REQUEST_SENT      (1<<TMCB_REQUEST_SENT_N)
113 115
 #define TMCB_RESPONSE_SENT     (1<<TMCB_RESPONSE_SENT_N)
116
+#define TMCB_ON_BRANCH_FAILURE (1<<TMCB_ON_BRANCH_FAILURE_N)
117
+#define TMCB_ON_BRANCH_FAILURE_RO (1<<TMCB_ON_BRANCH_FAILURE_RO_N)
114 118
 #define TMCB_MAX              ((1<<(TMCB_MAX_N+1))-1)
115 119
 
116 120
 
... ...
@@ -1286,6 +1286,7 @@ static inline void init_new_t(struct cell *new_cell, struct sip_msg *p_msg)
1286 1286
 			lifetime=cfg_get(tm, tm_cfg, tm_max_noninv_lifetime);
1287 1287
 	}
1288 1288
 	new_cell->on_failure=get_on_failure();
1289
+	new_cell->on_branch_failure=get_on_branch_failure();
1289 1290
 	new_cell->on_reply=get_on_reply();
1290 1291
 	new_cell->end_of_life=get_ticks_raw()+lifetime;;
1291 1292
 	new_cell->fr_timeout=(ticks_t)get_msgid_val(user_fr_timeout,
... ...
@@ -172,6 +172,8 @@ char *tm_tag_suffix;
172 172
 
173 173
 /* where to go if there is no positive reply (>=300) */
174 174
 static int goto_on_failure=0;
175
+/* where to go if a failure is returned on a branch */
176
+static int goto_on_branch_failure=0;
175 177
 /* where to go on receipt of reply */
176 178
 static int goto_on_reply=0;
177 179
 /* where to go on receipt of reply without transaction context */
... ...
@@ -262,6 +264,20 @@ void t_on_failure( unsigned int go_to )
262 264
 }
263 265
 
264 266
 
267
+void t_on_branch_failure( unsigned int go_to )
268
+{
269
+	struct cell *t = get_t();
270
+
271
+	/* in REPLY_ROUTE and FAILURE_ROUTE T will be set to current transaction;
272
+	 * in REQUEST_ROUTE T will be set only if the transaction was already
273
+	 * created; if not -> use the static variable */
274
+	if (!t || t==T_UNDEFINED )
275
+		goto_on_branch_failure=go_to;
276
+	else
277
+		t->on_branch_failure = go_to;
278
+}
279
+
280
+
265 281
 void t_on_reply( unsigned int go_to )
266 282
 {
267 283
 	struct cell *t = get_t();
... ...
@@ -280,6 +296,10 @@ unsigned int get_on_failure()
280 296
 {
281 297
 	return goto_on_failure;
282 298
 }
299
+unsigned int get_on_branch_failure()
300
+{
301
+	return goto_on_branch_failure;
302
+}
283 303
 unsigned int get_on_reply()
284 304
 {
285 305
 	return goto_on_reply;
... ...
@@ -1039,6 +1059,67 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
1039 1059
 }
1040 1060
 
1041 1061
 
1062
+/* return 1 if a failure_route processes */
1063
+int run_branch_failure_handlers(struct cell *t, struct sip_msg *rpl,
1064
+					int code, int extra_flags)
1065
+{
1066
+	static struct sip_msg faked_req;
1067
+	struct sip_msg *shmem_msg = t->uas.request;
1068
+	int on_branch_failure;
1069
+
1070
+	on_branch_failure = t->uac[picked_branch].on_branch_failure;
1071
+
1072
+	/* failure_route for a local UAC? */
1073
+	if (!shmem_msg) {
1074
+		LOG(L_WARN,"Warning: run_branch_failure_handlers: no UAC support (%d, %d) \n",
1075
+			on_branch_failure, t->tmcb_hl.reg_types);
1076
+		return 0;
1077
+	}
1078
+
1079
+	/* don't start faking anything if we don't have to */
1080
+	if (unlikely(!on_branch_failure && !has_tran_tmcbs( t, TMCB_ON_BRANCH_FAILURE))) {
1081
+		LOG(L_WARN,
1082
+			"Warning: run_failure_handlers: no branch_failure handler (%d, %d)\n",
1083
+			on_branch_failure, t->tmcb_hl.reg_types);
1084
+		return 1;
1085
+	}
1086
+
1087
+	if (!fake_req(&faked_req, shmem_msg, extra_flags, &t->uac[picked_branch])) {
1088
+		LOG(L_ERR, "ERROR: run_branch_failure_handlers: fake_req failed\n");
1089
+		return 0;
1090
+	}
1091
+	/* fake also the env. conforming to the fake msg */
1092
+	faked_env( t, &faked_req);
1093
+	/* DONE with faking ;-) -> run the branch_failure handlers */
1094
+
1095
+	if (unlikely(has_tran_tmcbs( t, TMCB_ON_BRANCH_FAILURE)) ) {
1096
+		run_trans_callbacks( TMCB_ON_BRANCH_FAILURE, t, &faked_req, rpl, code);
1097
+	}
1098
+	if (on_branch_failure) {
1099
+		/* avoid recursion -- if branch_failure_route forwards, and does not
1100
+		 * set next branch failure route, branch_failure_route will not be reentered
1101
+		 * on branch failure */
1102
+		t->on_branch_failure=0;
1103
+		if (exec_pre_script_cb(&faked_req, BRANCH_FAILURE_CB_TYPE)>0) {
1104
+			/* run a branch_failure_route action if some was marked */
1105
+			if (run_top_route(branch_failure_rt.rlist[on_branch_failure], &faked_req, 0)<0)
1106
+				LOG(L_ERR, "ERROR: run_branch_failure_handlers: Error in run_top_route\n");
1107
+			exec_post_script_cb(&faked_req, BRANCH_FAILURE_CB_TYPE);
1108
+		}
1109
+		/* update message flags, if changed in branch_failure route */
1110
+		t->uas.request->flags = faked_req.flags;
1111
+	}
1112
+
1113
+	/* restore original environment and free the fake msg */
1114
+	faked_env( t, 0);
1115
+	free_faked_req(&faked_req,t);
1116
+
1117
+	/* if branch_failure handler changed flag, update transaction context */
1118
+	shmem_msg->flags = faked_req.flags;
1119
+	return 1;
1120
+}
1121
+
1122
+
1042 1123
 
1043 1124
 /* 401, 407, 415, 420, and 484 have priority over the other 4xx*/
1044 1125
 inline static short int get_4xx_prio(unsigned char xx)
... ...
@@ -1252,6 +1333,22 @@ static enum rps t_should_relay_response( struct cell *Trans , int new_code,
1252 1333
 
1253 1334
 		Trans->uac[branch].last_received=new_code;
1254 1335
 
1336
+/* New branch failure route code */
1337
+		if (unlikely(has_tran_tmcbs( Trans, TMCB_ON_BRANCH_FAILURE_RO|TMCB_ON_BRANCH_FAILURE)
1338
+						|| Trans->uac[branch].on_branch_failure )) {
1339
+			extra_flags=
1340
+				((Trans->uac[branch].request.flags & F_RB_TIMEOUT)?
1341
+							FL_TIMEOUT:0) | 
1342
+				((Trans->uac[branch].request.flags & F_RB_REPLIED)?
1343
+						 	FL_REPLIED:0);
1344
+			tm_ctx_set_branch_index(branch);
1345
+			picked_branch = branch;
1346
+			run_branch_failure_handlers( Trans, Trans->uac[branch].reply,
1347
+									new_code, extra_flags);
1348
+		}
1349
+/* END - New branch failure route code */
1350
+
1351
+
1255 1352
 		/* if all_final return lowest */
1256 1353
 		picked_branch=t_pick_branch(branch,new_code, Trans, &picked_code);
1257 1354
 		if (picked_branch==-2) { /* branches open yet */
... ...
@@ -161,6 +161,11 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
161 161
 					int code, int extra_flags);
162 162
 typedef int (*run_failure_handlers_f)(struct cell*, struct sip_msg*, int, int);
163 163
 
164
+/* return 1 if a branch_failure_route processes */
165
+int run_branch_failure_handlers(struct cell *t, struct sip_msg *rpl,
166
+					int code, int extra_flags);
167
+typedef int (*run_branch_failure_handlers_f)(struct cell*, struct sip_msg*, int, int);
168
+
164 169
 
165 170
 /* Retransmits the last sent inbound reply.
166 171
  * Returns  -1 - error
... ...
@@ -209,6 +214,8 @@ void on_failure_reply( struct cell* t, struct sip_msg* msg,
209 214
 */
210 215
 void t_on_failure( unsigned int go_to );
211 216
 unsigned int get_on_failure(void);
217
+void t_on_branch_failure( unsigned int go_to );
218
+unsigned int get_on_branch_failure(void);
212 219
 void t_on_reply( unsigned int go_to );
213 220
 unsigned int get_on_reply(void);
214 221
 
... ...
@@ -190,6 +190,7 @@ MODULE_VERSION
190 190
 static int fixup_hostport2proxy(void** param, int param_no);
191 191
 static int fixup_proto_hostport2proxy(void** param, int param_no);
192 192
 static int fixup_on_failure(void** param, int param_no);
193
+static int fixup_on_branch_failure(void** param, int param_no);
193 194
 static int fixup_on_reply(void** param, int param_no);
194 195
 static int fixup_on_branch(void** param, int param_no);
195 196
 static int fixup_t_reply(void** param, int param_no);
... ...
@@ -272,6 +273,7 @@ inline static int w_t_forward_nonack_sctp(struct sip_msg*, char* str,char*);
272 273
 inline static int w_t_forward_nonack_to(struct sip_msg* msg, char* str,char*);
273 274
 inline static int w_t_relay_cancel(struct sip_msg *p_msg, char *_foo, char *_bar);
274 275
 inline static int w_t_on_failure(struct sip_msg* msg, char *go_to, char *foo);
276
+inline static int w_t_on_branch_failure(struct sip_msg* msg, char *go_to, char *foo);
275 277
 inline static int w_t_on_branch(struct sip_msg* msg, char *go_to, char *foo);
276 278
 inline static int w_t_on_reply(struct sip_msg* msg, char *go_to, char *foo );
277 279
 inline static int t_check_status(struct sip_msg* msg, char *match, char *foo);
... ...
@@ -409,6 +411,8 @@ static cmd_export_t cmds[]={
409 411
 			REQUEST_ROUTE},
410 412
 	{"t_on_failure",       w_t_on_failure,         1, fixup_on_failure,
411 413
 			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
414
+	{"t_on_branch_failure",w_t_on_branch_failure,         1, fixup_on_branch_failure,
415
+			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
412 416
 	{"t_on_reply",         w_t_on_reply,            1, fixup_on_reply,
413 417
 			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
414 418
 	{"t_on_branch",       w_t_on_branch,         1, fixup_on_branch,
... ...
@@ -601,6 +605,20 @@ static int fixup_on_failure(void** param, int param_no)
601 605
 }
602 606
 
603 607
 
608
+static int fixup_on_branch_failure(void** param, int param_no)
609
+{
610
+	if (param_no==1){
611
+		if(strlen((char*)*param)<=1
612
+				&& (*(char*)(*param)==0 || *(char*)(*param)=='0')) {
613
+			*param = (void*)0;
614
+			return 0;
615
+		}
616
+		return fixup_routes("t_on_branch_failure", &branch_failure_rt, param);
617
+	}
618
+	return 0;
619
+}
620
+
621
+
604 622
 
605 623
 static int fixup_on_reply(void** param, int param_no)
606 624
 {
... ...
@@ -733,6 +751,7 @@ static int script_init( struct sip_msg *foo, unsigned int flags, void *bar)
733 751
 		message's t_on_failure value
734 752
 	*/
735 753
 	t_on_failure( 0 );
754
+	t_on_branch_failure(0);
736 755
 	t_on_reply(0);
737 756
 	t_on_branch(0);
738 757
 	/* reset the kr status */
... ...
@@ -1368,6 +1387,12 @@ inline static int w_t_on_failure( struct sip_msg* msg, char *go_to, char *foo)
1368 1387
 	return 1;
1369 1388
 }
1370 1389
 
1390
+inline static int w_t_on_branch_failure( struct sip_msg* msg, char *go_to, char *foo)
1391
+{
1392
+	t_on_branch_failure( (unsigned int )(long) go_to );
1393
+	return 1;
1394
+}
1395
+
1371 1396
 inline static int w_t_on_branch( struct sip_msg* msg, char *go_to, char *foo)
1372 1397
 {
1373 1398
 	t_on_branch( (unsigned int )(long) go_to );
... ...
@@ -1410,6 +1435,7 @@ static int w_t_is_set(struct sip_msg* msg, char *target, char *foo )
1410 1435
 			else
1411 1436
 				r = t->on_reply;
1412 1437
 			break;
1438
+#warning need to add branch_failure_route
1413 1439
 	}
1414 1440
 	if(r) return 1;
1415 1441
 	return -1;
... ...
@@ -1423,6 +1449,7 @@ static int fixup_t_is_set(void** param, int param_no)
1423 1449
 		if((len==13 && strncmp((char*)*param, "failure_route", 13)==0)
1424 1450
 				|| (len==13 && strncmp((char*)*param, "onreply_route", 13)==0)
1425 1451
 				|| (len==12 && strncmp((char*)*param, "branch_route", 12)==0)) {
1452
+#warning need to add branch_failure_route
1426 1453
 			return 0;
1427 1454
 		}
1428 1455
 
... ...
@@ -110,6 +110,7 @@ int load_tm( struct tm_binds *tmb)
110 110
 	tmb->t_uac_with_ids = t_uac_with_ids;
111 111
 	tmb->t_unref = t_unref;
112 112
 	tmb->run_failure_handlers = run_failure_handlers;
113
+	tmb->run_branch_failure_handlers = run_branch_failure_handlers;
113 114
 	tmb->cancel_uacs = cancel_uacs;
114 115
 	tmb->cancel_all_uacs = cancel_all_uacs;
115 116
 	tmb->prepare_request_within = prepare_req_within;
... ...
@@ -88,6 +88,7 @@ struct tm_binds {
88 88
 	trelease_f         t_release;
89 89
 	tunref_f           t_unref;
90 90
 	run_failure_handlers_f run_failure_handlers;
91
+	run_branch_failure_handlers_f run_branch_failure_handlers;
91 92
 	cancel_uacs_f      cancel_uacs;
92 93
 	cancel_all_uacs_f  cancel_all_uacs;
93 94
 	prepare_request_within_f  prepare_request_within;
... ...
@@ -176,6 +177,7 @@ int t_is_canceled(struct sip_msg* msg);
176 177
 
177 178
 typedef struct tm_xbinds {
178 179
 	t_on_route_f t_on_failure;
180
+	t_on_route_f t_on_branch_failure;
179 181
 	t_on_route_f t_on_branch;
180 182
 	t_on_route_f t_on_reply;
181 183
 	t_no_param_f t_check_trans;