From 6a86c7c5c90c3452e8a85141b87bdffec40dd914 Mon Sep 17 00:00:00 2001 From: Mark Spencer <markster@digium.com> Date: Sun, 26 Feb 2006 20:46:11 +0000 Subject: [PATCH] Add SNMP support (bug #6439) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@11193 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- configs/res_snmp.conf.sample | 10 + doc/asterisk-mib.txt | 717 +++++++++++++++++++++++++++++ doc/digium-mib.txt | 17 + doc/snmp.txt | 36 ++ res/Makefile | 8 + res/res_snmp.c | 148 ++++++ res/snmp/agent.c | 845 +++++++++++++++++++++++++++++++++++ res/snmp/agent.h | 40 ++ 8 files changed, 1821 insertions(+) create mode 100644 configs/res_snmp.conf.sample create mode 100644 doc/asterisk-mib.txt create mode 100644 doc/digium-mib.txt create mode 100644 doc/snmp.txt create mode 100644 res/res_snmp.c create mode 100644 res/snmp/agent.c create mode 100644 res/snmp/agent.h diff --git a/configs/res_snmp.conf.sample b/configs/res_snmp.conf.sample new file mode 100644 index 0000000000..5ca09d5761 --- /dev/null +++ b/configs/res_snmp.conf.sample @@ -0,0 +1,10 @@ +; +; Configuration file for res_snmp +; + +[general] +; We run as a subagent per default -- to run as a full agent +; we must run as root (to be able to bind to port 161) +;subagent = yes +; SNMP must be explicitly enabled to be active +;enabled = yes diff --git a/doc/asterisk-mib.txt b/doc/asterisk-mib.txt new file mode 100644 index 0000000000..f4d6656f95 --- /dev/null +++ b/doc/asterisk-mib.txt @@ -0,0 +1,717 @@ +ASTERISK-MIB DEFINITIONS ::= BEGIN + +IMPORTS + OBJECT-TYPE, MODULE-IDENTITY, Integer32, Counter32, TimeTicks + FROM SNMPv2-SMI + + TEXTUAL-CONVENTION, DisplayString, TruthValue + FROM SNMPv2-TC + + digium + FROM DIGIUM-MIB; + +asterisk MODULE-IDENTITY + LAST-UPDATED "200602041900Z" + ORGANIZATION "Digium, Inc." + CONTACT-INFO + "Mark Spencer + Email: markster@digium.com" + DESCRIPTION + "Asterisk is an Open Source PBX. This MIB defined + objects for managing Asterisk instances." + ::= { digium 1 } + +asteriskVersion OBJECT IDENTIFIER ::= { asterisk 1 } +asteriskConfiguration OBJECT IDENTIFIER ::= { asterisk 2 } +asteriskModules OBJECT IDENTIFIER ::= { asterisk 3 } +asteriskIndications OBJECT IDENTIFIER ::= { asterisk 4 } +asteriskChannels OBJECT IDENTIFIER ::= { asterisk 5 } + +-- asteriskVersion + +astVersionString OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Text version string of the version of Asterisk that + the SNMP Agent was compiled to run against." + ::= { asteriskVersion 1 } + +astVersionTag OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "SubVersion revision of the version of Asterisk that + the SNMP Agent was compiled to run against -- this is + typically 0 for release-versions of Asterisk." + ::= { asteriskVersion 2 } + +-- asteriskConfiguration + +astConfigUpTime OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Time ticks since Asterisk was started." + ::= { asteriskConfiguration 1 } + +astConfigReloadTime OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Time ticks since Asterisk was last reloaded." + ::= { asteriskConfiguration 2 } + +astConfigPid OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The process id of the running Asterisk process." + ::= { asteriskConfiguration 3 } + +astConfigSocket OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The control socket for giving Asterisk commands." + ::= { asteriskConfiguration 4 } + +-- asteriskModules + +astNumModules OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of modules currently loaded into Asterisk." + ::= { asteriskModules 1 } + +-- asteriskIndications + +astNumIndications OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of indications currently defined in Asterisk." + ::= { asteriskIndications 1 } + +astCurrentIndication OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Default indication zone to use." + ::= { asteriskIndications 2 } + +astIndicationsTable OBJECT-TYPE + SYNTAX SEQUENCE OF AstIndicationsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table with all the indication zones currently know to + the running Asterisk instance." + ::= { asteriskIndications 3 } + +astIndicationsEntry OBJECT-TYPE + SYNTAX AstIndicationsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about a single indication zone." + INDEX { astIndIndex } + ::= { astIndicationsTable 1 } + +AstIndicationsEntry ::= SEQUENCE { + astIndIndex Integer32, + astIndCountry DisplayString, + astIndAlias DisplayString, + astIndDescription DisplayString +} + +astIndIndex OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Numerical index into the table of indication zones." + ::= { astIndicationsEntry 1 } + +astIndCountry OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Country for which the indication zone is valid, + typically this is the ISO 2-letter code of the country." + ::= { astIndicationsEntry 2 } + +astIndAlias OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { astIndicationsEntry 3 } + +astIndDescription OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Description of the indication zone, usually the full + name of the country it is valid for." + ::= { astIndicationsEntry 4 } + +-- asteriskChannels + +astNumChannels OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current number of active channels." + ::= { asteriskChannels 1 } + +astChanTable OBJECT-TYPE + SYNTAX SEQUENCE OF AstChanEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table with details of the currently active channels + in the Asterisk instance." + ::= { asteriskChannels 2 } + +astChanEntry OBJECT-TYPE + SYNTAX AstChanEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Details of a single channel." + INDEX { astChanIndex } + ::= { astChanTable 1 } + +AstChanEntry ::= SEQUENCE { + astChanIndex Integer32, + astChanName DisplayString, + astChanLanguage DisplayString, + astChanType DisplayString, + astChanMusicClass DisplayString, + astChanBridge DisplayString, + astChanMasq DisplayString, + astChanMasqr DisplayString, + astChanWhenHangup TimeTicks, + astChanApp DisplayString, + astChanData DisplayString, + astChanContext DisplayString, + astChanMacroContext DisplayString, + astChanMacroExten DisplayString, + astChanMacroPri Integer32, + astChanExten DisplayString, + astChanPri Integer32, + astChanAccountCode DisplayString, + astChanForwardTo DisplayString, + astChanUniqueId DisplayString, + astChanCallGroup Unsigned32, + astChanPickupGroup Unsigned32, + astChanState INTEGER, + astChanMuted TruthValue, + astChanRings Integer32, + astChanCidDNID DisplayString, + astChanCidNum DisplayString, + astChanCidName DisplayString, + astChanCidANI DisplayString, + astChanCidRDNIS DisplayString, + astChanCidPresentation DisplayString, + astChanCidANI2 Integer32, + astChanCidTON Integer32, + astChanCidTNS Integer32, + astChanAMAFlags INTEGER, + astChanADSI INTEGER, + astChanToneZone DisplayString, + astChanHangupCause INTEGER, + astChanVariables DisplayString, + astChanFlags BITS, + astChanTransferCap INTEGER +} + +astChanIndex OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Index into the channel table." + ::= { astChanEntry 1 } + +astChanName OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Name of the currentl channel." + ::= { astChanEntry 2 } + +astChanLanguage OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Which language the current channel is configured to + use -- used mainly for prompts." + ::= { astChanEntry 3 } + +astChanType OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Underlying technology for the current channel." + ::= { astChanEntry 4 } + +astChanMusicClass OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Music class to be used for Music on Hold for this + channel." + ::= { astChanEntry 5 } + +astChanBridge OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Which channel this channel is currently bridged (in a + conversation) with." + ::= { astChanEntry 6 } + +astChanMasq OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Channel masquerading for us." + ::= { astChanEntry 7 } + +astChanMasqr OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Channel we are masquerading for." + ::= { astChanEntry 8 } + +astChanWhenHangup OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "How long until this channel will be hung up." + ::= { astChanEntry 9 } + +astChanApp OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current application for the channel." + ::= { astChanEntry 10 } + +astChanData OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Arguments passed to the current application." + ::= { astChanEntry 11 } + +astChanContext OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current extension context." + ::= { astChanEntry 12 } + +astChanMacroContext OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current macro context." + ::= { astChanEntry 13 } + +astChanMacroExten OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current macro extension." + ::= { astChanEntry 14 } + +astChanMacroPri OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current macro priority." + ::= { astChanEntry 15 } + +astChanExten OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current extension." + ::= { astChanEntry 16 } + +astChanPri OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current priority." + ::= { astChanEntry 17 } + +astChanAccountCode OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Account Code for billing." + ::= { astChanEntry 18 } + +astChanForwardTo OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Where to forward to if asked to dial on this + interface." + ::= { astChanEntry 19 } + +astChanUniqueId OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Unique Channel Identifier." + ::= { astChanEntry 20 } + +astChanCallGroup OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Call Group." + ::= { astChanEntry 21 } + +astChanPickupGroup OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Pickup Group." + ::= { astChanEntry 22 } + +astChanState OBJECT-TYPE + SYNTAX INTEGER { + stateDown(0), + stateReserved(1), + stateOffHook(2), + stateDialing(3), + stateRing(4), + stateRinging(5), + stateUp(6), + stateBusy(7), + stateDialingOffHook(8), + statePreRing(9) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Channel state." + ::= { astChanEntry 23 } + +astChanMuted OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Transmission of voice data has been muted." + ::= { astChanEntry 24 } + +astChanRings OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of rings so far." + ::= { astChanEntry 25 } + +astChanCidDNID OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Dialled Number ID." + ::= { astChanEntry 26 } + +astChanCidNum OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Caller Number." + ::= { astChanEntry 27 } + +astChanCidName OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Caller Name." + ::= { astChanEntry 28 } + +astCanCidANI OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "ANI" + ::= { astChanEntry 29 } + +astChanCidRDNIS OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Redirected Dialled Number Service." + ::= { astChanEntry 30 } + +astChanCidPresentation OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number Presentation/Screening." + ::= { astChanEntry 31 } + +astChanCidANI2 OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "ANI 2 (info digit)." + ::= { astChanEntry 32 } + +astChanCidTON OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Type of Number." + ::= { astChanEntry 33 } + +astChanCidTNS OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Transit Network Select." + ::= { astChanEntry 34 } + +astChanAMAFlags OBJECT-TYPE + SYNTAX INTEGER { + Default(0), + Omit(1), + Billing(2), + Documentation(3) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "AMA Flags." + ::= { astChanEntry 35 } + +astChanADSI OBJECT-TYPE + SYNTAX INTEGER { + Unknown(0), + Available(1), + Unavailable(2), + OffHookOnly(3) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Whether or not ADSI is detected on CPE." + ::= { astChanEntry 36 } + +astChanToneZone OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Indication zone to use for channel." + ::= { astChanEntry 37 } + +astChanHangupCause OBJECT-TYPE + SYNTAX INTEGER { + NotDefined(0), + Unregistered(3), + Normal(16), + Busy(17), + NoAnswer(19), + Congestion(34), + Failure(38), + NoSuchDriver(66) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Why is the channel hung up." + ::= { astChanEntry 38 } + +astChanVariables OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Channel Variables defined for this channel." + ::= { astChanEntry 39 } + +astChanFlags OBJECT-TYPE + SYNTAX BITS { + WantsJitter(0), + DeferDTMF(1), + WriteInterrupt(2), + Blocking(3), + Zombie(4), + Exception(5), + MusicOnHold(6), + Spying(7), + NativeBridge(8), + AutoIncrementingLoop(9) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Flags set on this channel." + ::= { astChanEntry 40 } + +astChanTransferCap OBJECT-TYPE + SYNTAX INTEGER { + Speech(0), + Digital(8), + RestrictedDigital(9), + 3kAudio(16), + DigitalWithTones(17), + Video(24) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Transfer Capabilities for this channel." + ::= { astChanEntry 41 } + +astNumChanTypes OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of channel types (technologies) supported." + ::= { asteriskChannels 3 } + +astChanTypeTable OBJECT-TYPE + SYNTAX SEQUENCE OF AstChanTypeEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table with details of the supported channel types." + ::= { asteriskChannels 4 } + +astChanTypeEntry OBJECT-TYPE + SYNTAX AstChanTypeEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Information about a technology we support, including + how many channels are currently using this technology." + INDEX { astChanTypeIndex } + ::= { astChanTypeTable 1 } + +AstChanTypeEntry ::= SEQUENCE { + astChanTypeIndex Integer32, + astChanTypeName DisplayString, + astChanTypeDesc DisplayString, + astChanTypeDeviceState Integer32, + astChanTypeIndications Integer32, + astChanTypeTransfer Integer32, + astChanTypeChannels Gauge32 +} + +astChanTypeIndex OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Index into the table of channel types." + ::= { astChanTypeEntry 1 } + +astChanTypeName OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Unique name of the technology we are describing." + ::= { astChanTypeEntry 2 } + +astChanTypeDesc OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Description of the channel type (technology)." + ::= { astChanTypeEntry 3 } + +astChanTypeDeviceState OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Whether the current technology can hold device states." + ::= { astChanTypeEntry 4 } + +astChanTypeIndications OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Whether the current technology supports progress indication." + ::= { astChanTypeEntry 5 } + +astChanTypeTransfer OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Whether the current technology supports transfers, where + Asterisk can get out from inbetween two bridged channels." + ::= { astChanTypeEntry 6 } + +astChanTypeChannels OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of active channels using the current technology." + ::= { astChanTypeEntry 7 } + +END diff --git a/doc/digium-mib.txt b/doc/digium-mib.txt new file mode 100644 index 0000000000..018a080dd3 --- /dev/null +++ b/doc/digium-mib.txt @@ -0,0 +1,17 @@ +DIGIUM-MIB DEFINITIONS ::= BEGIN + +IMPORTS + enterprises + FROM SNMPv2-SMI; + +digium MODULE-IDENTITY + LAST-UPDATED "200602041900Z" + ORGANIZATION "Digium, Inc." + CONTACT-INFO + "Mark Spencer + Email: markster@digium.com" + DESCRIPTION + "" + ::= { enterprises 22736 } + +END diff --git a/doc/snmp.txt b/doc/snmp.txt new file mode 100644 index 0000000000..afab91c3e0 --- /dev/null +++ b/doc/snmp.txt @@ -0,0 +1,36 @@ +Asterisk SNMP Support +--------------------- + +Rudimentary support for SNMP access to Asterisk is available. To build +this, one needs to have Net-SNMP development headers and libraries on +the build system, including any libraries Net-SNMP depends on. + +Note that on some (many?) Linux-distributions the dependency list in +the net-snmp-devel list is not complete, and additional RPMs will need +to be installed. This is typically seen as attempts to build res_snmp +as net-snmp-devel is available, but then failures to find certain +libraries. + +SNMP support comes in two varieties -- as a sub-agent to a running SNMP +daemon using the AgentX protocol, or as a full standalone agent. If +you wish to run a full standalone agent, Asterisk must run as root in +order to find to port 161. + +Configuring access when running as a full agent is something that is +left as an exercise to the reader. + +To enable access to the Asterisk SNMP subagent from a master SNMP +daemon, one will need to enable AgentX support, and also make sure that +Asterisk will be able to access the Unix domain socket. One way of +doing this is to add the following to /etc/snmp/snmpd.conf: + + # Enable AgentX support + master agentx + + # Set permissions on AgentX socket and containing + # directory such that process in group 'asterisk' + # will be able to connect + agentXPerms 0660 0550 nobody asterisk + +This assumes that you run Asterisk under group 'asterisk' (and does +not care what user you run as). diff --git a/res/Makefile b/res/Makefile index 2759f4e49e..08ee8e14a3 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 0000000000..e62e6fb05d --- /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 0000000000..740f5c10e1 --- /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 0000000000..21389d6c94 --- /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; -- GitLab