From d4aebdcca668f2d3357826d172a81d3d815b3060 Mon Sep 17 00:00:00 2001 From: lazedo Date: Sun, 25 Jun 2017 11:27:14 +0100 Subject: [PATCH] dispatcher: runtime status access from script --- src/modules/dispatcher/dispatch.c | 94 ++++++++---- src/modules/dispatcher/dispatch.h | 4 + src/modules/dispatcher/dispatcher.c | 139 ++++++++++++++++++ .../dispatcher/doc/dispatcher_admin.xml | 98 +++++++++++- 4 files changed, 302 insertions(+), 33 deletions(-) diff --git a/src/modules/dispatcher/dispatch.c b/src/modules/dispatcher/dispatch.c index 38a6213de1e..fb7847805b1 100644 --- a/src/modules/dispatcher/dispatch.c +++ b/src/modules/dispatcher/dispatch.c @@ -93,6 +93,24 @@ void shuffle_uint100array(unsigned int *arr); int ds_reinit_rweight_on_state_change( int old_state, int new_state, ds_set_t *dset); +void clear_dest(ds_dest_t *dp) +{ + if(dp != NULL) { + if(dp->uri.s != NULL) + shm_free(dp->uri.s); + if(dp->description.s != NULL) + shm_free(dp->description.s); + } +} + +void free_dest(ds_dest_t *dp) +{ + if(dp != NULL) { + clear_dest(dp); + shm_free(dp); + } +} + /** * */ @@ -282,7 +300,7 @@ int ds_set_attrs(ds_dest_t *dest, str *attrs) /** * */ -ds_dest_t *pack_dest(str uri, int flags, int priority, str *attrs) +ds_dest_t *pack_dest(int id, str uri, int flags, int priority, str *attrs, str* desc) { ds_dest_t *dp = NULL; /* For DNS-Lookups */ @@ -314,6 +332,8 @@ ds_dest_t *pack_dest(str uri, int flags, int priority, str *attrs) } memset(dp, 0, sizeof(ds_dest_t)); + dp->id = id; + dp->uri.s = (char *)shm_malloc((uri.len + 1) * sizeof(char)); if(dp->uri.s == NULL) { LM_ERR("no more memory!\n"); @@ -323,6 +343,17 @@ ds_dest_t *pack_dest(str uri, int flags, int priority, str *attrs) dp->uri.s[uri.len] = '\0'; dp->uri.len = uri.len; + if(desc != NULL && desc->len > 0) { + dp->description.s = (char *)shm_malloc((desc->len + 1) * sizeof(char)); + if(dp->description.s == NULL) { + LM_ERR("no more memory!\n"); + goto err; + } + strncpy(dp->description.s, desc->s, desc->len); + dp->description.s[desc->len] = '\0'; + dp->description.len = desc->len; + } + dp->flags = flags; dp->priority = priority; @@ -383,19 +414,14 @@ ds_dest_t *pack_dest(str uri, int flags, int priority, str *attrs) return dp; err: - if(dp != NULL) { - if(dp->uri.s != NULL) - shm_free(dp->uri.s); - shm_free(dp); - } - + free_dest(dp); return NULL; } /** * */ -int add_dest2list(int id, str uri, int flags, int priority, str *attrs, +int add_dest2list(int setid, int id, str uri, int flags, int priority, str *attrs, str *desc, int list_idx, int *setn) { ds_dest_t *dp = NULL; @@ -403,11 +429,11 @@ int add_dest2list(int id, str uri, int flags, int priority, str *attrs, ds_dest_t *dp0 = NULL; ds_dest_t *dp1 = NULL; - dp = pack_dest(uri, flags, priority, attrs); + dp = pack_dest(id, uri, flags, priority, attrs, desc); if(!dp) goto err; - sp = ds_avl_insert(&ds_lists[list_idx], id, setn); + sp = ds_avl_insert(&ds_lists[list_idx], setid, setn); if(!sp) { LM_ERR("no more memory.\n"); goto err; @@ -439,12 +465,7 @@ int add_dest2list(int id, str uri, int flags, int priority, str *attrs, return 0; err: - if(dp != NULL) { - if(dp->uri.s != NULL) - shm_free(dp->uri.s); - shm_free(dp); - } - + free_dest(dp); return -1; } @@ -625,7 +646,7 @@ int ds_load_list(char *lfile) { char line[256], *p; FILE *f = NULL; - int id, setn, flags, priority; + int setid, id, setn, flags, priority; str uri; str attrs; @@ -645,13 +666,14 @@ int ds_load_list(char *lfile) return -1; } - id = setn = flags = priority = 0; + setid = id = setn = flags = priority = 0; *next_idx = (*crt_idx + 1) % 2; ds_avl_destroy(&ds_lists[*next_idx]); p = fgets(line, 256, f); while(p) { + id++; /* eat all white spaces */ while(*p && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')) p++; @@ -659,9 +681,9 @@ int ds_load_list(char *lfile) goto next_line; /* get set id */ - id = 0; + setid = 0; while(*p >= '0' && *p <= '9') { - id = id * 10 + (*p - '0'); + setid = setid * 10 + (*p - '0'); p++; } @@ -723,7 +745,7 @@ int ds_load_list(char *lfile) attrs.len = p - attrs.s; add_destination: - if(add_dest2list(id, uri, flags, priority, &attrs, *next_idx, &setn) + if(add_dest2list(setid, id, uri, flags, priority, &attrs, NULL, *next_idx, &setn) != 0) LM_WARN("unable to add destination %.*s to set %d -- skipping\n", uri.len, uri.s, id); @@ -849,19 +871,21 @@ int ds_reload_db(void) /*! \brief load groups of destinations from DB*/ int ds_load_db(void) { - int i, id, nr_rows, setn; + int i, setid, id, nr_rows, setn; int flags; int priority; int nrcols; int dest_errs = 0; str uri; + str desc = {0, 0}; str attrs = {0, 0}; db1_res_t *res; db_val_t *values; db_row_t *rows; - db_key_t query_cols[5] = {&ds_set_id_col, &ds_dest_uri_col, - &ds_dest_flags_col, &ds_dest_priority_col, &ds_dest_attrs_col}; + db_key_t query_cols[7] = {&ds_set_id_col, &ds_dest_uri_col, + &ds_dest_flags_col, &ds_dest_priority_col, &ds_dest_attrs_col, + &ds_dest_id_col, &ds_dest_desc_col}; nrcols = 2; if(_ds_table_version == DS_TABLE_VERSION2) @@ -869,7 +893,7 @@ int ds_load_db(void) else if(_ds_table_version == DS_TABLE_VERSION3) nrcols = 4; else if(_ds_table_version == DS_TABLE_VERSION4) - nrcols = 5; + nrcols = 7; if((*crt_idx) != (*next_idx)) { LM_WARN("load command already generated, aborting reload...\n"); @@ -905,7 +929,7 @@ int ds_load_db(void) for(i = 0; i < nr_rows; i++) { values = ROW_VALUES(rows + i); - id = VAL_INT(values); + setid = VAL_INT(values); uri.s = VAL_STR(values + 1).s; uri.len = strlen(uri.s); flags = 0; @@ -917,12 +941,21 @@ int ds_load_db(void) attrs.s = 0; attrs.len = 0; + id = i+1; + desc.s = 0; + desc.len = 0; + if(nrcols >= 5) { attrs.s = VAL_STR(values + 4).s; attrs.len = strlen(attrs.s); + + id = VAL_INT(values + 5); + + desc.s = VAL_STR(values + 6).s; + desc.len = strlen(desc.s); + } - if(add_dest2list(id, uri, flags, priority, &attrs, *next_idx, &setn) - != 0) { + if(add_dest2list(setid, id, uri, flags, priority, &attrs, &desc, *next_idx, &setn) != 0) { dest_errs++; LM_WARN("unable to add destination %.*s to set %d -- skipping\n", uri.len, uri.s, id); @@ -2805,10 +2838,7 @@ void ds_avl_destroy(ds_set_t **node_ptr) ds_avl_destroy(&node->next[i]); for(dest = node->dlist; dest != NULL; dest = dest->next) { - if(dest->uri.s != NULL) { - shm_free(dest->uri.s); - dest->uri.s = NULL; - } + clear_dest(dest); } if(node->dlist != NULL) shm_free(node->dlist); diff --git a/src/modules/dispatcher/dispatch.h b/src/modules/dispatcher/dispatch.h index 6ab8d5661e0..0770246882b 100644 --- a/src/modules/dispatcher/dispatch.h +++ b/src/modules/dispatcher/dispatch.h @@ -60,10 +60,12 @@ extern str ds_db_url; extern str ds_table_name; extern str ds_set_id_col; +extern str ds_dest_id_col; extern str ds_dest_uri_col; extern str ds_dest_flags_col; extern str ds_dest_priority_col; extern str ds_dest_attrs_col; +extern str ds_dest_desc_col; extern int ds_flags; extern int ds_use_default; @@ -157,7 +159,9 @@ typedef struct _ds_attrs { } ds_attrs_t; typedef struct _ds_dest { + int id; str uri; + str description; int flags; int priority; int dload; diff --git a/src/modules/dispatcher/dispatcher.c b/src/modules/dispatcher/dispatcher.c index 545d49b2bbd..428c93fd463 100644 --- a/src/modules/dispatcher/dispatcher.c +++ b/src/modules/dispatcher/dispatcher.c @@ -62,10 +62,12 @@ MODULE_VERSION /* clang-format off */ #define DS_SET_ID_COL "setid" +#define DS_DEST_ID_COL "id" #define DS_DEST_URI_COL "destination" #define DS_DEST_FLAGS_COL "flags" #define DS_DEST_PRIORITY_COL "priority" #define DS_DEST_ATTRS_COL "attrs" +#define DS_DEST_DESC_COL "description" #define DS_TABLE_NAME "dispatcher" /** parameters */ @@ -126,10 +128,12 @@ struct tm_binds tmb; /*db */ str ds_db_url = STR_NULL; str ds_set_id_col = str_init(DS_SET_ID_COL); +str ds_dest_id_col = str_init(DS_DEST_ID_COL); str ds_dest_uri_col = str_init(DS_DEST_URI_COL); str ds_dest_flags_col = str_init(DS_DEST_FLAGS_COL); str ds_dest_priority_col = str_init(DS_DEST_PRIORITY_COL); str ds_dest_attrs_col = str_init(DS_DEST_ATTRS_COL); +str ds_dest_desc_col = str_init(DS_DEST_DESC_COL); str ds_table_name = str_init(DS_TABLE_NAME); str ds_setid_pvname = STR_NULL; @@ -165,6 +169,7 @@ static int w_ds_is_from_list2(struct sip_msg*, char*, char*); static int w_ds_is_from_list3(struct sip_msg*, char*, char*, char*); static int w_ds_list_exist(struct sip_msg*, char*); static int w_ds_reload(struct sip_msg* msg); +static int w_ds_list(struct sip_msg *msg, char *); static int fixup_ds_is_from_list(void** param, int param_no); static int fixup_ds_list_exist(void** param,int param_no); @@ -212,6 +217,8 @@ static cmd_export_t cmds[]={ 0, 0, 0}, {"ds_reload", (cmd_function)w_ds_reload, 0, 0, 0, ANY_ROUTE}, + {"ds_list", (cmd_function)w_ds_list, 1, + fixup_spve_null, 0, ANY_ROUTE}, {0,0,0,0,0,0} }; @@ -221,10 +228,12 @@ static param_export_t params[]={ {"db_url", PARAM_STR, &ds_db_url}, {"table_name", PARAM_STR, &ds_table_name}, {"setid_col", PARAM_STR, &ds_set_id_col}, + {"dest_id_col", PARAM_STR, &ds_dest_id_col}, {"destination_col", PARAM_STR, &ds_dest_uri_col}, {"flags_col", PARAM_STR, &ds_dest_flags_col}, {"priority_col", PARAM_STR, &ds_dest_priority_col}, {"attrs_col", PARAM_STR, &ds_dest_attrs_col}, + {"description_col", PARAM_STR, &ds_dest_desc_col}, {"force_dst", INT_PARAM, &ds_force_dst}, {"flags", INT_PARAM, &ds_flags}, {"use_default", INT_PARAM, &ds_use_default}, @@ -1410,3 +1419,133 @@ static int ds_init_rpc(void) } return 0; } + +static sr_xavp_t *ds_xavp_add_value(char *name, sr_xval_t *val, sr_xavp_t **list) +{ + str sname; + sname.s = name; + sname.len = strlen(name); + return xavp_add_value(&sname, val, list); +} + +static int ds_set_to_xavp(ds_set_t *node, str* xavp) +{ + sr_xavp_t *row = NULL; + sr_xval_t val; + int j; + char c[3]; + str data = STR_NULL; + + if(!node) + return 1; + + int i = 0, rc = 0; + for(; i < 2; ++i) { + ds_set_to_xavp(node->next[i], xavp); + } + + for(j = 0; j < node->nr; j++) { + row = NULL; + + val.type = SR_XTYPE_INT; + val.v.i = node->id; + ds_xavp_add_value("setid", &val, &row); + + val.v.i = node->dlist[j].id; + ds_xavp_add_value("id", &val, &row); + + val.type = SR_XTYPE_STR; + val.v.s=node->dlist[j].uri; + ds_xavp_add_value("uri", &val, &row); + + val.type = SR_XTYPE_STR; + val.v.s=node->dlist[j].description; + ds_xavp_add_value("description", &val, &row); + + memset(&c, 0, sizeof(c)); + if(node->dlist[j].flags & DS_INACTIVE_DST) + c[0] = 'I'; + else if(node->dlist[j].flags & DS_DISABLED_DST) + c[0] = 'D'; + else if(node->dlist[j].flags & DS_TRYING_DST) + c[0] = 'T'; + else + c[0] = 'A'; + + if(node->dlist[j].flags & DS_PROBING_DST) + c[1] = 'P'; + else + c[1] = 'X'; + + val.type = SR_XTYPE_STR; + val.v.s.len=2; + val.v.s.s=c; + ds_xavp_add_value("state", &val, &row); + + val.type = SR_XTYPE_INT; + val.v.i = node->dlist[j].flags; + ds_xavp_add_value("flags", &val, &row); + + val.type = SR_XTYPE_INT; + val.v.i = node->dlist[j].priority; + ds_xavp_add_value("priority", &val, &row); + + val.type = SR_XTYPE_INT; + val.v.i = node->dlist[j].attrs.maxload; + ds_xavp_add_value("maxload", &val, &row); + + val.type = SR_XTYPE_INT; + val.v.i = node->dlist[j].attrs.weight; + ds_xavp_add_value("weight", &val, &row); + + val.type = SR_XTYPE_INT; + val.v.i = node->dlist[j].attrs.rweight; + ds_xavp_add_value("rweight", &val, &row); + + val.type = SR_XTYPE_STR; + val.v.s = node->dlist[j].attrs.duid; + ds_xavp_add_value("duid", &val, &row); + + val.type = SR_XTYPE_STR; + val.v.s = node->dlist[j].attrs.socket; + ds_xavp_add_value("socket", &val, &row); + + val.type = SR_XTYPE_STR; + val.v.s = node->dlist[j].attrs.body; + ds_xavp_add_value("attrs", &val, &row); + + val.type = SR_XTYPE_STR; + val.v.s.s = ip_addr2a(&node->dlist[j].ip_address); + val.v.s.len = strlen(val.v.s.s); + ds_xavp_add_value("ip", &val, &row); + + val.type = SR_XTYPE_INT; + val.v.i = node->dlist[j].port; + ds_xavp_add_value("port", &val, &row); + + val.type = SR_XTYPE_INT; + val.v.i = node->dlist[j].proto; + ds_xavp_add_value("proto", &val, &row); + + + val.type = SR_XTYPE_XAVP; + val.v.xavp = row; + xavp_add_value(xavp, &val, NULL); + + } + + return 1; +} + +static int w_ds_list(struct sip_msg *msg, char *xavpname) +{ + str xavp; + if (fixup_get_svalue(msg, (gparam_p)xavpname, &xavp) != 0) { + LM_ERR("cannot get xavp string value\n"); + return -1; + } + + xavp_rm_by_name(&xavp, 1, NULL); + ds_set_t *ds_list = ds_get_list(); + return ds_set_to_xavp(ds_list, &xavp); +} diff --git a/src/modules/dispatcher/doc/dispatcher_admin.xml b/src/modules/dispatcher/doc/dispatcher_admin.xml index b5315acc2dc..c0da3938c90 100644 --- a/src/modules/dispatcher/doc/dispatcher_admin.xml +++ b/src/modules/dispatcher/doc/dispatcher_admin.xml @@ -179,6 +179,46 @@ modparam("dispatcher", "destination_col", "uri") +
+ <varname>dest_id_col</varname> (string) + + The column's name in the database storing the id of the destination + + + + Default value is id. + + + + Set <quote>dest_id_col</quote> parameter + +... +modparam("dispatcher", "dest_id_col", "my_id") +... + + +
+ +
+ <varname>description_col</varname> (string) + + The column's name in the database storing the description of the destination + + + + Default value is description. + + + + Set <quote>description_col</quote> parameter + +... +modparam("dispatcher", "description_col", "my_description") +... + + +
+
<varname>flags_col</varname> (string) @@ -929,7 +969,7 @@ end set - the id of the set from where to pick up destination address. It is the first column in destination list file. The parameter can be an integer or a variable holding - an integer. + an integer.id @@ -1221,6 +1261,61 @@ failure_route[tryagain] {
+
+ + <function moreinfo="none">ds_list(xavpname)</function> + + + fills xavp with runtime information of dispatcher list. + + + + xavpname - name of the xavp to be filled. + + + + + This function can be used from ANY_ROUTE. + + + xavp fields. + + + + setid + id + uri + description + state + flags + priority + attrs + maxload + weight + rweight + duid + socket + ip + port + proto + + + + <function>ds_list</function> usage + +... +if(ds_list("ds")) { + while($xavp(ds) != $null) { + xlog("L_INFO", "Destination $xavp(ds=>uri) state is $xavp(ds=>state)\n"); + pv_unset("$xavp(ds)"); + } + ... +} +... + + +
+
<function moreinfo="none">ds_list_exist(groupid)</function> @@ -1249,6 +1344,7 @@ if(ds_list_exist("10")) { </programlisting> </example> </section> + <section id="dispatcher.f.ds_is_from_list"> <title> <function moreinfo="none">ds_is_from_list([groupid [, mode [, uri] ] ])</function>