From f81454ad591e72c286ec0300f90c0a0b6a36cecf Mon Sep 17 00:00:00 2001 From: Andreas Granig Date: Wed, 29 Feb 2012 16:07:10 +0000 Subject: [PATCH] First part of kex backport from trunk. --- events.c | 26 ++++ events.h | 4 +- modules_k/kex/core_stats.c | 133 +++++++++++++++++- modules_k/kex/core_stats.h | 5 +- modules_k/kex/kex_mod.c | 85 +++++++++++- modules_k/kex/pkg_stats.c | 277 +++++++++++++++++++++++++++++++++++++ modules_k/kex/pkg_stats.h | 38 +++++ 7 files changed, 554 insertions(+), 14 deletions(-) create mode 100644 modules_k/kex/pkg_stats.c create mode 100644 modules_k/kex/pkg_stats.h diff --git a/events.c b/events.c index 61abc5f30..86e3c4441 100644 --- a/events.c +++ b/events.c @@ -65,6 +65,16 @@ int sr_event_register_cb(int type, sr_event_cb_f f) _sr_events_list.run_action = f; else return -1; break; + case SREV_PKG_SET_USED: + if(_sr_events_list.pkg_set_used==0) + _sr_events_list.pkg_set_used = f; + else return -1; + break; + case SREV_PKG_SET_REAL_USED: + if(_sr_events_list.pkg_set_real_used==0) + _sr_events_list.pkg_set_real_used = f; + else return -1; + break; default: return -1; } @@ -121,6 +131,18 @@ int sr_event_exec(int type, void *data) ret = _sr_events_list.run_action(data); return ret; } else return 1; + case SREV_PKG_SET_USED: + if(unlikely(_sr_events_list.pkg_set_used!=0)) + { + ret = _sr_events_list.pkg_set_used(data); + return ret; + } else return 1; + case SREV_PKG_SET_REAL_USED: + if(unlikely(_sr_events_list.pkg_set_real_used!=0)) + { + ret = _sr_events_list.pkg_set_real_used(data); + return ret; + } else return 1; default: return -1; } @@ -137,6 +159,10 @@ int sr_event_enabled(int type) return (_sr_events_list.core_stats!=0)?1:0; case SREV_CFG_RUN_ACTION: return (_sr_events_list.run_action!=0)?1:0; + case SREV_PKG_SET_USED: + return (_sr_events_list.pkg_set_used!=0)?1:0; + case SREV_PKG_SET_REAL_USED: + return (_sr_events_list.pkg_set_real_used!=0)?1:0; } return 0; } diff --git a/events.h b/events.h index 6f7907067..a5338fee6 100644 --- a/events.h +++ b/events.h @@ -26,7 +26,9 @@ #define SREV_NET_DATA_IN 1 #define SREV_NET_DATA_OUT 2 #define SREV_CORE_STATS 3 -#define SREV_CFG_RUN_ACTION 4 +#define SREV_CFG_RUN_ACTION 4 +#define SREV_PKG_SET_USED 5 +#define SREV_PKG_SET_REAL_USED 6 typedef int (*sr_event_cb_f)(void *data); diff --git a/modules_k/kex/core_stats.c b/modules_k/kex/core_stats.c index 997405650..6b77ae122 100644 --- a/modules_k/kex/core_stats.c +++ b/modules_k/kex/core_stats.c @@ -1,6 +1,4 @@ /* - * $Id$ - * * Copyright (C) 2006 Voice Sistem SRL * * This file is part of Kamailio, a free SIP server. @@ -28,7 +26,8 @@ /*! * \file - * \brief Kamailio Core statistics + * \brief KEX :: Kamailio Core statistics + * \ingroup kex */ @@ -56,8 +55,8 @@ stat_var* drp_rpls; /*!< dropped replies */ stat_var* err_reqs; /*!< error requests */ stat_var* err_rpls; /*!< error replies */ stat_var* bad_URIs; /*!< number of bad URIs */ -stat_var* unsupported_methods; /*!< unsupported methods */ -stat_var* bad_msg_hdr; /*!< messages with bad header */ +stat_var* unsupported_methods; /*!< unsupported methods */ +stat_var* bad_msg_hdr; /*!< messages with bad header */ /*! exported core statistics */ @@ -95,10 +94,12 @@ stat_export_t shm_stats[] = { static struct mi_root *mi_get_stats(struct mi_root *cmd, void *param); static struct mi_root *mi_reset_stats(struct mi_root *cmd, void *param); +static struct mi_root *mi_clear_stats(struct mi_root *cmd, void *param); static mi_export_t mi_stat_cmds[] = { { "get_statistics", mi_get_stats, 0 , 0, 0 }, { "reset_statistics", mi_reset_stats, 0 , 0, 0 }, + { "clear_statistics", mi_clear_stats, 0 , 0, 0 }, { 0, 0, 0, 0, 0} }; @@ -220,10 +221,9 @@ inline static int mi_add_stat(struct mi_node *rpl, stat_var *stat) static void mi_add_grp_vars_cbk(void* r, str* g, str* n, counter_handle_t h) { struct mi_node *rpl; - struct mi_node *node; rpl = r; - node = addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu", + addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu", g->len, g->s, n->len, n->s, counter_get_val(h)); } @@ -329,6 +329,125 @@ static struct mi_root *mi_reset_stats(struct mi_root *cmd, void *param) return rpl_tree; } + +inline static int mi_reset_and_add_stat(struct mi_node *rpl, stat_var *stat) +{ + struct mi_node *node; + long old_val, new_val; + + if (stats_support()==0) return -1; + + old_val=get_stat_val(stat); + reset_stat(stat); + new_val=get_stat_val(stat); + + if (old_val==new_val) + { + node = addf_mi_node_child(rpl, 0, 0, 0, "%s:%s = %lu", + ZSW(get_stat_module(stat)), + ZSW(get_stat_name(stat)), + new_val); + } else { + node = addf_mi_node_child(rpl, 0, 0, 0, "%s:%s = %lu (%lu)", + ZSW(get_stat_module(stat)), + ZSW(get_stat_name(stat)), + new_val, old_val ); + } + + if (node==0) + return -1; + return 0; +} + + +/* callback for counter_iterate_grp_vars to reset counters */ +static void mi_add_grp_vars_cbk2(void* r, str* g, str* n, counter_handle_t h) +{ + struct mi_node *rpl; + counter_val_t old_val, new_val; + + rpl = r; + old_val = counter_get_val(h); + counter_reset(h); + new_val = counter_get_val(h); + + if (old_val==new_val) + { + addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu", + g->len, g->s, n->len, n->s, new_val); + } else { + addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu (%lu)", + g->len, g->s, n->len, n->s, new_val, old_val); + } +} + + +/* callback for counter_iterate_grp_names to reset counters */ +static void mi_add_all_grps_cbk2(void* p, str* g) +{ + counter_iterate_grp_vars(g->s, mi_add_grp_vars_cbk2, p); +} + + +static struct mi_root *mi_clear_stats(struct mi_root *cmd, void *param) +{ + struct mi_root *rpl_tree; + struct mi_node *rpl; + struct mi_node *arg; + stat_var *stat; + str val; + + if(stats_support()==0) + return init_mi_tree( 404, "Statistics Not Found", 20); + + if (cmd->node.kids==NULL) + return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + + rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); + if (rpl_tree==0) + return 0; + rpl = &rpl_tree->node; + + for( arg=cmd->node.kids ; arg ; arg=arg->next) + { + if (arg->value.len==0) + continue; + + val = arg->value; + + if ( val.len==3 && memcmp(val.s,"all",3)==0) { + /* add all statistic variables */ + /* use direct counters access for that */ + counter_iterate_grp_names(mi_add_all_grps_cbk2, rpl); + } else if ( val.len>1 && val.s[val.len-1]==':') { + /* add module statistics */ + val.len--; + val.s[val.len]=0; /* zero term. */ + /* use direct counters access for that */ + counter_iterate_grp_vars(val.s, mi_add_grp_vars_cbk2, rpl); + val.s[val.len]=':' /* restore */; + } else { + /* reset & return only one statistic */ + stat = get_stat( &val ); + + if (stat==0) + continue; + if (mi_reset_and_add_stat(rpl,stat)!=0) + goto error; + } + } + + if (rpl->kids==0) { + free_mi_tree(rpl_tree); + return init_mi_tree( 404, "Statistics Not Found", 20); + } + + return rpl_tree; +error: + free_mi_tree(rpl_tree); + return 0; +} + /*** shm stats ***/ static struct mem_info _stats_shm_mi; diff --git a/modules_k/kex/core_stats.h b/modules_k/kex/core_stats.h index fabbee112..48d8dd1d4 100644 --- a/modules_k/kex/core_stats.h +++ b/modules_k/kex/core_stats.h @@ -1,6 +1,4 @@ /* - * $Id$ - * * Copyright (C) 2006 Voice Sistem SRL * * This file is part of Kamailio, a free SIP server. @@ -28,7 +26,8 @@ /*! * \file - * \brief Kamailio statistics + * \brief KEX :: Kamailio statistics + * \ingroup kex */ diff --git a/modules_k/kex/kex_mod.c b/modules_k/kex/kex_mod.c index d86cfbde2..452cb99fb 100644 --- a/modules_k/kex/kex_mod.c +++ b/modules_k/kex/kex_mod.c @@ -1,6 +1,4 @@ /** - * $Id$ - * * Copyright (C) 2009 * * This file is part of SIP-Router.org, a free SIP server. @@ -20,20 +18,27 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/*! + * @defgroup kex KEX :: Kamailio Extensions + */ + #include #include #include #include "../../sr_module.h" #include "../../dprint.h" +#include "../../forward.h" #include "../../flags.h" #include "../../dset.h" #include "../../mod_fix.h" +#include "../../parser/parse_uri.h" #include "flags.h" #include "km_core.h" #include "mi_core.h" #include "core_stats.h" +#include "pkg_stats.h" MODULE_VERSION @@ -42,7 +47,12 @@ MODULE_VERSION /** parameters */ /** module functions */ +int w_is_myself(struct sip_msg *msg, char *uri, str *s2); +int w_setdebug(struct sip_msg *msg, char *level, str *s2); +int w_resetdebug(struct sip_msg *msg, char *uri, str *s2); + static int mod_init(void); +static int child_init(int rank); static void destroy(void); static cmd_export_t cmds[]={ @@ -78,6 +88,12 @@ static cmd_export_t cmds[]={ 0, ANY_ROUTE }, {"avp_printf", (cmd_function)w_pv_printf, 2, pv_printf_fixup, 0, ANY_ROUTE }, + {"is_myself", (cmd_function)w_is_myself, 1, fixup_spve_null, + 0, ANY_ROUTE }, + {"setdebug", (cmd_function)w_setdebug, 1, fixup_igp_null, + 0, ANY_ROUTE }, + {"resetdebug", (cmd_function)w_resetdebug, 0, 0, + 0, ANY_ROUTE }, {0,0,0,0,0,0} }; @@ -100,7 +116,7 @@ struct module_exports exports= { mod_init, /* module initialization function */ 0, (destroy_function) destroy, - 0 /* per-child init function */ + child_init /* per-child init function */ }; /** @@ -116,9 +132,23 @@ static int mod_init(void) if(register_mi_stats()<0) return -1; #endif + register_pkg_proc_stats(); + pkg_proc_stats_init_rpc(); return 0; } +/** + * + */ +static int child_init(int rank) +{ + LM_DBG("rank is (%d)\n", rank); + if (rank==PROC_INIT) + return pkg_proc_stats_init(); + return pkg_proc_stats_myinit(rank); +} + + /** * destroy function */ @@ -128,3 +158,52 @@ static void destroy(void) } +/** + * + */ +int w_is_myself(struct sip_msg *msg, char *uri, str *s2) +{ + int ret; + str suri; + struct sip_uri puri; + + if(fixup_get_svalue(msg, (gparam_p)uri, &suri)!=0) + { + LM_ERR("cannot get the URI parameter\n"); + return -1; + } + if(suri.len>4 && (strncmp(suri.s, "sip:", 4)==0 + || strncmp(suri.s, "sips:", 5)==0)) + { + if(parse_uri(suri.s, suri.len, &puri)!=0) + { + LM_ERR("failed to parse uri [%.*s]\n", suri.len, suri.s); + return -1; + } + ret = check_self(&puri.host, (puri.port.s)?puri.port_no:0, + (puri.transport_val.s)?puri.proto:0); + } else { + ret = check_self(&suri, 0, 0); + } + if(ret!=1) + return -1; + return 1; +} + +int w_setdebug(struct sip_msg *msg, char *level, str *s2) +{ + int lval=0; + if(fixup_get_ivalue(msg, (gparam_p)level, &lval)!=0) + { + LM_ERR("no debug level value\n"); + return -1; + } + //set_local_debug_level(lval); + return 1; +} + +int w_resetdebug(struct sip_msg *msg, char *uri, str *s2) +{ + //reset_local_debug_level(); + return 1; +} diff --git a/modules_k/kex/pkg_stats.c b/modules_k/kex/pkg_stats.c new file mode 100644 index 000000000..ce98e6f4c --- /dev/null +++ b/modules_k/kex/pkg_stats.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com) + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/*! + * \file + * \brief KEX :: Kamailio private memory pool statistics + * \ingroup kex + */ + +#include +#include +#include +#include + +#include "../../dprint.h" +#include "../../ut.h" +#include "../../pt.h" +#include "../../events.h" +#include "../../mem/mem.h" +#include "../../mem/shm_mem.h" +#include "../../rpc.h" +#include "../../rpc_lookup.h" + + +/** + * + */ +typedef struct pkg_proc_stats { + int rank; + unsigned int pid; + unsigned int used; + unsigned int available; + unsigned int real_used; +} pkg_proc_stats_t; + +/** + * + */ +static pkg_proc_stats_t *_pkg_proc_stats_list = NULL; + +/** + * + */ +static int _pkg_proc_stats_no = 0; + +/** + * + */ +int pkg_proc_stats_init(void) +{ + _pkg_proc_stats_no = get_max_procs(); + + if(_pkg_proc_stats_no<=0) + return -1; + if(_pkg_proc_stats_list!=NULL) + return -1; + _pkg_proc_stats_list = (pkg_proc_stats_t*)shm_malloc( + _pkg_proc_stats_no*sizeof(pkg_proc_stats_t)); + if(_pkg_proc_stats_list==NULL) + return -1; + memset(_pkg_proc_stats_list, 0, + _pkg_proc_stats_no*sizeof(pkg_proc_stats_t)); + return 0; +} + +/** + * + */ +int pkg_proc_stats_myinit(int rank) +{ + struct mem_info info; + if(_pkg_proc_stats_list==NULL) + return -1; + if(process_no>=_pkg_proc_stats_no) + return -1; + _pkg_proc_stats_list[process_no].pid = (unsigned int)my_pid(); + _pkg_proc_stats_list[process_no].rank = rank; + + /* init pkg usage values */ + pkg_info(&info); + _pkg_proc_stats_list[process_no].used = info.used; + _pkg_proc_stats_list[process_no].real_used = info.real_used; + return 0; +} + +/** + * + */ +int pkg_proc_stats_destroy(void) +{ + if(_pkg_proc_stats_list==NULL) + return -1; + shm_free(_pkg_proc_stats_list); + _pkg_proc_stats_list = 0; + _pkg_proc_stats_no = 0; + return 0; +} + + +/** + * + */ +static int pkg_proc_update_used(void *data) +{ + if(_pkg_proc_stats_list==NULL) + return -1; + if(process_no>=_pkg_proc_stats_no) + return -1; + _pkg_proc_stats_list[process_no].used = (unsigned int)(long)data; + return 0; +} + +/** + * + */ +static int pkg_proc_update_real_used(void *data) +{ + if(_pkg_proc_stats_list==NULL) + return -1; + if(process_no>=_pkg_proc_stats_no) + return -1; + _pkg_proc_stats_list[process_no].real_used = (unsigned int)(long)data; + _pkg_proc_stats_list[process_no].available = pkg_available(); + return 0; +} + +/** + * + */ +int register_pkg_proc_stats(void) +{ + sr_event_register_cb(SREV_PKG_SET_USED, pkg_proc_update_used); + sr_event_register_cb(SREV_PKG_SET_REAL_USED, pkg_proc_update_real_used); + return 0; +} + +/** + * + */ +static const char* rpc_pkg_stats_doc[2] = { + "Private memory (pkg) statistics per process", + 0 +}; + +/** + * + */ +int pkg_proc_get_pid_index(unsigned int pid) +{ + int i; + for(i=0; i<_pkg_proc_stats_no; i++) + { + if(_pkg_proc_stats_list[i].pid == pid) + return i; + } + return -1; +} + +/** + * + */ +static void rpc_pkg_stats(rpc_t* rpc, void* ctx) +{ + int i; + int limit; + int cval; + str cname; + void* th; + int mode; + + if(_pkg_proc_stats_list==NULL) + { + rpc->fault(ctx, 500, "Not initialized"); + return; + } + i = 0; + mode = 0; + cval = 0; + limit = _pkg_proc_stats_no; + if (rpc->scan(ctx, "*S", &cname) == 1) + { + if(cname.len==3 && strncmp(cname.s, "pid", 3)==0) + mode = 1; + else if(cname.len==4 && strncmp(cname.s, "rank", 4)==0) + mode = 2; + else if(cname.len==5 && strncmp(cname.s, "index", 5)==0) + mode = 3; + else { + rpc->fault(ctx, 500, "Invalid filter type"); + return; + } + + if (rpc->scan(ctx, "d", &cval) < 1) + { + rpc->fault(ctx, 500, "One more parameter expected"); + return; + } + if(mode==1) + { + i = pkg_proc_get_pid_index((unsigned int)cval); + if(i<0) + { + rpc->fault(ctx, 500, "No such pid"); + return; + } + limit = i + 1; + } else if(mode==3) { + i=cval; + limit = i + 1; + } + } + + for(; iadd(ctx, "{", &th) < 0) + { + rpc->fault(ctx, 500, "Internal error creating rpc"); + return; + } + if(rpc->struct_add(th, "dddddd", + "entry", i, + "pid", _pkg_proc_stats_list[i].pid, + "rank", _pkg_proc_stats_list[i].rank, + "used", _pkg_proc_stats_list[i].used, + "free", _pkg_proc_stats_list[i].available, + "real_used", _pkg_proc_stats_list[i].real_used + )<0) + { + rpc->fault(ctx, 500, "Internal error creating rpc"); + return; + } + } + } +} + +/** + * + */ +rpc_export_t kex_pkg_rpc[] = { + {"pkg.stats", rpc_pkg_stats, rpc_pkg_stats_doc, 0}, + {0, 0, 0, 0} +}; + +/** + * + */ +int pkg_proc_stats_init_rpc(void) +{ + if (rpc_register_array(kex_pkg_rpc)!=0) + { + LM_ERR("failed to register RPC commands\n"); + return -1; + } + return 0; +} + diff --git a/modules_k/kex/pkg_stats.h b/modules_k/kex/pkg_stats.h new file mode 100644 index 000000000..cff9345df --- /dev/null +++ b/modules_k/kex/pkg_stats.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com) + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/*! + * \file + * \brief KEX :: Kamailio private memory pool statistics + * \ingroup kex + */ + + +#ifndef _PKG_STATS_H_ +#define _PKG_STATS_H_ + +int pkg_proc_stats_init(void); +int pkg_proc_stats_myinit(int rank); +int pkg_proc_stats_destroy(void); +int register_pkg_proc_stats(void); +int pkg_proc_stats_init_rpc(void); + +#endif /*_PKG_STATS_H_*/