modules_k/dispatcher/dispatcher.c

Go to the documentation of this file.
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; /* number of failed requests, before a destination
00108                                                            is taken into probing */
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 /* tm */
00126 struct tm_binds tmb;
00127 
00128 /*db */
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, /* dlopen flags */
00241         cmds,
00242         params,
00243         0,          /* exported statistics */
00244         mi_cmds,    /* exported MI functions */
00245         0,          /* exported pseudo-variables */
00246         0,          /* extra processes */
00247         mod_init,   /* module initialization function */
00248         0,
00249         (destroy_function) destroy,
00250         child_init  /* per-child init function */
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         /* Initialize the counter */
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         /* Copy Threshhold to Config */
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         /* Only, if the Probing-Timer is enabled the TM-API needs to be loaded: */
00480         if (ds_ping_interval > 0)
00481         {
00482                 /*****************************************************
00483                  * TM-Bindings
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                  * Register the PING-Timer
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 /*set dst uri*/);
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/*set host port*/);
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/*set dst uri*/);
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/*set host port*/);
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 /************************** MI STUFF ************************/
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                 /* set inactive */
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                 /* set active */
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                 /* set disabled */
00700                 state |= DS_DISABLED_DST;
00701         } else if(sp.s[0]=='3' || sp.s[0]=='T' || sp.s[0]=='t') {
00702                 /* set trying */
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         /* Validate String: */
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         /* parse_params will modify the string pointer of .s, so we need to make a copy. */
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         /* Parse the parameters: */
00818         if (parse_params(&input, CLASS_ANY, 0, &params_list)<0)
00819                 return -1;
00820 
00821         /* Get the number of entries in the list */
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                 /* Allocate Memory for the new list: */
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                 /* Now create the list of valid reply-codes: */
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                                         /* Add every code from this class, e.g. 100 to 199 */
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         /* More reply-codes? Change Pointer and then set number of codes. */
00872         if (list_size > *ds_ping_reply_codes_cnt) {
00873                 // Copy Pointer
00874                 ds_ping_reply_codes_old = *ds_ping_reply_codes;
00875                 *ds_ping_reply_codes = ds_ping_reply_codes_new;
00876                 // Done: Set new Number of entries:
00877                 *ds_ping_reply_codes_cnt = list_size;
00878                 // Free the old memory area:
00879                 if(ds_ping_reply_codes_old)
00880                         shm_free(ds_ping_reply_codes_old);      
00881                 /* Less or equal? Set the number of codes first. */
00882         } else {
00883                 // Done:
00884                 *ds_ping_reply_codes_cnt = list_size;
00885                 // Copy Pointer
00886                 ds_ping_reply_codes_old = *ds_ping_reply_codes;
00887                 *ds_ping_reply_codes = ds_ping_reply_codes_new;
00888                 // Free the old memory area:
00889                 if(ds_ping_reply_codes_old)
00890                         shm_free(ds_ping_reply_codes_old);      
00891         }
00892         /* Print the list as INFO: */
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 /*** RPC implementation ***/
00919 
00920 static const char* dispatcher_rpc_reload_doc[2] = {
00921         "Reload dispatcher destination sets",
00922         0
00923 };
00924 
00925 
00926 /*
00927  * RPC command to reload dispatcher destination sets
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  * RPC command to print dispatcher destination sets
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         /* add entry node */
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  * RPC command to set the state of a destination address
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                 /* set inactive */
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                 /* set active */
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                 /* set disabled */
01083                 stval |= DS_DISABLED_DST;
01084         } else if(state.s[0]=='3' || state.s[0]=='T' || state.s[0]=='t') {
01085                 /* set trying */
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 }