Browse code

dispatcher: new variable $dsv(...)

- access attributes related to response code when executing event routes
- $dsv(code) - the response code that triggered execution of the
event_route dispatcher:dst-up or dispatcher:dst-down
- $dsv(reason) - the response reason; $dsv(flags) - internal flags set
during event route execution

Daniel-Constantin Mierla authored on 19/11/2019 09:15:15
Showing 3 changed files
... ...
@@ -105,7 +105,8 @@ int *next_idx = NULL;
105 105
 #define _ds_list (ds_lists[*crt_idx])
106 106
 #define _ds_list_nr (*ds_list_nr)
107 107
 
108
-static void ds_run_route(struct sip_msg *msg, str *uri, char *route);
108
+static void ds_run_route(struct sip_msg *msg, str *uri, char *route,
109
+		ds_rctx_t *rctx);
109 110
 
110 111
 void shuffle_uint100array(unsigned int *arr);
111 112
 int ds_reinit_rweight_on_state_change(
... ...
@@ -2484,6 +2485,7 @@ int ds_mark_dst(struct sip_msg *msg, int state)
2484 2485
 	sr_xavp_t *rxavp = NULL;
2485 2486
 	int group;
2486 2487
 	int ret;
2488
+	ds_rctx_t rctx;
2487 2489
 
2488 2490
 	if(!(ds_flags & DS_FAILOVER_ON)) {
2489 2491
 		LM_WARN("failover support disabled\n");
... ...
@@ -2505,7 +2507,23 @@ int ds_mark_dst(struct sip_msg *msg, int state)
2505 2507
 	if(rxavp == NULL )
2506 2508
 		return -1; /* dst addr uri not available */
2507 2509
 
2508
-	ret = ds_update_state(msg, group, &rxavp->val.v.s, state);
2510
+	memset(&rctx, 0, sizeof(ds_rctx_t));
2511
+	if(msg!=NULL) {
2512
+		if(msg!=FAKED_REPLY) {
2513
+			if(msg->first_line.type == SIP_REPLY) {
2514
+				rctx.flags |= 1;
2515
+				rctx.code = (int)msg->first_line.u.reply.statuscode;
2516
+				rctx.reason = msg->first_line.u.reply.reason;
2517
+			} else {
2518
+				rctx.code = 820;
2519
+			}
2520
+		} else {
2521
+			rctx.code = 810;
2522
+		}
2523
+	} else {
2524
+		rctx.code = 800;
2525
+	}
2526
+	ret = ds_update_state(msg, group, &rxavp->val.v.s, state, &rctx);
2509 2527
 
2510 2528
 	LM_DBG("state [%d] grp [%d] dst [%.*s]\n", state, group, rxavp->val.v.s.len,
2511 2529
 			rxavp->val.v.s.s);
... ...
@@ -2682,7 +2700,8 @@ int ds_get_state(int group, str *address)
2682 2700
 /**
2683 2701
  * Update destionation's state
2684 2702
  */
2685
-int ds_update_state(sip_msg_t *msg, int group, str *address, int state)
2703
+int ds_update_state(sip_msg_t *msg, int group, str *address, int state,
2704
+		ds_rctx_t *rctx)
2686 2705
 {
2687 2706
 	int i = 0;
2688 2707
 	int old_state = 0;
... ...
@@ -2761,11 +2780,11 @@ int ds_update_state(sip_msg_t *msg, int group, str *address, int state)
2761 2780
 			}
2762 2781
 
2763 2782
 			if(!ds_skip_dst(old_state) && ds_skip_dst(idx->dlist[i].flags)) {
2764
-				ds_run_route(msg, address, "dispatcher:dst-down");
2783
+				ds_run_route(msg, address, "dispatcher:dst-down", rctx);
2765 2784
 
2766 2785
 			} else {
2767 2786
 				if(ds_skip_dst(old_state) && !ds_skip_dst(idx->dlist[i].flags))
2768
-					ds_run_route(msg, address, "dispatcher:dst-up");
2787
+					ds_run_route(msg, address, "dispatcher:dst-up", rctx);
2769 2788
 			}
2770 2789
 			if(idx->dlist[i].attrs.rweight > 0)
2771 2790
 				ds_reinit_rweight_on_state_change(
... ...
@@ -2780,7 +2799,20 @@ int ds_update_state(sip_msg_t *msg, int group, str *address, int state)
2780 2799
 	return -1;
2781 2800
 }
2782 2801
 
2783
-static void ds_run_route(sip_msg_t *msg, str *uri, char *route)
2802
+/**
2803
+ *
2804
+ */
2805
+static ds_rctx_t *_ds_rctx = NULL;
2806
+
2807
+/**
2808
+ *
2809
+ */
2810
+ds_rctx_t* ds_get_rctx(void)
2811
+{
2812
+	return _ds_rctx;
2813
+}
2814
+
2815
+static void ds_run_route(sip_msg_t *msg, str *uri, char *route, ds_rctx_t *rctx)
2784 2816
 {
2785 2817
 	int rt, backup_rt;
2786 2818
 	struct run_act_ctx ctx;
... ...
@@ -2793,7 +2825,7 @@ static void ds_run_route(sip_msg_t *msg, str *uri, char *route)
2793 2825
 		return;
2794 2826
 	}
2795 2827
 
2796
-	LM_DBG("ds_run_route event_route[%s]\n", route);
2828
+	LM_DBG("executing event_route[%s]\n", route);
2797 2829
 
2798 2830
 	rt = -1;
2799 2831
 	if(ds_event_callback.s==NULL || ds_event_callback.len<=0) {
... ...
@@ -2824,6 +2856,7 @@ static void ds_run_route(sip_msg_t *msg, str *uri, char *route)
2824 2856
 	}
2825 2857
 
2826 2858
 	if(rt>=0 || ds_event_callback.len>0) {
2859
+		_ds_rctx = rctx;
2827 2860
 		backup_rt = get_route_type();
2828 2861
 		set_route_type(REQUEST_ROUTE);
2829 2862
 		init_run_actions_ctx(&ctx);
... ...
@@ -2840,6 +2873,7 @@ static void ds_run_route(sip_msg_t *msg, str *uri, char *route)
2840 2873
 			}
2841 2874
 		}
2842 2875
 		set_route_type(backup_rt);
2876
+		_ds_rctx = NULL;
2843 2877
 	}
