00001
00051 #include <stdio.h>
00052 #include <string.h>
00053 #include <stdlib.h>
00054 #include <sys/types.h>
00055 #include <unistd.h>
00056
00057 #include "../../lib/kmi/mi.h"
00058 #include "../../sr_module.h"
00059 #include "../../dprint.h"
00060 #include "../../error.h"
00061 #include "../../ut.h"
00062 #include "../../route.h"
00063 #include "../../mem/mem.h"
00064 #include "../../mod_fix.h"
00065 #include "../../rpc.h"
00066 #include "../../rpc_lookup.h"
00067
00068 #include "ds_ht.h"
00069 #include "dispatch.h"
00070 #include "config.h"
00071 #include "api.h"
00072
00073 MODULE_VERSION
00074
00075 #define DS_SET_ID_COL "setid"
00076 #define DS_DEST_URI_COL "destination"
00077 #define DS_DEST_FLAGS_COL "flags"
00078 #define DS_DEST_PRIORITY_COL "priority"
00079 #define DS_DEST_ATTRS_COL "attrs"
00080 #define DS_TABLE_NAME "dispatcher"
00081
00083 char *dslistfile = CFG_DIR"dispatcher.list";
00084 int ds_force_dst = 1;
00085 int ds_flags = 0;
00086 int ds_use_default = 0;
00087 static str dst_avp_param = {NULL, 0};
00088 static str grp_avp_param = {NULL, 0};
00089 static str cnt_avp_param = {NULL, 0};
00090 static str dstid_avp_param = {NULL, 0};
00091 static str attrs_avp_param = {NULL, 0};
00092 str hash_pvar_param = {NULL, 0};
00093
00094 int_str dst_avp_name;
00095 unsigned short dst_avp_type;
00096 int_str grp_avp_name;
00097 unsigned short grp_avp_type;
00098 int_str cnt_avp_name;
00099 unsigned short cnt_avp_type;
00100 int_str dstid_avp_name;
00101 unsigned short dstid_avp_type;
00102 int_str attrs_avp_name;
00103 unsigned short attrs_avp_type;
00104
00105 pv_elem_t * hash_param_model = NULL;
00106
00107 int probing_threshhold = 1;
00108
00109 str ds_ping_method = {"OPTIONS",7};
00110 str ds_ping_from = {"sip:dispatcher@localhost", 24};
00111 static int ds_ping_interval = 0;
00112 int ds_probing_mode = DS_PROBE_NONE;
00113
00114 static str ds_ping_reply_codes_str= {NULL, 0};
00115 static int** ds_ping_reply_codes = NULL;
00116 static int* ds_ping_reply_codes_cnt;
00117
00118 int ds_hash_size = 0;
00119 int ds_hash_expire = 7200;
00120 int ds_hash_initexpire = 7200;
00121 int ds_hash_check_interval = 30;
00122
00123 str ds_outbound_proxy = {0, 0};
00124
00125
00126 struct tm_binds tmb;
00127
00128
00129 str ds_db_url = {NULL, 0};
00130 str ds_set_id_col = str_init(DS_SET_ID_COL);
00131 str ds_dest_uri_col = str_init(DS_DEST_URI_COL);
00132 str ds_dest_flags_col = str_init(DS_DEST_FLAGS_COL);
00133 str ds_dest_priority_col = str_init(DS_DEST_PRIORITY_COL);
00134 str ds_dest_attrs_col = str_init(DS_DEST_ATTRS_COL);
00135 str ds_table_name = str_init(DS_TABLE_NAME);
00136
00137 str ds_setid_pvname = {NULL, 0};
00138 pv_spec_t ds_setid_pv;
00139
00141 static int mod_init(void);
00142 static int child_init(int);
00143
00144 static int ds_parse_reply_codes();
00145 static int ds_init_rpc(void);
00146
00147 static int w_ds_select_dst(struct sip_msg*, char*, char*);
00148 static int w_ds_select_domain(struct sip_msg*, char*, char*);
00149 static int w_ds_next_dst(struct sip_msg*, char*, char*);
00150 static int w_ds_next_domain(struct sip_msg*, char*, char*);
00151 static int w_ds_mark_dst0(struct sip_msg*, char*, char*);
00152 static int w_ds_mark_dst1(struct sip_msg*, char*, char*);
00153 static int w_ds_load_unset(struct sip_msg*, char*, char*);
00154 static int w_ds_load_update(struct sip_msg*, char*, char*);
00155
00156 static int w_ds_is_from_list0(struct sip_msg*, char*, char*);
00157 static int w_ds_is_from_list1(struct sip_msg*, char*, char*);
00158
00159 static void destroy(void);
00160
00161 static int ds_warn_fixup(void** param, int param_no);
00162
00163 static struct mi_root* ds_mi_set(struct mi_root* cmd, void* param);
00164 static struct mi_root* ds_mi_list(struct mi_root* cmd, void* param);
00165 static struct mi_root* ds_mi_reload(struct mi_root* cmd_tree, void* param);
00166 static int mi_child_init(void);
00167
00168 static cmd_export_t cmds[]={
00169 {"ds_select_dst", (cmd_function)w_ds_select_dst, 2,
00170 fixup_igp_igp, 0, REQUEST_ROUTE|FAILURE_ROUTE},
00171 {"ds_select_domain", (cmd_function)w_ds_select_domain, 2,
00172 fixup_igp_igp, 0, REQUEST_ROUTE|FAILURE_ROUTE},
00173 {"ds_next_dst", (cmd_function)w_ds_next_dst, 0,
00174 ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
00175 {"ds_next_domain", (cmd_function)w_ds_next_domain, 0,
00176 ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE},
00177 {"ds_mark_dst", (cmd_function)w_ds_mark_dst0, 0,
00178 ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
00179 {"ds_mark_dst", (cmd_function)w_ds_mark_dst1, 1,
00180 ds_warn_fixup, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
00181 {"ds_is_from_list", (cmd_function)w_ds_is_from_list0, 0,
00182 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE},
00183 {"ds_is_from_list", (cmd_function)w_ds_is_from_list1, 1,
00184 fixup_uint_null, 0, ANY_ROUTE},
00185 {"ds_load_unset", (cmd_function)w_ds_load_unset, 0,
00186 0, 0, ANY_ROUTE},
00187 {"ds_load_update", (cmd_function)w_ds_load_update, 0,
00188 0, 0, ANY_ROUTE},
00189 {"bind_dispatcher", (cmd_function)bind_dispatcher, 0,
00190 0, 0, 0},
00191 {0,0,0,0,0,0}
00192 };
00193
00194
00195 static param_export_t params[]={
00196 {"list_file", STR_PARAM, &dslistfile},
00197 {"db_url", STR_PARAM, &ds_db_url.s},
00198 {"table_name", STR_PARAM, &ds_table_name.s},
00199 {"setid_col", STR_PARAM, &ds_set_id_col.s},
00200 {"destination_col", STR_PARAM, &ds_dest_uri_col.s},
00201 {"flags_col", STR_PARAM, &ds_dest_flags_col.s},
00202 {"priority_col", STR_PARAM, &ds_dest_priority_col.s},
00203 {"attrs_col", STR_PARAM, &ds_dest_attrs_col.s},
00204 {"force_dst", INT_PARAM, &ds_force_dst},
00205 {"flags", INT_PARAM, &ds_flags},
00206 {"use_default", INT_PARAM, &ds_use_default},
00207 {"dst_avp", STR_PARAM, &dst_avp_param.s},
00208 {"grp_avp", STR_PARAM, &grp_avp_param.s},
00209 {"cnt_avp", STR_PARAM, &cnt_avp_param.s},
00210 {"dstid_avp", STR_PARAM, &dstid_avp_param.s},
00211 {"attrs_avp", STR_PARAM, &attrs_avp_param.s},
00212 {"hash_pvar", STR_PARAM, &hash_pvar_param.s},
00213 {"setid_pvname", STR_PARAM, &ds_setid_pvname.s},
00214 {"ds_probing_threshhold", INT_PARAM, &probing_threshhold},
00215 {"ds_ping_method", STR_PARAM, &ds_ping_method.s},
00216 {"ds_ping_from", STR_PARAM, &ds_ping_from.s},
00217 {"ds_ping_interval", INT_PARAM, &ds_ping_interval},
00218 {"ds_ping_reply_codes", STR_PARAM, &ds_ping_reply_codes_str},
00219 {"ds_probing_mode", INT_PARAM, &ds_probing_mode},
00220 {"ds_hash_size", INT_PARAM, &ds_hash_size},
00221 {"ds_hash_expire", INT_PARAM, &ds_hash_expire},
00222 {"ds_hash_initexpire", INT_PARAM, &ds_hash_initexpire},
00223 {"ds_hash_check_interval", INT_PARAM, &ds_hash_check_interval},
00224 {"outbound_proxy", STR_PARAM, &ds_outbound_proxy.s},
00225 {0,0,0}
00226 };
00227
00228
00229 static mi_export_t mi_cmds[] = {
00230 { "ds_set_state", ds_mi_set, 0, 0, 0 },
00231 { "ds_list", ds_mi_list, MI_NO_INPUT_FLAG, 0, 0 },
00232 { "ds_reload", ds_mi_reload, 0, 0, mi_child_init},
00233 { 0, 0, 0, 0, 0}
00234 };
00235
00236
00238 struct module_exports exports= {
00239 "dispatcher",
00240 DEFAULT_DLFLAGS,
00241 cmds,
00242 params,
00243 0,
00244 mi_cmds,
00245 0,
00246 0,
00247 mod_init,
00248 0,
00249 (destroy_function) destroy,
00250 child_init
00251 };
00252
00256 static int mod_init(void)
00257 {
00258 pv_spec_t avp_spec;
00259
00260 if(register_mi_mod(exports.name, mi_cmds)!=0)
00261 {
00262 LM_ERR("failed to register MI commands\n");
00263 return -1;
00264 }
00265 if(ds_init_rpc()<0)
00266 {
00267 LM_ERR("failed to register RPC commands\n");
00268 return -1;
00269 }
00270
00271 if (dst_avp_param.s)
00272 dst_avp_param.len = strlen(dst_avp_param.s);
00273 if (grp_avp_param.s)
00274 grp_avp_param.len = strlen(grp_avp_param.s);
00275 if (cnt_avp_param.s)
00276 cnt_avp_param.len = strlen(cnt_avp_param.s);
00277 if (dstid_avp_param.s)
00278 dstid_avp_param.len = strlen(dstid_avp_param.s);
00279 if (attrs_avp_param.s)
00280 attrs_avp_param.len = strlen(attrs_avp_param.s);
00281 if (hash_pvar_param.s)
00282 hash_pvar_param.len = strlen(hash_pvar_param.s);
00283 if (ds_setid_pvname.s)
00284 ds_setid_pvname.len = strlen(ds_setid_pvname.s);
00285 if (ds_ping_from.s) ds_ping_from.len = strlen(ds_ping_from.s);
00286 if (ds_ping_method.s) ds_ping_method.len = strlen(ds_ping_method.s);
00287 if (ds_outbound_proxy.s) ds_outbound_proxy.len = strlen(ds_outbound_proxy.s);
00288
00289 if(cfg_declare("dispatcher", dispatcher_cfg_def,
00290 &default_dispatcher_cfg, cfg_sizeof(dispatcher),
00291 &dispatcher_cfg)){
00292 LM_ERR("Fail to declare the configuration\n");
00293 return -1;
00294 }
00295
00296
00297 ds_ping_reply_codes = (int**)shm_malloc(sizeof(unsigned int*));
00298 *ds_ping_reply_codes = 0;
00299 ds_ping_reply_codes_cnt = (int*)shm_malloc(sizeof(int));
00300 *ds_ping_reply_codes_cnt = 0;
00301 if(ds_ping_reply_codes_str.s) {
00302 ds_ping_reply_codes_str.len = strlen(ds_ping_reply_codes_str.s);
00303 cfg_get(dispatcher, dispatcher_cfg, ds_ping_reply_codes_str)
00304 = ds_ping_reply_codes_str;
00305 if(ds_parse_reply_codes()< 0)
00306 {
00307 return -1;
00308 }
00309 }
00310
00311 cfg_get(dispatcher, dispatcher_cfg, probing_threshhold)
00312 = probing_threshhold;
00313
00314
00315 if(init_data()!= 0)
00316 return -1;
00317
00318 if(ds_db_url.s)
00319 {
00320 ds_db_url.len = strlen(ds_db_url.s);
00321 ds_table_name.len = strlen(ds_table_name.s);
00322 ds_set_id_col.len = strlen(ds_set_id_col.s);
00323 ds_dest_uri_col.len = strlen(ds_dest_uri_col.s);
00324 ds_dest_flags_col.len = strlen(ds_dest_flags_col.s);
00325 ds_dest_priority_col.len = strlen(ds_dest_priority_col.s);
00326 ds_dest_attrs_col.len = strlen(ds_dest_attrs_col.s);
00327
00328 if(init_ds_db()!= 0)
00329 {
00330 LM_ERR("could not initiate a connect to the database\n");
00331 return -1;
00332 }
00333 } else {
00334 if(ds_load_list(dslistfile)!=0) {
00335 LM_ERR("no dispatching list loaded from file\n");
00336 return -1;
00337 } else {
00338 LM_DBG("loaded dispatching list\n");
00339 }
00340 }
00341
00342 if (dst_avp_param.s && dst_avp_param.len > 0)
00343 {
00344 if (pv_parse_spec(&dst_avp_param, &avp_spec)==0
00345 || avp_spec.type!=PVT_AVP)
00346 {
00347 LM_ERR("malformed or non AVP %.*s AVP definition\n",
00348 dst_avp_param.len, dst_avp_param.s);
00349 return -1;
00350 }
00351
00352 if(pv_get_avp_name(0, &(avp_spec.pvp), &dst_avp_name, &dst_avp_type)!=0)
00353 {
00354 LM_ERR("[%.*s]- invalid AVP definition\n", dst_avp_param.len,
00355 dst_avp_param.s);
00356 return -1;
00357 }
00358 } else {
00359 dst_avp_name.n = 0;
00360 dst_avp_type = 0;
00361 }
00362 if (grp_avp_param.s && grp_avp_param.len > 0)
00363 {
00364 if (pv_parse_spec(&grp_avp_param, &avp_spec)==0
00365 || avp_spec.type!=PVT_AVP)
00366 {
00367 LM_ERR("malformed or non AVP %.*s AVP definition\n",
00368 grp_avp_param.len, grp_avp_param.s);
00369 return -1;
00370 }
00371
00372 if(pv_get_avp_name(0, &(avp_spec.pvp), &grp_avp_name, &grp_avp_type)!=0)
00373 {
00374 LM_ERR("[%.*s]- invalid AVP definition\n", grp_avp_param.len,
00375 grp_avp_param.s);
00376 return -1;
00377 }
00378 } else {
00379 grp_avp_name.n = 0;
00380 grp_avp_type = 0;
00381 }
00382 if (cnt_avp_param.s && cnt_avp_param.len > 0)
00383 {
00384 if (pv_parse_spec(&cnt_avp_param, &avp_spec)==0
00385 || avp_spec.type!=PVT_AVP)
00386 {
00387 LM_ERR("malformed or non AVP %.*s AVP definition\n",
00388 cnt_avp_param.len, cnt_avp_param.s);
00389 return -1;
00390 }
00391
00392 if(pv_get_avp_name(0, &(avp_spec.pvp), &cnt_avp_name, &cnt_avp_type)!=0)
00393 {
00394 LM_ERR("[%.*s]- invalid AVP definition\n", cnt_avp_param.len,
00395 cnt_avp_param.s);
00396 return -1;
00397 }
00398 } else {
00399 cnt_avp_name.n = 0;
00400 cnt_avp_type = 0;
00401 }
00402 if (dstid_avp_param.s && dstid_avp_param.len > 0)
00403 {
00404 if (pv_parse_spec(&dstid_avp_param, &avp_spec)==0
00405 || avp_spec.type!=PVT_AVP)
00406 {
00407 LM_ERR("malformed or non AVP %.*s AVP definition\n",
00408 dstid_avp_param.len, dstid_avp_param.s);
00409 return -1;
00410 }
00411
00412 if(pv_get_avp_name(0, &(avp_spec.pvp), &dstid_avp_name,
00413 &dstid_avp_type)!=0)
00414 {
00415 LM_ERR("[%.*s]- invalid AVP definition\n", dstid_avp_param.len,
00416 dstid_avp_param.s);
00417 return -1;
00418 }
00419 } else {
00420 dstid_avp_name.n = 0;
00421 dstid_avp_type = 0;
00422 }
00423
00424 if (attrs_avp_param.s && attrs_avp_param.len > 0)
00425 {
00426 if (pv_parse_spec(&attrs_avp_param, &avp_spec)==0
00427 || avp_spec.type!=PVT_AVP)
00428 {
00429 LM_ERR("malformed or non AVP %.*s AVP definition\n",
00430 attrs_avp_param.len, attrs_avp_param.s);
00431 return -1;
00432 }
00433
00434 if(pv_get_avp_name(0, &(avp_spec.pvp), &attrs_avp_name,
00435 &attrs_avp_type)!=0)
00436 {
00437 LM_ERR("[%.*s]- invalid AVP definition\n", attrs_avp_param.len,
00438 attrs_avp_param.s);
00439 return -1;
00440 }
00441 } else {
00442 attrs_avp_name.n = 0;
00443 attrs_avp_type = 0;
00444 }
00445
00446 if (hash_pvar_param.s && *hash_pvar_param.s) {
00447 if(pv_parse_format(&hash_pvar_param, &hash_param_model) < 0
00448 || hash_param_model==NULL) {
00449 LM_ERR("malformed PV string: %s\n", hash_pvar_param.s);
00450 return -1;
00451 }
00452 } else {
00453 hash_param_model = NULL;
00454 }
00455
00456 if(ds_setid_pvname.s!=0)
00457 {
00458 if(pv_parse_spec(&ds_setid_pvname, &ds_setid_pv)==NULL
00459 || !pv_is_w(&ds_setid_pv))
00460 {
00461 LM_ERR("[%s]- invalid setid_pvname\n", ds_setid_pvname.s);
00462 return -1;
00463 }
00464 }
00465 if (dstid_avp_param.s && dstid_avp_param.len > 0)
00466 {
00467 if(ds_hash_size>0)
00468 {
00469 if(ds_hash_load_init(1<<ds_hash_size, ds_hash_expire,
00470 ds_hash_initexpire)<0)
00471 return -1;
00472 register_timer(ds_ht_timer, NULL, ds_hash_check_interval);
00473 } else {
00474 LM_ERR("call load dispatching DSTID_AVP set but no size"
00475 " for hash table\n");
00476 return -1;
00477 }
00478 }
00479
00480 if (ds_ping_interval > 0)
00481 {
00482
00483
00484
00485 if (load_tm_api( &tmb ) == -1)
00486 {
00487 LM_ERR("could not load the TM-functions - disable DS ping\n");
00488 return -1;
00489 }
00490
00491
00492
00493 register_timer(ds_check_timer, NULL, ds_ping_interval);
00494 }
00495
00496 return 0;
00497 }
00498
00502 static int child_init(int rank)
00503 {
00504 srand((11+rank)*getpid()*7);
00505
00506 return 0;
00507 }
00508
00509 static int mi_child_init(void)
00510 {
00511
00512 if(ds_db_url.s)
00513 return ds_connect_db();
00514 return 0;
00515
00516 }
00517
00521 static void destroy(void)
00522 {
00523 ds_destroy_list();
00524 if(ds_db_url.s)
00525 ds_disconnect_db();
00526 ds_hash_load_destroy();
00527 if(ds_ping_reply_codes)
00528 shm_free(ds_ping_reply_codes);
00529
00530 }
00531
00535 static int w_ds_select_dst(struct sip_msg* msg, char* set, char* alg)
00536 {
00537 int a, s;
00538
00539 if(msg==NULL)
00540 return -1;
00541 if(fixup_get_ivalue(msg, (gparam_p)set, &s)!=0)
00542 {
00543 LM_ERR("no dst set value\n");
00544 return -1;
00545 }
00546 if(fixup_get_ivalue(msg, (gparam_p)alg, &a)!=0)
00547 {
00548 LM_ERR("no alg value\n");
00549 return -1;
00550 }
00551
00552 return ds_select_dst(msg, s, a, 0 );
00553 }
00554
00558 static int w_ds_select_domain(struct sip_msg* msg, char* set, char* alg)
00559 {
00560 int a, s;
00561 if(msg==NULL)
00562 return -1;
00563
00564 if(fixup_get_ivalue(msg, (gparam_p)set, &s)!=0)
00565 {
00566 LM_ERR("no dst set value\n");
00567 return -1;
00568 }
00569 if(fixup_get_ivalue(msg, (gparam_p)alg, &a)!=0)
00570 {
00571 LM_ERR("no alg value\n");
00572 return -1;
00573 }
00574
00575 return ds_select_dst(msg, s, a, 1);
00576 }
00577
00581 static int w_ds_next_dst(struct sip_msg *msg, char *str1, char *str2)
00582 {
00583 return ds_next_dst(msg, 0);
00584 }
00585
00589 static int w_ds_next_domain(struct sip_msg *msg, char *str1, char *str2)
00590 {
00591 return ds_next_dst(msg, 1);
00592 }
00593
00597 static int w_ds_mark_dst0(struct sip_msg *msg, char *str1, char *str2)
00598 {
00599 int state;
00600
00601 state = DS_INACTIVE_DST;
00602 if (ds_probing_mode==DS_PROBE_ALL)
00603 state |= DS_PROBING_DST;
00604
00605 return ds_mark_dst(msg, state);
00606 }
00607
00611 static int w_ds_mark_dst1(struct sip_msg *msg, char *str1, char *str2)
00612 {
00613 int state;
00614 int len;
00615
00616 if(str1==NULL)
00617 return w_ds_mark_dst0(msg, NULL, NULL);
00618
00619 len = strlen(str1);
00620 state = 0;
00621 if (len>1 && (str1[1]=='p' || str1[1]=='P'))
00622 state |= DS_PROBING_DST;
00623
00624 if(str1[0]=='i' || str1[0]=='I')
00625 state |= DS_INACTIVE_DST;
00626 else if(str1[0]=='t' || str1[0]=='T')
00627 state |= DS_TRYING_DST;
00628 else if(str1[0]=='d' || str1[0]=='D')
00629 state = DS_DISABLED_DST;
00630 else if(str1[0]=='p' || str1[0]=='P')
00631 state = DS_INACTIVE_DST|DS_PROBING_DST;
00632 return ds_mark_dst(msg, state);
00633 }
00634
00635
00639 static int w_ds_load_unset(struct sip_msg *msg, char *str1, char *str2)
00640 {
00641 if(ds_load_unset(msg)<0)
00642 return -1;
00643 return 1;
00644 }
00645
00649 static int w_ds_load_update(struct sip_msg *msg, char *str1, char *str2)
00650 {
00651 if(ds_load_update(msg)<0)
00652 return -1;
00653 return 1;
00654 }
00655
00659 static int ds_warn_fixup(void** param, int param_no)
00660 {
00661 if(!dst_avp_param.s || !grp_avp_param.s || !cnt_avp_param.s)
00662 {
00663 LM_ERR("failover functions used, but AVPs paraamters required"
00664 " are NULL -- feature disabled\n");
00665 }
00666 return 0;
00667 }
00668
00669
00670
00671 static struct mi_root* ds_mi_set(struct mi_root* cmd_tree, void* param)
00672 {
00673 str sp;
00674 int ret;
00675 unsigned int group, state;
00676 struct mi_node* node;
00677
00678 node = cmd_tree->node.kids;
00679 if(node == NULL)
00680 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00681 sp = node->value;
00682 if(sp.len<=0 || !sp.s)
00683 {
00684 LM_ERR("bad state value\n");
00685 return init_mi_tree(500, "bad state value", 15);
00686 }
00687
00688 state = 0;
00689 if(sp.s[0]=='0' || sp.s[0]=='I' || sp.s[0]=='i') {
00690
00691 state |= DS_INACTIVE_DST;
00692 if((sp.len>1) && (sp.s[1]=='P' || sp.s[1]=='p'))
00693 state |= DS_PROBING_DST;
00694 } else if(sp.s[0]=='1' || sp.s[0]=='A' || sp.s[0]=='a') {
00695
00696 if((sp.len>1) && (sp.s[1]=='P' || sp.s[1]=='p'))
00697 state |= DS_PROBING_DST;
00698 } else if(sp.s[0]=='2' || sp.s[0]=='D' || sp.s[0]=='d') {
00699
00700 state |= DS_DISABLED_DST;
00701 } else if(sp.s[0]=='3' || sp.s[0]=='T' || sp.s[0]=='t') {
00702
00703 state |= DS_TRYING_DST;
00704 if((sp.len>1) && (sp.s[1]=='P' || sp.s[1]=='p'))
00705 state |= DS_PROBING_DST;
00706 } else {
00707 LM_ERR("unknow state value\n");
00708 return init_mi_tree(500, "unknown state value", 19);
00709 }
00710 node = node->next;
00711 if(node == NULL)
00712 return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00713 sp = node->value;
00714 if(sp.s == NULL)
00715 {
00716 return init_mi_tree(500, "group not found", 15);
00717 }
00718
00719 if(str2int(&sp, &group))
00720 {
00721 LM_ERR("bad group value\n");
00722 return init_mi_tree( 500, "bad group value", 16);
00723 }
00724
00725 node= node->next;
00726 if(node == NULL)
00727 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00728
00729 sp = node->value;
00730 if(sp.s == NULL)
00731 {
00732 return init_mi_tree(500,"address not found", 18 );
00733 }
00734
00735 ret = ds_reinit_state(group, &sp, state);
00736
00737 if(ret!=0)
00738 {
00739 return init_mi_tree(404, "destination not found", 21);
00740 }
00741
00742 return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00743 }
00744
00745
00746
00747
00748 static struct mi_root* ds_mi_list(struct mi_root* cmd_tree, void* param)
00749 {
00750 struct mi_root* rpl_tree;
00751
00752 rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00753 if (rpl_tree==NULL)
00754 return 0;
00755
00756 if( ds_print_mi_list(&rpl_tree->node)< 0 )
00757 {
00758 LM_ERR("failed to add node\n");
00759 free_mi_tree(rpl_tree);
00760 return 0;
00761 }
00762
00763 return rpl_tree;
00764 }
00765
00766 #define MI_ERR_RELOAD "ERROR Reloading data"
00767 #define MI_ERR_RELOAD_LEN (sizeof(MI_ERR_RELOAD)-1)
00768 #define MI_NOT_SUPPORTED "DB mode not configured"
00769 #define MI_NOT_SUPPORTED_LEN (sizeof(MI_NOT_SUPPORTED)-1)
00770 #define MI_ERR_DSLOAD "No reload support for call load dispatching"
00771 #define MI_ERR_DSLOAD_LEN (sizeof(MI_ERR_DSLOAD)-1)
00772
00773 static struct mi_root* ds_mi_reload(struct mi_root* cmd_tree, void* param)
00774 {
00775 if(!ds_db_url.s) {
00776 if (ds_load_list(dslistfile)!=0)
00777 return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
00778 } else {
00779 if(ds_load_db()<0)
00780 return init_mi_tree(500, MI_ERR_RELOAD, MI_ERR_RELOAD_LEN);
00781 }
00782 return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
00783 }
00784
00785
00786 static int w_ds_is_from_list0(struct sip_msg *msg, char *str1, char *str2)
00787 {
00788 return ds_is_from_list(msg, -1);
00789 }
00790
00791
00792 static int w_ds_is_from_list1(struct sip_msg *msg, char *set, char *str2)
00793 {
00794 return ds_is_from_list(msg, (int)(long)set);
00795 }
00796
00797 static int ds_parse_reply_codes() {
00798 param_t* params_list = NULL;
00799 param_t *pit=NULL;
00800 int list_size = 0;
00801 int i = 0;
00802 int pos = 0;
00803 int code = 0;
00804 str input = {0, 0};
00805 int* ds_ping_reply_codes_new = NULL;
00806 int* ds_ping_reply_codes_old = NULL;
00807
00808
00809 if (cfg_get(dispatcher, dispatcher_cfg, ds_ping_reply_codes_str).s == 0
00810 || cfg_get(dispatcher, dispatcher_cfg, ds_ping_reply_codes_str).len<=0)
00811 return 0;
00812
00813
00814 input.s = cfg_get(dispatcher, dispatcher_cfg, ds_ping_reply_codes_str).s;
00815 input.len = cfg_get(dispatcher, dispatcher_cfg, ds_ping_reply_codes_str).len;
00816
00817
00818 if (parse_params(&input, CLASS_ANY, 0, ¶ms_list)<0)
00819 return -1;
00820
00821
00822 for (pit = params_list; pit; pit=pit->next)
00823 {
00824 if (pit->name.len==4
00825 && strncasecmp(pit->name.s, "code", 4)==0) {
00826 str2sint(&pit->body, &code);
00827 if ((code >= 100) && (code < 700))
00828 list_size += 1;
00829 } else if (pit->name.len==5
00830 && strncasecmp(pit->name.s, "class", 5)==0) {
00831 str2sint(&pit->body, &code);
00832 if ((code >= 1) && (code < 7))
00833 list_size += 100;
00834 }
00835 }
00836 LM_DBG("Should be %d Destinations.\n", list_size);
00837
00838 if (list_size > 0) {
00839
00840 ds_ping_reply_codes_new = (int*)shm_malloc(list_size * sizeof(int));
00841 if(ds_ping_reply_codes_new== NULL)
00842 {
00843 free_params(params_list);
00844 LM_ERR("no more memory\n");
00845 return -1;
00846 }
00847
00848
00849 for (pit = params_list; pit; pit=pit->next)
00850 {
00851 if (pit->name.len==4
00852 && strncasecmp(pit->name.s, "code", 4)==0) {
00853 str2sint(&pit->body, &code);
00854 if ((code >= 100) && (code < 700))
00855 ds_ping_reply_codes_new[pos++] = code;
00856 } else if (pit->name.len==5
00857 && strncasecmp(pit->name.s, "class", 5)==0) {
00858 str2sint(&pit->body, &code);
00859 if ((code >= 1) && (code < 7)) {
00860
00861 for (i = (code*100); i <= ((code*100)+99); i++)
00862 ds_ping_reply_codes_new[pos++] = i;
00863 }
00864 }
00865 }
00866 } else {
00867 ds_ping_reply_codes_new = 0;
00868 }
00869 free_params(params_list);
00870
00871
00872 if (list_size > *ds_ping_reply_codes_cnt) {
00873
00874 ds_ping_reply_codes_old = *ds_ping_reply_codes;
00875 *ds_ping_reply_codes = ds_ping_reply_codes_new;
00876
00877 *ds_ping_reply_codes_cnt = list_size;
00878
00879 if(ds_ping_reply_codes_old)
00880 shm_free(ds_ping_reply_codes_old);
00881
00882 } else {
00883
00884 *ds_ping_reply_codes_cnt = list_size;
00885
00886 ds_ping_reply_codes_old = *ds_ping_reply_codes;
00887 *ds_ping_reply_codes = ds_ping_reply_codes_new;
00888
00889 if(ds_ping_reply_codes_old)
00890 shm_free(ds_ping_reply_codes_old);
00891 }
00892
00893 for (i =0; i< *ds_ping_reply_codes_cnt; i++)
00894 {
00895 LM_DBG("Dispatcher: Now accepting Reply-Code %d (%d/%d) as valid\n",
00896 (*ds_ping_reply_codes)[i], (i+1), *ds_ping_reply_codes_cnt);
00897 }
00898 return 0;
00899 }
00900
00901 int ds_ping_check_rplcode(int code)
00902 {
00903 int i;
00904
00905 for (i =0; i< *ds_ping_reply_codes_cnt; i++)
00906 {
00907 if((*ds_ping_reply_codes)[i] == code)
00908 return 1;
00909 }
00910
00911 return 0;
00912 }
00913
00914 void ds_ping_reply_codes_update(str* gname, str* name){
00915 ds_parse_reply_codes();
00916 }
00917
00918
00919
00920 static const char* dispatcher_rpc_reload_doc[2] = {
00921 "Reload dispatcher destination sets",
00922 0
00923 };
00924
00925
00926
00927
00928
00929 static void dispatcher_rpc_reload(rpc_t* rpc, void* ctx)
00930 {
00931 if(!ds_db_url.s) {
00932 if (ds_load_list(dslistfile)!=0) {
00933 rpc->fault(ctx, 500, "Reload Failed");
00934 return;
00935 }
00936 } else {
00937 if(ds_load_db()<0) {
00938 rpc->fault(ctx, 500, "Reload Failed");
00939 return;
00940 }
00941 }
00942 return;
00943 }
00944
00945
00946
00947 static const char* dispatcher_rpc_list_doc[2] = {
00948 "Return the content of dispatcher sets",
00949 0
00950 };
00951
00952
00953
00954
00955
00956 static void dispatcher_rpc_list(rpc_t* rpc, void* ctx)
00957 {
00958 void* th;
00959 void* ih;
00960 void* vh;
00961 int j;
00962 char c[3];
00963 str data = {"", 0};
00964 ds_set_t *ds_list;
00965 int ds_list_nr;
00966 ds_set_t *list;
00967
00968 ds_list = ds_get_list();
00969 ds_list_nr = ds_get_list_nr();
00970
00971 if(ds_list==NULL || ds_list_nr<=0)
00972 {
00973 LM_ERR("no destination sets\n");
00974 rpc->fault(ctx, 500, "No Destination Sets");
00975 return;
00976 }
00977
00978
00979 if (rpc->add(ctx, "{", &th) < 0)
00980 {
00981 rpc->fault(c, 500, "Internal error root reply");
00982 return;
00983 }
00984 if(rpc->struct_add(th, "d{",
00985 "SET_NO", ds_list_nr,
00986 "SET", &ih)<0)
00987 {
00988 rpc->fault(c, 500, "Internal error set structure");
00989 return;
00990 }
00991
00992
00993 for(list = ds_list; list!= NULL; list= list->next)
00994 {
00995 if(rpc->struct_add(ih, "d",
00996 "SET_ID", list->id)<0)
00997 {
00998 rpc->fault(c, 500, "Internal error creating set id");
00999 return;
01000 }
01001
01002 for(j=0; j<list->nr; j++)
01003 {
01004 if(rpc->struct_add(ih, "{",
01005 "DEST", &vh)<0)
01006 {
01007 rpc->fault(c, 500, "Internal error creating dest");
01008 return;
01009 }
01010
01011 memset(&c, 0, sizeof(c));
01012 if (list->dlist[j].flags & DS_INACTIVE_DST)
01013 c[0] = 'I';
01014 else if (list->dlist[j].flags & DS_DISABLED_DST)
01015 c[0] = 'D';
01016 else if (list->dlist[j].flags & DS_TRYING_DST)
01017 c[0] = 'T';
01018 else
01019 c[0] = 'A';
01020
01021 if (list->dlist[j].flags & DS_PROBING_DST)
01022 c[1] = 'P';
01023 else
01024 c[1] = 'X';
01025
01026 if(rpc->struct_add(vh, "SsdS",
01027 "URI", &list->dlist[j].uri,
01028 "FLAGS", c,
01029 "PRIORITY", list->dlist[j].priority,
01030 "ATTRS", (list->dlist[j].attrs.body.s)?
01031 &(list->dlist[j].attrs.body):&data)<0)
01032 {
01033 rpc->fault(c, 500, "Internal error creating dest struct");
01034 return;
01035 }
01036 }
01037 }
01038
01039 return;
01040 }
01041
01042
01043 static const char* dispatcher_rpc_set_state_doc[2] = {
01044 "Set the state of a destination address",
01045 0
01046 };
01047
01048
01049
01050
01051
01052 static void dispatcher_rpc_set_state(rpc_t* rpc, void* ctx)
01053 {
01054 int group;
01055 str dest;
01056 str state;
01057 int stval;
01058
01059 if(rpc->scan(ctx, ".SdS", &state, &group, &dest)<3)
01060 {
01061 rpc->fault(ctx, 500, "Invalid Parameters");
01062 return;
01063 }
01064 if(state.len<=0 || state.s==NULL)
01065 {
01066 LM_ERR("bad state value\n");
01067 rpc->fault(ctx, 500, "Invalid State Parameter");
01068 return;
01069 }
01070
01071 stval = 0;
01072 if(state.s[0]=='0' || state.s[0]=='I' || state.s[0]=='i') {
01073
01074 stval |= DS_INACTIVE_DST;
01075 if((state.len>1) && (state.s[1]=='P' || state.s[1]=='p'))
01076 stval |= DS_PROBING_DST;
01077 } else if(state.s[0]=='1' || state.s[0]=='A' || state.s[0]=='a') {
01078
01079 if((state.len>1) && (state.s[1]=='P' || state.s[1]=='p'))
01080 stval |= DS_PROBING_DST;
01081 } else if(state.s[0]=='2' || state.s[0]=='D' || state.s[0]=='d') {
01082
01083 stval |= DS_DISABLED_DST;
01084 } else if(state.s[0]=='3' || state.s[0]=='T' || state.s[0]=='t') {
01085
01086 stval |= DS_TRYING_DST;
01087 if((state.len>1) && (state.s[1]=='P' || state.s[1]=='p'))
01088 stval |= DS_PROBING_DST;
01089 } else {
01090 LM_ERR("unknow state value\n");
01091 rpc->fault(ctx, 500, "Unknown State Value");
01092 return;
01093 }
01094
01095 if(ds_reinit_state(group, &dest, stval)<0)
01096 {
01097 rpc->fault(ctx, 500, "State Update Failed");
01098 return;
01099 }
01100
01101 return;
01102 }
01103
01104
01105 rpc_export_t dispatcher_rpc_cmds[] = {
01106 {"dispatcher.reload", dispatcher_rpc_reload,
01107 dispatcher_rpc_reload_doc, 0},
01108 {"dispatcher.list", dispatcher_rpc_list,
01109 dispatcher_rpc_list_doc, 0},
01110 {"dispatcher.set_state", dispatcher_rpc_set_state,
01111 dispatcher_rpc_set_state_doc, 0},
01112 {0, 0, 0, 0}
01113 };
01114
01118 static int ds_init_rpc(void)
01119 {
01120 if (rpc_register_array(dispatcher_rpc_cmds)!=0)
01121 {
01122 LM_ERR("failed to register RPC commands\n");
01123 return -1;
01124 }
01125 return 0;
01126 }