915 lines
31 KiB
C
915 lines
31 KiB
C
/*
|
|
* 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>
|
|
*/
|
|
|
|
/*** MODULEINFO
|
|
<support_level>extended</support_level>
|
|
***/
|
|
|
|
/* Needed for net-snmp headers */
|
|
#define ASTMM_LIBC ASTMM_IGNORE
|
|
#include "asterisk.h"
|
|
|
|
/*
|
|
* There is some collision collision between netsmp and asterisk names,
|
|
* causing build under AST_DEVMODE to fail.
|
|
*
|
|
* The following PACKAGE_* macros are one place.
|
|
* Also netsnmp has an improper check for HAVE_DMALLOC_H, using
|
|
* #if HAVE_DMALLOC_H instead of #ifdef HAVE_DMALLOC_H
|
|
* As a countermeasure we define it to 0, however this will fail
|
|
* when the proper check is implemented.
|
|
*/
|
|
#ifdef PACKAGE_NAME
|
|
#undef PACKAGE_NAME
|
|
#endif
|
|
#ifdef PACKAGE_BUGREPORT
|
|
#undef PACKAGE_BUGREPORT
|
|
#endif
|
|
#ifdef PACKAGE_STRING
|
|
#undef PACKAGE_STRING
|
|
#endif
|
|
#ifdef PACKAGE_TARNAME
|
|
#undef PACKAGE_TARNAME
|
|
#endif
|
|
#ifdef PACKAGE_VERSION
|
|
#undef PACKAGE_VERSION
|
|
#endif
|
|
#ifndef HAVE_DMALLOC_H
|
|
#define HAVE_DMALLOC_H 0 /* XXX we shouldn't do this */
|
|
#endif
|
|
|
|
#if defined(__OpenBSD__)
|
|
/*
|
|
* OpenBSD uses old "legacy" cc which has a rather pedantic builtin preprocessor.
|
|
* Using a macro which is not #defined throws an error.
|
|
*/
|
|
#define __NetBSD_Version__ 0
|
|
#endif
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
#include <net-snmp/net-snmp-includes.h>
|
|
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
|
|
|
#if !defined(RONLY) && defined(NETSNMP_OLDAPI_RONLY)
|
|
#define RONLY NETSNMP_OLDAPI_RONLY
|
|
#endif
|
|
|
|
#include "asterisk/paths.h" /* need ast_config_AST_SOCKET */
|
|
#include "asterisk/channel.h"
|
|
#include "asterisk/logger.h"
|
|
#include "asterisk/options.h"
|
|
#include "asterisk/indications.h"
|
|
#include "asterisk/ast_version.h"
|
|
#include "asterisk/pbx.h"
|
|
|
|
/* Collision 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);
|
|
|
|
/* 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 ASTCONFACTIVECALLS 5
|
|
#define ASTCONFPROCESSEDCALLS 6
|
|
|
|
#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
|
|
|
|
#define ASTCHANSCALARS 5
|
|
#define ASTCHANBRIDGECOUNT 1
|
|
|
|
void *agent_thread(void *arg)
|
|
{
|
|
ast_verb(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_verb(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;
|
|
|
|
if (vp->magic != ASTCHANCOUNT)
|
|
return NULL;
|
|
|
|
long_ret = ast_active_channels();
|
|
|
|
return (u_char *)&long_ret;
|
|
}
|
|
|
|
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 = NULL;
|
|
int i, bit;
|
|
struct ast_str *out = ast_str_alloca(2048);
|
|
struct ast_channel_iterator *iter;
|
|
|
|
if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
|
|
return NULL;
|
|
|
|
i = name[*length - 1] - 1;
|
|
|
|
if (!(iter = ast_channel_iterator_all_new())) {
|
|
return NULL;
|
|
}
|
|
|
|
while ((chan = ast_channel_iterator_next(iter)) && i) {
|
|
ast_channel_unref(chan);
|
|
i--;
|
|
}
|
|
|
|
iter = ast_channel_iterator_destroy(iter);
|
|
|
|
if (chan == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
*var_len = sizeof(long_ret);
|
|
|
|
ast_channel_lock(chan);
|
|
|
|
switch (vp->magic) {
|
|
case ASTCHANINDEX:
|
|
long_ret = name[*length - 1];
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANNAME:
|
|
if (!ast_strlen_zero(ast_channel_name(chan))) {
|
|
ast_copy_string(string_ret, ast_channel_name(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANLANGUAGE:
|
|
if (!ast_strlen_zero(ast_channel_language(chan))) {
|
|
ast_copy_string(string_ret, ast_channel_language(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANTYPE:
|
|
ast_copy_string(string_ret, ast_channel_tech(chan)->type, sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
break;
|
|
case ASTCHANMUSICCLASS:
|
|
if (!ast_strlen_zero(ast_channel_musicclass(chan))) {
|
|
ast_copy_string(string_ret, ast_channel_musicclass(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANBRIDGE:
|
|
ast_channel_unlock(chan);
|
|
bridge = ast_channel_bridge_peer(chan);
|
|
if (bridge) {
|
|
ast_channel_lock(bridge);
|
|
ast_copy_string(string_ret, ast_channel_name(bridge), sizeof(string_ret));
|
|
ast_channel_unlock(bridge);
|
|
ast_channel_unref(bridge);
|
|
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
ast_channel_lock(chan);
|
|
break;
|
|
case ASTCHANMASQ:
|
|
if (ast_channel_masq(chan) && !ast_strlen_zero(ast_channel_name(ast_channel_masq(chan)))) {
|
|
ast_copy_string(string_ret, ast_channel_name(ast_channel_masq(chan)), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANMASQR:
|
|
if (ast_channel_masqr(chan) && !ast_strlen_zero(ast_channel_name(ast_channel_masqr(chan)))) {
|
|
ast_copy_string(string_ret, ast_channel_name(ast_channel_masqr(chan)), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANWHENHANGUP:
|
|
if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
|
|
gettimeofday(&tval, NULL);
|
|
long_ret = difftime(ast_channel_whentohangup(chan)->tv_sec, tval.tv_sec) * 100 - tval.tv_usec / 10000;
|
|
ret= (u_char *)&long_ret;
|
|
}
|
|
break;
|
|
case ASTCHANAPP:
|
|
if (ast_channel_appl(chan)) {
|
|
ast_copy_string(string_ret, ast_channel_appl(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANDATA:
|
|
if (ast_channel_data(chan)) {
|
|
ast_copy_string(string_ret, ast_channel_data(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANCONTEXT:
|
|
ast_copy_string(string_ret, ast_channel_context(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
break;
|
|
case ASTCHANMACROCONTEXT:
|
|
ast_copy_string(string_ret, ast_channel_macrocontext(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
break;
|
|
case ASTCHANMACROEXTEN:
|
|
ast_copy_string(string_ret, ast_channel_macroexten(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
break;
|
|
case ASTCHANMACROPRI:
|
|
long_ret = ast_channel_macropriority(chan);
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANEXTEN:
|
|
ast_copy_string(string_ret, ast_channel_exten(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
break;
|
|
case ASTCHANPRI:
|
|
long_ret = ast_channel_priority(chan);
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANACCOUNTCODE:
|
|
if (!ast_strlen_zero(ast_channel_accountcode(chan))) {
|
|
ast_copy_string(string_ret, ast_channel_accountcode(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANFORWARDTO:
|
|
if (!ast_strlen_zero(ast_channel_call_forward(chan))) {
|
|
ast_copy_string(string_ret, ast_channel_call_forward(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANUNIQUEID:
|
|
ast_copy_string(string_ret, ast_channel_uniqueid(chan), sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
break;
|
|
case ASTCHANCALLGROUP:
|
|
long_ret = ast_channel_callgroup(chan);
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANPICKUPGROUP:
|
|
long_ret = ast_channel_pickupgroup(chan);
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANSTATE:
|
|
long_ret = ast_channel_state(chan) & 0xffff;
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANMUTED:
|
|
long_ret = ast_channel_state(chan) & AST_STATE_MUTE ? 1 : 2;
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANRINGS:
|
|
long_ret = ast_channel_rings(chan);
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANCIDDNID:
|
|
if (ast_channel_dialed(chan)->number.str) {
|
|
ast_copy_string(string_ret, ast_channel_dialed(chan)->number.str, sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANCIDNUM:
|
|
if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
|
|
ast_copy_string(string_ret, ast_channel_caller(chan)->id.number.str, sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANCIDNAME:
|
|
if (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) {
|
|
ast_copy_string(string_ret, ast_channel_caller(chan)->id.name.str, sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANCIDANI:
|
|
if (ast_channel_caller(chan)->ani.number.valid && ast_channel_caller(chan)->ani.number.str) {
|
|
ast_copy_string(string_ret, ast_channel_caller(chan)->ani.number.str, sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANCIDRDNIS:
|
|
if (ast_channel_redirecting(chan)->from.number.valid && ast_channel_redirecting(chan)->from.number.str) {
|
|
ast_copy_string(string_ret, ast_channel_redirecting(chan)->from.number.str, sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANCIDPRES:
|
|
long_ret = ast_party_id_presentation(&ast_channel_caller(chan)->id);
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANCIDANI2:
|
|
long_ret = ast_channel_caller(chan)->ani2;
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANCIDTON:
|
|
long_ret = ast_channel_caller(chan)->id.number.plan;
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANCIDTNS:
|
|
long_ret = ast_channel_dialed(chan)->transit_network_select;
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANAMAFLAGS:
|
|
long_ret = ast_channel_amaflags(chan);
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANADSI:
|
|
long_ret = ast_channel_adsicpe(chan);
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANTONEZONE:
|
|
if (ast_channel_zone(chan)) {
|
|
ast_copy_string(string_ret, ast_channel_zone(chan)->country, sizeof(string_ret));
|
|
*var_len = strlen(string_ret);
|
|
ret = (u_char *)string_ret;
|
|
}
|
|
break;
|
|
case ASTCHANHANGUPCAUSE:
|
|
long_ret = ast_channel_hangupcause(chan);
|
|
ret = (u_char *)&long_ret;
|
|
break;
|
|
case ASTCHANVARIABLES:
|
|
if (pbx_builtin_serialize_variables(chan, &out)) {
|
|
*var_len = ast_str_strlen(out);
|
|
ret = (u_char *)ast_str_buffer(out);
|
|
}
|
|
break;
|
|
case ASTCHANFLAGS:
|
|
bits_ret[0] = 0;
|
|
for (bit = 0; bit < 8; bit++)
|
|
bits_ret[0] |= ((ast_channel_flags(chan)->flags & (1 << bit)) >> bit) << (7 - bit);
|
|
bits_ret[1] = 0;
|
|
for (bit = 0; bit < 8; bit++)
|
|
bits_ret[1] |= (((ast_channel_flags(chan)->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
|
|
*var_len = 2;
|
|
ret = bits_ret;
|
|
break;
|
|
case ASTCHANTRANSFERCAP:
|
|
long_ret = ast_channel_transfercapability(chan);
|
|
ret = (u_char *)&long_ret;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ast_channel_unlock(chan);
|
|
chan = ast_channel_unref(chan);
|
|
|
|
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;
|
|
|
|
if (vp->magic != ASTCHANTYPECOUNT)
|
|
return NULL;
|
|
|
|
for (long_ret = 0, channel_types = next = ast_channeltype_list(); next; next = next->next)
|
|
long_ret++;
|
|
ast_variables_destroy(channel_types);
|
|
|
|
return (u_char *)&long_ret;
|
|
}
|
|
|
|
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:
|
|
{
|
|
struct ast_channel_iterator *iter;
|
|
|
|
long_ret = 0;
|
|
|
|
if (!(iter = ast_channel_iterator_all_new())) {
|
|
return NULL;
|
|
}
|
|
|
|
while ((chan = ast_channel_iterator_next(iter))) {
|
|
if (ast_channel_tech(chan) == tech) {
|
|
long_ret++;
|
|
}
|
|
chan = ast_channel_unref(chan);
|
|
}
|
|
|
|
ast_channel_iterator_destroy(iter);
|
|
|
|
return (u_char *)&long_ret;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static u_char *ast_var_channel_bridge(struct variable *vp, oid *name, size_t *length,
|
|
int exact, size_t *var_len, WriteMethod **write_method)
|
|
{
|
|
static unsigned long long_ret;
|
|
struct ast_channel *chan = NULL;
|
|
struct ast_channel_iterator *iter;
|
|
|
|
long_ret = 0;
|
|
|
|
if (header_generic(vp, name, length, exact, var_len, write_method)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!(iter = ast_channel_iterator_all_new())) {
|
|
return NULL;
|
|
}
|
|
|
|
while ((chan = ast_channel_iterator_next(iter))) {
|
|
ast_channel_lock(chan);
|
|
if (ast_channel_is_bridged(chan)) {
|
|
long_ret++;
|
|
}
|
|
ast_channel_unlock(chan);
|
|
chan = ast_channel_unref(chan);
|
|
}
|
|
|
|
ast_channel_iterator_destroy(iter);
|
|
|
|
*var_len = sizeof(long_ret);
|
|
|
|
return (vp->magic == ASTCHANBRIDGECOUNT) ? (u_char *) &long_ret : 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.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
|
|
return (u_char *)&long_ret;
|
|
case ASTCONFRELOADTIME:
|
|
gettimeofday(&tval, NULL);
|
|
if (ast_lastreloadtime.tv_sec)
|
|
long_ret = difftime(tval.tv_sec, ast_lastreloadtime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_lastreloadtime.tv_usec / 10000;
|
|
else
|
|
long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.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;
|
|
case ASTCONFACTIVECALLS:
|
|
long_ret = ast_active_calls();
|
|
return (u_char *)&long_ret;
|
|
case ASTCONFPROCESSEDCALLS:
|
|
long_ret = ast_processed_calls();
|
|
return (u_char *)&long_ret;
|
|
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;
|
|
static char ret_buf[128];
|
|
struct ast_tone_zone *tz = NULL;
|
|
|
|
if (header_generic(vp, name, length, exact, var_len, write_method))
|
|
return NULL;
|
|
|
|
switch (vp->magic) {
|
|
case ASTINDCOUNT:
|
|
{
|
|
struct ao2_iterator i;
|
|
|
|
long_ret = 0;
|
|
|
|
i = ast_tone_zone_iterator_init();
|
|
while ((tz = ao2_iterator_next(&i))) {
|
|
tz = ast_tone_zone_unref(tz);
|
|
long_ret++;
|
|
}
|
|
ao2_iterator_destroy(&i);
|
|
|
|
return (u_char *) &long_ret;
|
|
}
|
|
case ASTINDCURRENT:
|
|
tz = ast_get_indication_zone(NULL);
|
|
if (tz) {
|
|
ast_copy_string(ret_buf, tz->country, sizeof(ret_buf));
|
|
*var_len = strlen(ret_buf);
|
|
tz = ast_tone_zone_unref(tz);
|
|
return (u_char *) ret_buf;
|
|
}
|
|
*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;
|
|
static char ret_buf[256];
|
|
struct ast_tone_zone *tz = NULL;
|
|
int i;
|
|
struct ao2_iterator iter;
|
|
|
|
if (header_simple_table(vp, name, length, exact, var_len, write_method, -1)) {
|
|
return NULL;
|
|
}
|
|
|
|
i = name[*length - 1] - 1;
|
|
|
|
iter = ast_tone_zone_iterator_init();
|
|
|
|
while ((tz = ao2_iterator_next(&iter)) && i) {
|
|
tz = ast_tone_zone_unref(tz);
|
|
i--;
|
|
}
|
|
ao2_iterator_destroy(&iter);
|
|
|
|
if (tz == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
switch (vp->magic) {
|
|
case ASTINDINDEX:
|
|
ast_tone_zone_unref(tz);
|
|
long_ret = name[*length - 1];
|
|
return (u_char *)&long_ret;
|
|
case ASTINDCOUNTRY:
|
|
ast_copy_string(ret_buf, tz->country, sizeof(ret_buf));
|
|
ast_tone_zone_unref(tz);
|
|
*var_len = strlen(ret_buf);
|
|
return (u_char *) ret_buf;
|
|
case ASTINDALIAS:
|
|
/* No longer exists */
|
|
ast_tone_zone_unref(tz);
|
|
return NULL;
|
|
case ASTINDDESCRIPTION:
|
|
ast_tone_zone_lock(tz);
|
|
ast_copy_string(ret_buf, tz->description, sizeof(ret_buf));
|
|
ast_tone_zone_unlock(tz);
|
|
ast_tone_zone_unref(tz);
|
|
*var_len = strlen(ret_buf);
|
|
return (u_char *) ret_buf;
|
|
default:
|
|
ast_tone_zone_unref(tz);
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int countmodule(const char *mod, const char *desc, int use, const char *status,
|
|
const char *like, enum ast_module_support_level support_level)
|
|
{
|
|
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;
|
|
|
|
if (vp->magic != ASTMODCOUNT)
|
|
return NULL;
|
|
|
|
long_ret = ast_update_module_list(countmodule, NULL);
|
|
|
|
return (u_char *)&long_ret;
|
|
}
|
|
|
|
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:
|
|
{
|
|
const char *version = ast_get_version();
|
|
*var_len = strlen(version);
|
|
return (u_char *)version;
|
|
}
|
|
case ASTVERTAG:
|
|
sscanf(ast_get_version_num(), "%30lu", &long_ret);
|
|
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}},
|
|
{ASTCONFACTIVECALLS, ASN_GAUGE, RONLY, ast_var_Config, 2, {ASTCONFIGURATION, ASTCONFACTIVECALLS}},
|
|
{ASTCONFPROCESSEDCALLS, ASN_COUNTER, RONLY, ast_var_Config, 2, {ASTCONFIGURATION, ASTCONFPROCESSEDCALLS}},
|
|
{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_GAUGE, 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}},
|
|
{ASTCHANBRIDGECOUNT, ASN_GAUGE, RONLY, ast_var_channel_bridge, 3, {ASTCHANNELS, ASTCHANSCALARS, ASTCHANBRIDGECOUNT}},
|
|
};
|
|
|
|
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:
|
|
*/
|