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 441
 	unsigned short on_reply;
442 442
 	 /* The route to take for each downstream branch separately */
443 443
 	unsigned short on_branch;
444
+	 /* The route to take for each downstream branch failure */
445
+	unsigned short on_branch_failure;
444 446
 
445 447
 	/* place holder for MD5checksum  (meaningful only if syn_branch=0) */
446 448
 	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 111
 #endif
112 112
 #define TMCB_REQUEST_SENT      (1<<TMCB_REQUEST_SENT_N)
113 113
 #define TMCB_RESPONSE_SENT     (1<<TMCB_RESPONSE_SENT_N)
114
+#define TMCB_ON_BRANCH_FAILURE (1<<TMCB_ON_BRANCH_FAILURE_N)
115
+#define TMCB_ON_BRANCH_FAILURE_RO (1<<TMCB_ON_BRANCH_FAILURE_RO_N)
114 116
 #define TMCB_MAX              ((1<<(TMCB_MAX_N+1))-1)
115 117
 
116 118
 
... ...
@@ -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 262
 }
263 263
 
264 264
 
265
+void t_on_branch_failure( unsigned int go_to )
266
+{
267
+	struct cell *t = get_t();
268
+
269
+	/* in REPLY_ROUTE and FAILURE_ROUTE T will be set to current transaction;
270
+	 * in REQUEST_ROUTE T will be set only if the transaction was already
271
+	 * created; if not -> use the static variable */
272
+	if (!t || t==T_UNDEFINED )
273
+		goto_on_branch_failure=go_to;
274
+	else
275
+		t->on_branch_failure = go_to;
276
+}
277
+
278
+
265 279
 void t_on_reply( unsigned int go_to )
