diff options
author | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-02-26 20:46:11 +0000 |
---|---|---|
committer | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-02-26 20:46:11 +0000 |
commit | 9dc45031753b6c466b322dd105af10a156c11eaa (patch) | |
tree | dc11dea95379b474e67d6e7b12cff34e6154e4e4 /res | |
parent | 181407f0739de8cfd78f71645cbc49f5063996c2 (diff) |
Add SNMP support (bug #6439)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@11193 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'res')
-rw-r--r-- | res/Makefile | 8 | ||||
-rw-r--r-- | res/res_snmp.c | 148 | ||||
-rw-r--r-- | res/snmp/agent.c | 845 | ||||
-rw-r--r-- | res/snmp/agent.h | 40 |
4 files changed, 1041 insertions, 0 deletions
diff --git a/res/Makefile b/res/Makefile index 2759f4e49..08ee8e14a 100644 --- a/res/Makefile +++ b/res/Makefile @@ -32,6 +32,11 @@ ifeq (${OSPLIB},) MODS:=$(filter-out res_osp.so,$(MODS)) endif +ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/net-snmp/net-snmp-config.h),) + SNMP_LDLIBS+=$(shell net-snmp-config --agent-libs) + MODS+=res_snmp.so +endif + ifeq (${WITH_SMDI},) MODS:=$(filter-out res_smdi.so,$(MODS)) endif @@ -108,6 +113,9 @@ res_features.so: res_features.o res_config_odbc.so: res_config_odbc.o $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} ${CYG_RES_CONFIG_ODBC_LIB} +res_snmp.so: res_snmp.o snmp/agent.o + $(CC) $(SOLINK) ${SNMP_LDFLAGS} -o $@ ${CYGSOLINK} res_snmp.o snmp/agent.o ${CYGSOLIB} ${SNMP_LDLIBS} + ifneq ($(wildcard .depend),) include .depend endif diff --git a/res/res_snmp.c b/res/res_snmp.c new file mode 100644 index 000000000..e62e6fb05 --- /dev/null +++ b/res/res_snmp.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2006 Voop as + * Thorsten Lockert <tholo@voop.as> + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief SNMP Agent / SubAgent support for Asterisk + * + * \author Thorsten Lockert <tholo@voop.as> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/channel.h" +#include "asterisk/module.h" +#include "asterisk/logger.h" +#include "asterisk/options.h" + +#include "snmp/agent.h" + +#define MODULE_DESCRIPTION "SNMP [Sub]Agent for Asterisk" + +int res_snmp_agentx_subagent; +int res_snmp_dont_stop; +int res_snmp_enabled; + +static pthread_t thread; + +static int load_config(void) +{ + struct ast_variable *var; + struct ast_config *cfg; + char *cat; + + res_snmp_enabled = 0; + res_snmp_agentx_subagent = 1; + cfg = ast_config_load("res_snmp.conf"); + if (cfg) { + cat = ast_category_browse(cfg, NULL); + while (cat) { + var = ast_variable_browse(cfg, cat); + + if (strcasecmp(cat, "general") == 0) { + while (var) { + if (strcasecmp(var->name, "subagent") == 0) { + if (ast_true(var->value)) + res_snmp_agentx_subagent = 1; + else if (ast_false(var->value)) + res_snmp_agentx_subagent = 0; + else { + ast_log(LOG_ERROR, "Value '%s' does not evaluate to true or false.\n", + var->value); + ast_config_destroy(cfg); + return 1; + } + } else if (strcasecmp(var->name, "enabled") == 0) { + res_snmp_enabled = ast_true(var->value); + } else { + ast_log(LOG_ERROR, "Unrecognized variable '%s' in category '%s'\n", + var->name, cat); + ast_config_destroy(cfg); + return 1; + } + var = var->next; + } + } + else { + ast_log(LOG_ERROR, "Unrecognized category '%s'\n", cat); + ast_config_destroy(cfg); + return 1; + } + + cat = ast_category_browse(cfg, cat); + } + ast_config_destroy(cfg); + } + + return 0; +} + +int load_module(void) +{ + load_config(); + + ast_verbose(VERBOSE_PREFIX_1 "Loading [Sub]Agent Module\n"); + + res_snmp_dont_stop = 1; + if (res_snmp_enabled) + return ast_pthread_create(&thread, NULL, agent_thread, NULL); + else + return 0; +} + +int unload_module(void) +{ + ast_verbose(VERBOSE_PREFIX_1 "Unloading [Sub]Agent Module\n"); + + res_snmp_dont_stop = 0; + return pthread_join(thread, NULL); +} + +int reload(void) +{ + ast_verbose(VERBOSE_PREFIX_1 "Reloading [Sub]Agent Module\n"); + + res_snmp_dont_stop = 0; + pthread_join(thread, NULL); + + load_config(); + + res_snmp_dont_stop = 1; + if (res_snmp_enabled) + return ast_pthread_create(&thread, NULL, agent_thread, NULL); + else + return 0; +} + +int usecount(void) +{ + return 0; +} + +char *key(void) +{ + return ASTERISK_GPL_KEY; +} + +char *description(void) +{ + return MODULE_DESCRIPTION; +} + +/* + * Local Variables: + * c-file-style: gnu + * c-basic-offset: 4 + * c-file-offsets: ((case-label . 0)) + * tab-width: 4 + * indent-tabs-mode: t + * End: + */ diff --git a/res/snmp/agent.c b/res/snmp/agent.c new file mode 100644 index 000000000..740f5c10e --- /dev/null +++ b/res/snmp/agent.c @@ -0,0 +1,845 @@ +/* + * Copyright (C) 2006 Voop as + * Thorsten Lockert <tholo@voop.as> + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief SNMP Agent / SubAgent support for Asterisk + * + * \author Thorsten Lockert <tholo@voop.as> + */ + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> + +/* + * These conflict with ones in Asterisk header files, so + * get rid of them. They'll be back after the next few + * includes... + */ +#undef HAVE_GETLOADAVG +#undef HAVE_STRCASESTR + +#include <pthread.h> + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include "asterisk/channel.h" +#include "asterisk/logger.h" +#include "asterisk/options.h" +#include "asterisk/indications.h" +#include "asterisk/version.h" +#include "asterisk/pbx.h" + +/* Colission between Net-SNMP and Asterisk */ +#define unload_module ast_unload_module +#include "asterisk/module.h" +#undef unload_module + +#include "agent.h" + +/* Helper functions in Net-SNMP, header file not installed by default */ +int header_generic(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); +int header_simple_table(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **, int); +int register_sysORTable(oid *, size_t, const char *); +int unregister_sysORTable(oid *, size_t); + +/* Not defined in header files */ +extern char ast_config_AST_SOCKET[]; + +/* Forward declaration */ +static void init_asterisk_mib(void); + +/* + * Anchor for all the Asterisk MIB values + */ +static oid asterisk_oid[] = { 1, 3, 6, 1, 4, 1, 22736, 1 }; + +/* + * MIB values -- these correspond to values in the Asterisk MIB, + * and MUST be kept in sync with the MIB for things to work as + * expected. + */ +#define ASTVERSION 1 +#define ASTVERSTRING 1 +#define ASTVERTAG 2 + +#define ASTCONFIGURATION 2 +#define ASTCONFUPTIME 1 +#define ASTCONFRELOADTIME 2 +#define ASTCONFPID 3 +#define ASTCONFSOCKET 4 + +#define ASTMODULES 3 +#define ASTMODCOUNT 1 + +#define ASTINDICATIONS 4 +#define ASTINDCOUNT 1 +#define ASTINDCURRENT 2 + +#define ASTINDTABLE 3 +#define ASTINDINDEX 1 +#define ASTINDCOUNTRY 2 +#define ASTINDALIAS 3 +#define ASTINDDESCRIPTION 4 + +#define ASTCHANNELS 5 +#define ASTCHANCOUNT 1 + +#define ASTCHANTABLE 2 +#define ASTCHANINDEX 1 +#define ASTCHANNAME 2 +#define ASTCHANLANGUAGE 3 +#define ASTCHANTYPE 4 +#define ASTCHANMUSICCLASS 5 +#define ASTCHANBRIDGE 6 +#define ASTCHANMASQ 7 +#define ASTCHANMASQR 8 +#define ASTCHANWHENHANGUP 9 +#define ASTCHANAPP 10 +#define ASTCHANDATA 11 +#define ASTCHANCONTEXT 12 +#define ASTCHANMACROCONTEXT 13 +#define ASTCHANMACROEXTEN 14 +#define ASTCHANMACROPRI 15 +#define ASTCHANEXTEN 16 +#define ASTCHANPRI 17 +#define ASTCHANACCOUNTCODE 18 +#define ASTCHANFORWARDTO 19 +#define ASTCHANUNIQUEID 20 +#define ASTCHANCALLGROUP 21 +#define ASTCHANPICKUPGROUP 22 +#define ASTCHANSTATE 23 +#define ASTCHANMUTED 24 +#define ASTCHANRINGS 25 +#define ASTCHANCIDDNID 26 +#define ASTCHANCIDNUM 27 +#define ASTCHANCIDNAME 28 +#define ASTCHANCIDANI 29 +#define ASTCHANCIDRDNIS 30 +#define ASTCHANCIDPRES 31 +#define ASTCHANCIDANI2 32 +#define ASTCHANCIDTON 33 +#define ASTCHANCIDTNS 34 +#define ASTCHANAMAFLAGS 35 +#define ASTCHANADSI 36 +#define ASTCHANTONEZONE 37 +#define ASTCHANHANGUPCAUSE 38 +#define ASTCHANVARIABLES 39 +#define ASTCHANFLAGS 40 +#define ASTCHANTRANSFERCAP 41 + +#define ASTCHANTYPECOUNT 3 + +#define ASTCHANTYPETABLE 4 +#define ASTCHANTYPEINDEX 1 +#define ASTCHANTYPENAME 2 +#define ASTCHANTYPEDESC 3 +#define ASTCHANTYPEDEVSTATE 4 +#define ASTCHANTYPEINDICATIONS 5 +#define ASTCHANTYPETRANSFER 6 +#define ASTCHANTYPECHANNELS 7 + +void *agent_thread(void *arg) +{ + ast_verbose(VERBOSE_PREFIX_2 "Starting %sAgent\n", res_snmp_agentx_subagent ? "Sub" : ""); + + snmp_enable_stderrlog(); + + if (res_snmp_agentx_subagent) + netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, + NETSNMP_DS_AGENT_ROLE, + 1); + + init_agent("asterisk"); + + init_asterisk_mib(); + + init_snmp("asterisk"); + + if (!res_snmp_agentx_subagent) + init_master_agent(); + + while (res_snmp_dont_stop) + agent_check_and_process(1); + + snmp_shutdown("asterisk"); + + ast_verbose(VERBOSE_PREFIX_2 "Terminating %sAgent\n", + res_snmp_agentx_subagent ? "Sub" : ""); + + return NULL; +} + +static u_char * +ast_var_channels(struct variable *vp, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + static unsigned long long_ret; + + if (header_generic(vp, name, length, exact, var_len, write_method)) + return NULL; + + switch (vp->magic) { + case ASTCHANCOUNT: + long_ret = ast_active_channels(); + return (u_char *)&long_ret; + default: + break; + } + return NULL; +} + +static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + static unsigned long long_ret; + static u_char bits_ret[2]; + static char string_ret[256]; + struct ast_channel *chan, *bridge; + struct timeval tval; + u_char *ret; + int i, bit; + + if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels())) + return NULL; + + i = name[*length - 1] - 1; + for (chan = ast_channel_walk_locked(NULL); + chan && i; + chan = ast_channel_walk_locked(chan), i--) + ast_mutex_unlock(&chan->lock); + if (chan == NULL) + return NULL; + *var_len = sizeof(long_ret); + + switch (vp->magic) { + case ASTCHANINDEX: + long_ret = name[*length - 1]; + ret = (u_char *)&long_ret; + break; + case ASTCHANNAME: + if (!ast_strlen_zero(chan->name)) { + strncpy(string_ret, chan->name, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANLANGUAGE: + if (!ast_strlen_zero(chan->language)) { + strncpy(string_ret, chan->language, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANTYPE: + strncpy(string_ret, chan->tech->type, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + break; + case ASTCHANMUSICCLASS: + if (!ast_strlen_zero(chan->musicclass)) { + strncpy(string_ret, chan->musicclass, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANBRIDGE: + if ((bridge = ast_bridged_channel(chan)) != NULL) { + strncpy(string_ret, bridge->name, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANMASQ: + if (chan->masq && !ast_strlen_zero(chan->masq->name)) { + strncpy(string_ret, chan->masq->name, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANMASQR: + if (chan->masqr && !ast_strlen_zero(chan->masqr->name)) { + strncpy(string_ret, chan->masqr->name, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANWHENHANGUP: + if (chan->whentohangup) { + gettimeofday(&tval, NULL); + long_ret = difftime(chan->whentohangup, tval.tv_sec) * 100 - tval.tv_usec / 10000; + ret= (u_char *)&long_ret; + } + else + ret = NULL; + break; + case ASTCHANAPP: + if (chan->appl) { + strncpy(string_ret, chan->appl, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANDATA: + if (chan->data) { + strncpy(string_ret, chan->data, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANCONTEXT: + strncpy(string_ret, chan->context, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + break; + case ASTCHANMACROCONTEXT: + strncpy(string_ret, chan->macrocontext, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + break; + case ASTCHANMACROEXTEN: + strncpy(string_ret, chan->macroexten, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + break; + case ASTCHANMACROPRI: + long_ret = chan->macropriority; + ret = (u_char *)&long_ret; + break; + case ASTCHANEXTEN: + strncpy(string_ret, chan->exten, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + break; + case ASTCHANPRI: + long_ret = chan->priority; + ret = (u_char *)&long_ret; + break; + case ASTCHANACCOUNTCODE: + if (!ast_strlen_zero(chan->accountcode)) { + strncpy(string_ret, chan->accountcode, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANFORWARDTO: + if (!ast_strlen_zero(chan->call_forward)) { + strncpy(string_ret, chan->call_forward, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANUNIQUEID: + strncpy(string_ret, chan->uniqueid, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + break; + case ASTCHANCALLGROUP: + long_ret = chan->callgroup; + ret = (u_char *)&long_ret; + break; + case ASTCHANPICKUPGROUP: + long_ret = chan->pickupgroup; + ret = (u_char *)&long_ret; + break; + case ASTCHANSTATE: + long_ret = chan->_state & 0xffff; + ret = (u_char *)&long_ret; + break; + case ASTCHANMUTED: + long_ret = chan->_state & AST_STATE_MUTE ? 1 : 2; + ret = (u_char *)&long_ret; + break; + case ASTCHANRINGS: + long_ret = chan->rings; + ret = (u_char *)&long_ret; + break; + case ASTCHANCIDDNID: + if (chan->cid.cid_dnid) { + strncpy(string_ret, chan->cid.cid_dnid, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANCIDNUM: + if (chan->cid.cid_num) { + strncpy(string_ret, chan->cid.cid_num, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANCIDNAME: + if (chan->cid.cid_name) { + strncpy(string_ret, chan->cid.cid_name, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANCIDANI: + if (chan->cid.cid_ani) { + strncpy(string_ret, chan->cid.cid_ani, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANCIDRDNIS: + if (chan->cid.cid_rdnis) { + strncpy(string_ret, chan->cid.cid_rdnis, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANCIDPRES: + long_ret = chan->cid.cid_pres; + ret = (u_char *)&long_ret; + break; + case ASTCHANCIDANI2: + long_ret = chan->cid.cid_ani2; + ret = (u_char *)&long_ret; + break; + case ASTCHANCIDTON: + long_ret = chan->cid.cid_ton; + ret = (u_char *)&long_ret; + break; + case ASTCHANCIDTNS: + long_ret = chan->cid.cid_tns; + ret = (u_char *)&long_ret; + break; + case ASTCHANAMAFLAGS: + long_ret = chan->amaflags; + ret = (u_char *)&long_ret; + break; + case ASTCHANADSI: + long_ret = chan->adsicpe; + ret = (u_char *)&long_ret; + break; + case ASTCHANTONEZONE: + if (chan->zone) { + strncpy(string_ret, chan->zone->country, sizeof(string_ret)); + string_ret[sizeof(string_ret) - 1] = '\0'; + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANHANGUPCAUSE: + long_ret = chan->hangupcause; + ret = (u_char *)&long_ret; + break; + case ASTCHANVARIABLES: + if (pbx_builtin_serialize_variables(chan, string_ret, sizeof(string_ret))) { + *var_len = strlen(string_ret); + ret = (u_char *)string_ret; + } + else + ret = NULL; + break; + case ASTCHANFLAGS: + bits_ret[0] = 0; + for (bit = 0; bit < 8; bit++) + bits_ret[0] |= ((chan->flags & (1 << bit)) >> bit) << (7 - bit); + bits_ret[1] = 0; + for (bit = 0; bit < 8; bit++) + bits_ret[1] |= (((chan->flags >> 8) & (1 << bit)) >> bit) << (7 - bit); + *var_len = 2; + ret = bits_ret; + break; + case ASTCHANTRANSFERCAP: + long_ret = chan->transfercapability; + ret = (u_char *)&long_ret; + break; + default: + ret = NULL; + break; + } + ast_mutex_unlock(&chan->lock); + return ret; +} + +static u_char *ast_var_channel_types(struct variable *vp, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + static unsigned long long_ret; + struct ast_variable *channel_types, *next; + + if (header_generic(vp, name, length, exact, var_len, write_method)) + return NULL; + + switch (vp->magic) { + case ASTCHANTYPECOUNT: + long_ret = 0; + for (channel_types = next = ast_channeltype_list(); next; next = next->next) { + long_ret++; + } + ast_variables_destroy(channel_types); + return (u_char *)&long_ret; + default: + break; + } + return NULL; +} + +static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + const struct ast_channel_tech *tech = NULL; + struct ast_variable *channel_types, *next; + static unsigned long long_ret; + struct ast_channel *chan; + u_long i; + + if (header_simple_table(vp, name, length, exact, var_len, write_method, -1)) + return NULL; + + channel_types = ast_channeltype_list(); + for (i = 1, next = channel_types; next && i != name[*length - 1]; next = next->next, i++) + ; + if (next != NULL) + tech = ast_get_channel_tech(next->name); + ast_variables_destroy(channel_types); + if (next == NULL || tech == NULL) + return NULL; + + switch (vp->magic) { + case ASTCHANTYPEINDEX: + long_ret = name[*length - 1]; + return (u_char *)&long_ret; + case ASTCHANTYPENAME: + *var_len = strlen(tech->type); + return (u_char *)tech->type; + case ASTCHANTYPEDESC: + *var_len = strlen(tech->description); + return (u_char *)tech->description; + case ASTCHANTYPEDEVSTATE: + long_ret = tech->devicestate ? 1 : 2; + return (u_char *)&long_ret; + case ASTCHANTYPEINDICATIONS: + long_ret = tech->indicate ? 1 : 2; + return (u_char *)&long_ret; + case ASTCHANTYPETRANSFER: + long_ret = tech->transfer ? 1 : 2; + return (u_char *)&long_ret; + case ASTCHANTYPECHANNELS: + long_ret = 0; + for (chan = ast_channel_walk_locked(NULL); chan; chan = ast_channel_walk_locked(chan)) { + ast_mutex_unlock(&chan->lock); + if (chan->tech == tech) + long_ret++; + } + return (u_char *)&long_ret; + default: + break; + } + return NULL; +} + +static u_char *ast_var_Config(struct variable *vp, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + static unsigned long long_ret; + struct timeval tval; + + if (header_generic(vp, name, length, exact, var_len, write_method)) + return NULL; + + switch (vp->magic) { + case ASTCONFUPTIME: + gettimeofday(&tval, NULL); + long_ret = difftime(tval.tv_sec, ast_startuptime) * 100 + tval.tv_usec / 10000; + return (u_char *)&long_ret; + case ASTCONFRELOADTIME: + gettimeofday(&tval, NULL); + if (ast_lastreloadtime) + long_ret = difftime(tval.tv_sec, ast_lastreloadtime) * 100 + tval.tv_usec / 10000; + else + long_ret = difftime(tval.tv_sec, ast_startuptime) * 100 + tval.tv_usec / 10000; + return (u_char *)&long_ret; + case ASTCONFPID: + long_ret = getpid(); + return (u_char *)&long_ret; + case ASTCONFSOCKET: + *var_len = strlen(ast_config_AST_SOCKET); + return (u_char *)ast_config_AST_SOCKET; + default: + break; + } + return NULL; +} + +static u_char *ast_var_indications(struct variable *vp, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + static unsigned long long_ret; + struct tone_zone *tz; + + if (header_generic(vp, name, length, exact, var_len, write_method)) + return NULL; + + switch (vp->magic) { + case ASTINDCOUNT: + if (ast_mutex_lock(&tzlock)) { + ast_log(LOG_WARNING, "Unable to lock tone_zones list\n"); + snmp_log(LOG_ERR, "Unable to lock tone_zones list in ast_var_indications\n"); + return NULL; + } + long_ret = 0; + for (tz = tone_zones; tz; tz = tz->next) + long_ret++; + ast_mutex_unlock(&tzlock); + + return (u_char *)&long_ret; + case ASTINDCURRENT: + tz = ast_get_indication_zone(NULL); + if (tz) { + *var_len = strlen(tz->country); + return (u_char *)tz->country; + } + *var_len = 0; + return NULL; + default: + break; + } + return NULL; +} + +static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + static unsigned long long_ret; + struct tone_zone *tz; + int i; + + if (header_simple_table(vp, name, length, exact, var_len, write_method, -1)) + return NULL; + + if (ast_mutex_lock(&tzlock)) { + ast_log(LOG_WARNING, "Unable to lock tone_zones list\n"); + snmp_log(LOG_ERR, "Unable to lock tone_zones list in ast_var_indications_table\n"); + return NULL; + } + i = name[*length - 1] - 1; + for (tz = tone_zones; tz && i; tz = tz->next) + i--; + ast_mutex_unlock(&tzlock); + if (tz == NULL) + return NULL; + + switch (vp->magic) { + case ASTINDINDEX: + long_ret = name[*length - 1]; + return (u_char *)&long_ret; + case ASTINDCOUNTRY: + *var_len = strlen(tz->country); + return (u_char *)tz->country; + case ASTINDALIAS: + if (tz->alias) { + *var_len = strlen(tz->alias); + return (u_char *)tz->alias; + } + return NULL; + case ASTINDDESCRIPTION: + *var_len = strlen(tz->description); + return (u_char *)tz->description; + default: + break; + } + return NULL; +} + +static int countmodule(const char *mod, const char *desc, int use, const char *like) +{ + return 1; +} + +static u_char *ast_var_Modules(struct variable *vp, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + static unsigned long long_ret; + + if (header_generic(vp, name, length, exact, var_len, write_method)) + return NULL; + + switch (vp->magic) { + case ASTMODCOUNT: + long_ret = ast_update_module_list(countmodule, NULL); + return (u_char *)&long_ret; + default: + break; + } + return NULL; +} + +static u_char *ast_var_Version(struct variable *vp, oid *name, size_t *length, + int exact, size_t *var_len, WriteMethod **write_method) +{ + static unsigned long long_ret; + + if (header_generic(vp, name, length, exact, var_len, write_method)) + return NULL; + + switch (vp->magic) { + case ASTVERSTRING: + *var_len = strlen(ASTERISK_VERSION); + return (u_char *)ASTERISK_VERSION; + case ASTVERTAG: + long_ret = ASTERISK_VERSION_NUM; + return (u_char *)&long_ret; + default: + break; + } + return NULL; +} + +static int term_asterisk_mib(int majorID, int minorID, void *serverarg, void *clientarg) +{ + unregister_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid)); + return 0; +} + +static void init_asterisk_mib(void) +{ + static struct variable4 asterisk_vars[] = { + {ASTVERSTRING, ASN_OCTET_STR, RONLY, ast_var_Version, 2, {ASTVERSION, ASTVERSTRING}}, + {ASTVERTAG, ASN_UNSIGNED, RONLY, ast_var_Version, 2, {ASTVERSION, ASTVERTAG}}, + {ASTCONFUPTIME, ASN_TIMETICKS, RONLY, ast_var_Config, 2, {ASTCONFIGURATION, ASTCONFUPTIME}}, + {ASTCONFRELOADTIME, ASN_TIMETICKS, RONLY, ast_var_Config, 2, {ASTCONFIGURATION, ASTCONFRELOADTIME}}, + {ASTCONFPID, ASN_INTEGER, RONLY, ast_var_Config, 2, {ASTCONFIGURATION, ASTCONFPID}}, + {ASTCONFSOCKET, ASN_OCTET_STR, RONLY, ast_var_Config, 2, {ASTCONFIGURATION, ASTCONFSOCKET}}, + {ASTMODCOUNT, ASN_INTEGER, RONLY, ast_var_Modules , 2, {ASTMODULES, ASTMODCOUNT}}, + {ASTINDCOUNT, ASN_INTEGER, RONLY, ast_var_indications, 2, {ASTINDICATIONS, ASTINDCOUNT}}, + {ASTINDCURRENT, ASN_OCTET_STR, RONLY, ast_var_indications, 2, {ASTINDICATIONS, ASTINDCURRENT}}, + {ASTINDINDEX, ASN_INTEGER, RONLY, ast_var_indications_table, 4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDINDEX}}, + {ASTINDCOUNTRY, ASN_OCTET_STR, RONLY, ast_var_indications_table, 4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDCOUNTRY}}, + {ASTINDALIAS, ASN_OCTET_STR, RONLY, ast_var_indications_table, 4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDALIAS}}, + {ASTINDDESCRIPTION, ASN_OCTET_STR, RONLY, ast_var_indications_table, 4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDDESCRIPTION}}, + {ASTCHANCOUNT, ASN_INTEGER, RONLY, ast_var_channels, 2, {ASTCHANNELS, ASTCHANCOUNT}}, + {ASTCHANINDEX, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANINDEX}}, + {ASTCHANNAME, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANNAME}}, + {ASTCHANLANGUAGE, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANLANGUAGE}}, + {ASTCHANTYPE, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTYPE}}, + {ASTCHANMUSICCLASS, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUSICCLASS}}, + {ASTCHANBRIDGE, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANBRIDGE}}, + {ASTCHANMASQ, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQ}}, + {ASTCHANMASQR, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQR}}, + {ASTCHANWHENHANGUP, ASN_TIMETICKS, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANWHENHANGUP}}, + {ASTCHANAPP, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAPP}}, + {ASTCHANDATA, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANDATA}}, + {ASTCHANCONTEXT, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCONTEXT}}, + {ASTCHANMACROCONTEXT, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROCONTEXT}}, + {ASTCHANMACROEXTEN, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROEXTEN}}, + {ASTCHANMACROPRI, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROPRI}}, + {ASTCHANEXTEN, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANEXTEN}}, + {ASTCHANPRI, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPRI}}, + {ASTCHANACCOUNTCODE, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANACCOUNTCODE}}, + {ASTCHANFORWARDTO, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFORWARDTO}}, + {ASTCHANUNIQUEID, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANUNIQUEID}}, + {ASTCHANCALLGROUP, ASN_UNSIGNED, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCALLGROUP}}, + {ASTCHANPICKUPGROUP, ASN_UNSIGNED, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPICKUPGROUP}}, + {ASTCHANSTATE, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANSTATE}}, + {ASTCHANMUTED, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUTED}}, + {ASTCHANRINGS, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANRINGS}}, + {ASTCHANCIDDNID, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDDNID}}, + {ASTCHANCIDNUM, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNUM}}, + {ASTCHANCIDNAME, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNAME}}, + {ASTCHANCIDANI, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI}}, + {ASTCHANCIDRDNIS, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDRDNIS}}, + {ASTCHANCIDPRES, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDPRES}}, + {ASTCHANCIDANI2, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI2}}, + {ASTCHANCIDTON, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTON}}, + {ASTCHANCIDTNS, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTNS}}, + {ASTCHANAMAFLAGS, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAMAFLAGS}}, + {ASTCHANADSI, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANADSI}}, + {ASTCHANTONEZONE, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTONEZONE}}, + {ASTCHANHANGUPCAUSE, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANHANGUPCAUSE}}, + {ASTCHANVARIABLES, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANVARIABLES}}, + {ASTCHANFLAGS, ASN_OCTET_STR, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFLAGS}}, + {ASTCHANTRANSFERCAP, ASN_INTEGER, RONLY, ast_var_channels_table, 4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTRANSFERCAP}}, + {ASTCHANTYPECOUNT, ASN_INTEGER, RONLY, ast_var_channel_types, 2, {ASTCHANNELS, ASTCHANTYPECOUNT}}, + {ASTCHANTYPEINDEX, ASN_INTEGER, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDEX}}, + {ASTCHANTYPENAME, ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPENAME}}, + {ASTCHANTYPEDESC, ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDESC}}, + {ASTCHANTYPEDEVSTATE, ASN_INTEGER, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDEVSTATE}}, + {ASTCHANTYPEINDICATIONS, ASN_INTEGER, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDICATIONS}}, + {ASTCHANTYPETRANSFER, ASN_INTEGER, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPETRANSFER}}, + {ASTCHANTYPECHANNELS, ASN_GAUGE, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPECHANNELS}}, + }; + + register_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid), + "ASTERISK-MIB implementation for Asterisk."); + + REGISTER_MIB("res_snmp", asterisk_vars, variable4, asterisk_oid); + + snmp_register_callback(SNMP_CALLBACK_LIBRARY, + SNMP_CALLBACK_SHUTDOWN, + term_asterisk_mib, NULL); +} + +/* + * Local Variables: + * c-basic-offset: 4 + * c-file-offsets: ((case-label . 0)) + * tab-width: 4 + * indent-tabs-mode: t + * End: + */ diff --git a/res/snmp/agent.h b/res/snmp/agent.h new file mode 100644 index 000000000..21389d6c9 --- /dev/null +++ b/res/snmp/agent.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2006 Voop as + * Thorsten Lockert <tholo@voop.as> + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief SNMP Agent / SubAgent support for Asterisk + * + * \author Thorsten Lockert <tholo@voop.as> + */ + +/*! + * \internal + * \brief Thread running the SNMP Agent or Subagent + * \param Not used -- required by pthread_create + * \return A pointer with return status -- not used + * + * This represent the main thread of the SNMP [sub]agent, and + * will initialize SNMP and loop, processing requests until + * termination is requested by resetting the flag in + * \ref res_snmp_dontStop. + */ +void *agent_thread(void *); + +/*! + * \internal + * Flag saying whether we run as a Subagent or full Agent + */ +extern int res_snmp_agentx_subagent; + +/*! + * \internal + * Flag stating the agent thread should not terminate + */ +extern int res_snmp_dont_stop; |