2844 2878
 }
2845 2879
 
... ...
@@ -3132,6 +3166,7 @@ static void ds_options_callback(
3132 3166
 	str uri = {0, 0};
3133 3167
 	sip_msg_t *fmsg;
3134 3168
 	int state;
3169
+	ds_rctx_t rctx;
3135 3170
 
3136 3171
 	/* The param contains the group, in which the failed host
3137 3172
 	 * can be found.*/
... ...
@@ -3154,8 +3189,19 @@ static void ds_options_callback(
3154 3189
 	uri.len = t->to.len - 8;
3155 3190
 	LM_DBG("OPTIONS-Request was finished with code %d (to %.*s, group %d)\n",
3156 3191
 			ps->code, uri.len, uri.s, group);
3157
-	if (ds_ping_latency_stats)
3192
+	if (ds_ping_latency_stats) {
3158 3193
 		ds_update_latency(group, &uri, ps->code);
3194
+	}
3195
+
3196
+	memset(&rctx, 0, sizeof(ds_rctx_t));
3197
+	rctx.code = ps->code;
3198
+	if(ps->rpl!=NULL) {
3199
+		if(ps->rpl!=FAKED_REPLY) {
3200
+			rctx.flags |= 1;
3201
+			rctx.reason = ps->rpl->first_line.u.reply.reason;
3202
+		}
3203
+	}
3204
+
3159 3205
 	/* ps->code contains the result-code of the request.
3160 3206
 	 *
3161 3207
 	 * We accept both a "200 OK" or the configured reply as a valid response */
... ...
@@ -3170,7 +3216,7 @@ static void ds_options_callback(
3170 3216
 
3171 3217
 		/* Check if in the meantime someone disabled the target through RPC or MI */
3172 3218
 		if(!(ds_get_state(group, &uri) & DS_DISABLED_DST)
3173
-				&& ds_update_state(fmsg, group, &uri, state) != 0) {
3219
+				&& ds_update_state(fmsg, group, &uri, state, &rctx) != 0) {
3174 3220
 			LM_ERR("Setting the state failed (%.*s, group %d)\n", uri.len,
3175 3221
 					uri.s, group);
3176 3222
 		}
... ...
@@ -3180,7 +3226,7 @@ static void ds_options_callback(
3180 3226
 			state |= DS_PROBING_DST;
3181 3227
 		/* Check if in the meantime someone disabled the target through RPC or MI */
3182 3228
 		if(!(ds_get_state(group, &uri) & DS_DISABLED_DST)
3183
-				&& ds_update_state(fmsg, group, &uri, state) != 0) {
3229
+				&& ds_update_state(fmsg, group, &uri, state, &rctx) != 0) {
3184 3230
 			LM_ERR("Setting the probing state failed (%.*s, group %d)\n",
3185 3231
 					uri.len, uri.s, group);
3186 3232
 		}
... ...
@@ -72,9 +72,14 @@
72 72
 #define DS_XAVP_CTX_SKIP_CNT	1
73 73
 
74 74
 #define DS_IRMODE_NOIPADDR	1
75
-
76 75
 /* clang-format on */
77 76
 
77
+typedef struct ds_rctx {
78
+	int flags;
79
+	int code;
80
+	str reason;
81
+} ds_rctx_t;
82
+
78 83
 extern str ds_db_url;
79 84
 extern str ds_table_name;
80 85
 extern str ds_set_id_col;
... ...
@@ -134,7 +139,8 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode);
134 139
 int ds_update_dst(struct sip_msg *msg, int upos, int mode);
135 140
 int ds_add_dst(int group, str *address, int flags);
136 141
 int ds_remove_dst(int group, str *address);
137
-int ds_update_state(sip_msg_t *msg, int group, str *address, int state);
142
+int ds_update_state(sip_msg_t *msg, int group, str *address, int state,
143
+		ds_rctx_t *rctx);
138 144
 int ds_reinit_state(int group, str *address, int state);
139 145
 int ds_reinit_state_all(int group, int state);
140 146
 int ds_mark_dst(struct sip_msg *msg, int mode);
... ...
@@ -259,4 +265,6 @@ void ds_avl_destroy(ds_set_t **node);
259 265
 
260 266
 int ds_manage_routes(sip_msg_t *msg, ds_select_state_t *rstate);
261 267
 
268
+ds_rctx_t* ds_get_rctx(void);
269
+
262 270
 #endif
... ...
@@ -183,6 +183,16 @@ static void destroy(void);
183 183
 
184 184
 static int ds_warn_fixup(void** param, int param_no);
185 185
 
186
+static int pv_get_dsv(sip_msg_t *msg, pv_param_t *param, pv_value_t *res);
187
+static int pv_parse_dsv(pv_spec_p sp, str *in);
188
+
189
+static pv_export_t mod_pvs[] = {
190
+	{ {"dsv", (sizeof("dsv")-1)}, PVT_OTHER, pv_get_dsv, 0,
191
+		pv_parse_dsv, 0, 0, 0 },
192
+
193
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
194
+};
195
+
186 196
 static cmd_export_t cmds[]={
187 197
 	{"ds_select",    (cmd_function)w_ds_select,            2,
188 198
 		fixup_igp_igp, 0, ANY_ROUTE},
... ...
@@ -287,7 +297,7 @@ struct module_exports exports= {
287 297
 	cmds,            /* cmd (cfg function) exports */
288 298
 	params,          /* param exports */
289 299
 	0,               /* exported rpc functions */
290
-	0,               /* exported pseudo-variables */
300
+	mod_pvs,         /* exported pseudo-variables */
291 301
 	0,               /* response handling function */
292 302
 	mod_init,        /* module init function */
293 303
 	child_init,      /* per-child init function */
... ...
@@ -1160,6 +1170,74 @@ void ds_ping_reply_codes_update(str *gname, str *name)
1160 1170
 	ds_parse_reply_codes();
1161 1171
 }
1162 1172
 
1173
+/**
1174
+ *
1175
+ */
1176
+static int pv_get_dsv(sip_msg_t *msg, pv_param_t *param, pv_value_t *res)
1177
+{
1178
+	ds_rctx_t *rctx;
1179
+
1180
+	if(param==NULL) {
1181
+		return -1;
1182
+	}
1183
+	rctx = ds_get_rctx();
1184
+	if(rctx==NULL) {
1185
+		return pv_get_null(msg, param, res);
1186
+	}
1187
+	switch(param->pvn.u.isname.name.n)
1188
+	{
1189
+		case 0:
1190
+			return pv_get_sintval(msg, param, res, rctx->code);
1191
+		case 1:
1192
+			if(rctx->reason.s!=NULL && rctx->reason.len>0) {
1193
+				return pv_get_strval(msg, param, res, &rctx->reason);
1194
+			}
1195
+			return pv_get_null(msg, param, res);
1196
+		case 2:
1197
+			return pv_get_sintval(msg, param, res, rctx->flags);
1198
+		default:
1199
+			return pv_get_null(msg, param, res);
1200
+	}
1201
+}
1202
+
1203
+/**
1204
+ *
1205
+ */
1206
+static int pv_parse_dsv(pv_spec_p sp, str *in)
1207
+{
1208
+	if(sp==NULL || in==NULL || in->len<=0)
1209
+		return -1;
1210
+
1211
+	switch(in->len)
1212
+	{
1213
+		case 4:
1214
+			if(strncmp(in->s, "code", 4)==0)
1215
+				sp->pvp.pvn.u.isname.name.n = 0;
1216
+			else goto error;
1217
+		break;
1218
+		case 5:
1219
+			if(strncmp(in->s, "flags", 5)==0)
1220
+				sp->pvp.pvn.u.isname.name.n = 2;
1221
+			else goto error;
1222
+		break;
1223
+		case 6:
1224
+			if(strncmp(in->s, "reason", 6)==0)
1225
+				sp->pvp.pvn.u.isname.name.n = 2;
1226
+			else goto error;
1227
+		break;
1228
+		default:
1229
+			goto error;
1230
+	}
1231
+	sp->pvp.pvn.type = PV_NAME_INTSTR;
1232
+	sp->pvp.pvn.u.isname.type = 0;
1233
+
1234
+	return 0;
1235
+
1236
+error:
1237
+	LM_ERR("unknown PV key: %.*s\n", in->len, in->s);
1238
+	return -1;
1239
+}
1240
+
1163 1241
 /* KEMI wrappers */
1164 1242
 /**
1165 1243
  *