266 280
 {
267 281
 	struct cell *t = get_t();
... ...
@@ -280,6 +296,10 @@ unsigned int get_on_failure()
280 280
 {
281 281
 	return goto_on_failure;
282 282
 }
283
+unsigned int get_on_branch_failure()
284
+{
285
+	return goto_on_branch_failure;
286
+}
283 287
 unsigned int get_on_reply()
284 288
 {
285 289
 	return goto_on_reply;
... ...
@@ -1039,6 +1059,67 @@ int run_failure_handlers(struct cell *t, struct sip_msg *rpl,
1039 1039
 }
1040 1040
 
1041 1041
 
1042
+/* return 1 if a failure_route processes */
1043
+int run_branch_failure_handlers(struct cell *t, struct sip_msg *rpl,
1044
+					int code, int extra_flags)
1045
+{
1046
+	static struct sip_msg faked_req;
1047
+	struct sip_msg *shmem_msg = t->uas.request;
1048
+	int on_branch_failure;
1049
+
1050
+	on_branch_failure = t->uac[picked_branch].on_branch_failure;
1051
+
1052
+	/* failure_route for a local UAC? */
1053
+	if (!shmem_msg) {
1054
+		LOG(L_WARN,"Warning: run_branch_failure_handlers: no UAC support (%d, %d) \n",
1055
+			on_branch_failure, t->tmcb_hl.reg_types);
1056
+		return 0;
1057
+	}
1058
+
1059
+	/* don't start faking anything if we don't have to */
1060
+	if (unlikely(!on_branch_failure && !has_tran_tmcbs( t, TMCB_ON_BRANCH_FAILURE))) {
1061
+		LOG(L_WARN,
1062
+			"Warning: run_failure_handlers: no branch_failure handler (%d, %d)\n",
1063
+			on_branch_failure, t->tmcb_hl.reg_types);
1064
+		return 1;
1065
+	}
1066
+
1067
+	if (!fake_req(&faked_req, shmem_msg, extra_flags, &t->uac[picked_branch])) {
1068
+		LOG(L_ERR, "ERROR: run_branch_failure_handlers: fake_req failed\n");
1069
+		return 0;
1070
+	}
1071
+	/* fake also the env. conforming to the fake msg */
1072
+	faked_env( t, &faked_req);
1073
+	/* DONE with faking ;-) -> run the branch_failure handlers */
1074
+
1075
+	if (unlikely(has_tran_tmcbs( t, TMCB_ON_BRANCH_FAILURE)) ) {
1076
+		run_trans_callbacks( TMCB_ON_BRANCH_FAILURE, t, &faked_req, rpl, code);
1077
+	}
1078
+	if (on_branch_failure) {
1079
+		/* avoid recursion -- if branch_failure_route forwards, and does not
1080
+		 * set next branch failure route, branch_failure_route will not be reentered
1081
+		 * on branch failure */
1082
+		t->on_branch_failure=0;
1083
+		if (exec_pre_script_cb(&faked_req, BRANCH_FAILURE_CB_TYPE)>0) {
1084
+			/* run a branch_failure_route action if some was marked */
1085
+			if (run_top_route(branch_failure_rt.rlist[on_branch_failure], &faked_req, 0)<0)
1086
+				LOG(L_ERR, "ERROR: run_branch_failure_handlers: Error in run_top_route\n");
1087
+			exec_post_script_cb(&faked_req, BRANCH_FAILURE_CB_TYPE);
1088
+		}
1089
+		/* update message flags, if changed in branch_failure route */
1090
+		t->uas.request->flags = faked_req.flags;
1091
+	}
1092
+
1093
+	/* restore original environment and free the fake msg */
1094
+	faked_env( t, 0);
1095
+	free_faked_req(&faked_req,t);
1096
+
1097
+	/* if branch_failure handler changed flag, update transaction context */
1098
+	shmem_msg->flags = faked_req.flags;
1099
+	return 1;
1100
+}
1101
+
1102
+
1042 1103
 
1043 1104
 /* 401, 407, 415, 420, and 484 have priority over the other 4xx*/
1044 1105
 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 1252
 
1253 1253
 		Trans->uac[branch].last_received=new_code;
1254 1254
 
1255
+/* New branch failure route code */
1256
+		if (unlikely(has_tran_tmcbs( Trans, TMCB_ON_BRANCH_FAILURE_RO|TMCB_ON_BRANCH_FAILURE)
1257
+						|| Trans->uac[branch].on_branch_failure )) {
1258
+			extra_flags=
1259
+				((Trans->uac[branch].request.flags & F_RB_TIMEOUT)?
1260
+							FL_TIMEOUT:0) | 
1261
+				((Trans->uac[branch].request.flags & F_RB_REPLIED)?
1262
+						 	FL_REPLIED:0);
1263
+			tm_ctx_set_branch_index(branch);
1264
+			picked_branch = branch;
1265
+			run_branch_failure_handlers( Trans, Trans->uac[branch].reply,
1266
+									new_code, extra_flags);
1267
+		}
1268
+/* END - New branch failure route code */
1269
+
1270
+
1255 1271
 		/* if all_final return lowest */
1256 1272
 		picked_branch=t_pick_branch(branch,new_code, Trans, &picked_code);
1257 1273
 		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 209
 */
210 210
 void t_on_failure( unsigned int go_to );
211 211
 unsigned int get_on_failure(void);
212
+void t_on_branch_failure( unsigned int go_to );
213
+unsigned int get_on_branch_failure(void);
212 214
 void t_on_reply( unsigned int go_to );
213 215
 unsigned int get_on_reply(void);
214 216
 
... ...
@@ -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 272
 inline static int w_t_forward_nonack_to(struct sip_msg* msg, char* str,char*);
273 273
 inline static int w_t_relay_cancel(struct sip_msg *p_msg, char *_foo, char *_bar);
274 274
 inline static int w_t_on_failure(struct sip_msg* msg, char *go_to, char *foo);
275
+inline static int w_t_on_branch_failure(struct sip_msg* msg, char *go_to, char *foo);
275 276
 inline static int w_t_on_branch(struct sip_msg* msg, char *go_to, char *foo);
276 277
 inline static int w_t_on_reply(struct sip_msg* msg, char *go_to, char *foo );
277 278
 inline static int t_check_status(struct sip_msg* msg, char *match, char *foo);
... ...
@@ -409,6 +411,8 @@ static cmd_export_t cmds[]={
409 409
 			REQUEST_ROUTE},
410 410
 	{"t_on_failure",       w_t_on_failure,         1, fixup_on_failure,
411 411
 			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
412
+	{"t_on_branch_failure",w_t_on_branch_failure,         1, fixup_on_branch_failure,
413
+			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
412 414
 	{"t_on_reply",         w_t_on_reply,            1, fixup_on_reply,
413 415
 			REQUEST_ROUTE | FAILURE_ROUTE | TM_ONREPLY_ROUTE | BRANCH_ROUTE },
414 416
 	{"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 601
 }
602 602
 
603 603
 
604
+static int fixup_on_branch_failure(void** param, int param_no)
605
+{
606
+	if (param_no==1){
607
+		if(strlen((char*)*param)<=1
608
+				&& (*(char*)(*param)==0 || *(char*)(*param)=='0')) {
609
+			*param = (void*)0;
610
+			return 0;
611
+		}
612
+		return fixup_routes("t_on_branch_failure", &branch_failure_rt, param);
613
+	}
614
+	return 0;
615
+}
616
+
617
+
604 618
 
605 619
 static int fixup_on_reply(void** param, int param_no)
606 620
 {
... ...
@@ -733,6 +751,7 @@ static int script_init( struct sip_msg *foo, unsigned int flags, void *bar)
733 733
 		message's t_on_failure value
734 734
 	*/
735 735
 	t_on_failure( 0 );
736
+	t_on_branch_failure(0);
736 737
 	t_on_reply(0);
737 738
 	t_on_branch(0);
738 739
 	/* 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 1368
 	return 1;
1369 1369
 }
1370 1370
 
1371
+inline static int w_t_on_branch_failure( struct sip_msg* msg, char *go_to, char *foo)
1372
+{
1373
+	t_on_branch_failure( (unsigned int )(long) go_to );
1374
+	return 1;
1375
+}
1376
+
1371 1377
 inline static int w_t_on_branch( struct sip_msg* msg, char *go_to, char *foo)
1372 1378
 {
1373 1379
 	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 1410
 			else
1411 1411
 				r = t->on_reply;
1412 1412
 			break;
1413
+#warning need to add branch_failure_route
1413 1414
 	}
1414 1415
 	if(r) return 1;
1415 1416
 	return -1;
... ...
@@ -1423,6 +1449,7 @@ static int fixup_t_is_set(void** param, int param_no)
1423 1423
 		if((len==13 && strncmp((char*)*param, "failure_route", 13)==0)
1424 1424
 				|| (len==13 && strncmp((char*)*param, "onreply_route", 13)==0)
1425 1425
 				|| (len==12 && strncmp((char*)*param, "branch_route", 12)==0)) {
1426
+#warning need to add branch_failure_route
1426 1427
 			return 0;
1427 1428
 		}
1428 1429
 
... ...
@@ -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 176
 
177 177
 typedef struct tm_xbinds {
178 178
 	t_on_route_f t_on_failure;
179
+	t_on_route_f t_on_branch_failure;
179 180
 	t_on_route_f t_on_branch;
180 181
 	t_on_route_f t_on_reply;
181 182
 	t_no_param_f t_check_trans;