diff --git a/conf.d/monitoring.conf.sample b/conf.d/monitoring.conf.sample new file mode 100644 index 00000000..50b24c06 --- /dev/null +++ b/conf.d/monitoring.conf.sample @@ -0,0 +1,154 @@ +; configure monitor module + +[general] + +; restart_alarm= +; after how many Yate restarts should the monitor send an alarm. +; default is 1 +;restart_alarm=1 + +; time (in seconds) for specifying for how long cached data should be kept or with which the cache time is increased on each access +;cache=1 + + +[database] +; enable or disable database monitoring. Default is false +;monitor=false + + +;[yate] +; this section is an example on how to configure a database account to be monitored +; name of the section is the database account + +; type= +; specify that this section is for database monitoring +;type=database + +;interval in seconds at which statistic data should be sent. Defaults to 3600 (1 hour) +;notiftime=3600 + +; alarm threshold for maximum number of queries. Defaults to 1000 +;maxqueries=1000 + +; alarm threshold for maximum number of failed queries. Defaults to 500 +;maxfailed=500 + +; alarm threshold for maximum number of queries returned with an error status. Defaults to 500 +;maxerrors=500 + +; alarm threshold for time took to execute a query. In miliseconds, defaults to 10 seconds. +;maxtimeperquery=10000 + + + +[call_qos] +; this is the configuration section for call monitoring +; to disable call monitoring comment this entire section or set monitor to false. Defaults to false. +;monitor=false + +; specify the call.cdr parameter based on which route monitoring should be done. Defaults to address. +;route=address + +; time_interval= +; Time interval in seconds at which the monitored values should be sent as notifications. +; Default value is 3600 (1 hour) +;time_interval=3600 + +;[192.168.168.185] +; this section is an example on how to configure a routing direction to be monitor for ASR/NER values and call statistics +; name of this section is the routing direction name. It should match the value of the route param from the call.cdr message + +; specify that this section is for call QOS monitoring on a given route +;type=call_qos + +; minASR= +; lower threshold at which the low ASR alarm is set for the current time interval. Value can be 0..100 +; Default is 0 ( to mean that no low ASR alarm will be sent) +;minASR=0 + +; maxASR= +; upper threshold at which the high ASR alarm is set for the current time interval. +; Default is 101 ( to mean that no high ASR alarm will be sent) +;maxASR=101 + +; minNER= +; threshold at which the low NER alarm should be set. +; Defaults to 0 +;minNER=0 + +; minimum number of calls received before calculating ASR and NER +; Defaults to 1 +;mincalls=1 + + +[sip] +; monitoring SIP parameters + +; list of gateways of which state to monitor +; It is a list of IP:port addresses separated by ';' +; If port is not present, the default SIP (5060) port will be added +;gateways= + +; threshold for sending an alarm signalling to many failed SIP authentications. Default is 0 (no alarm) +;max_failed_auths=0 + +; threshold for sending an alarm signalling that too many SIP transactions have timed out. Default is 0 (no alarm) +;max_transaction_timeouts=0 + +;threshold for sending an alarm signalling that too many SIP BYE transactions have not been acknowledged. Default is 0 (no alarm) +;max_byes_timeouts=0 + +; reset interval for alarms in seconds. Default is 0 (meaning alarms are not reset) +;reset_time=0 + + + +[sig] + +; enable monitoring for signalling components. Defaults to false. +;monitor=false + +; monitor trunks. Overrides the monitor value. Defaults to the monitor value. +;trunk= + +; monitor linkset. Overrides the monitor value. Defaults to the monitor value. +;linkset= + +; monitor links. Overrides the monitor value. Defaults to the monitor value. +;link= + +; monitor physical interfaces. Overrides the monitor value. Defaults to the monitor value. +;interface= + +; monitor ISDN. Overrides the monitor value. Defaults to the monitor value. +;isdn= + + + +[rtp] +; enable RTP monitoring? Defaults to false. +;monitor=false + +; RTP destinations to be monitored. Should be a comma separated list. +; i.e. rtp_directions=192.168.168.185,127.0.0.1 +;rtp_directions= + +; interval in secconds at which collected data should be reset. Defaults to 3600 seconds. +;reset_interval=3600 + + + +[mgcp] +; send notification if a MGCP gateway goes offline/back online? Defaults to false. +;gw_monitor=false + +; threshold for sending an alarm signalling that too many MGCP transactions have timed out. Default is 0 (no alarm) +;max_transaction_timeouts=0 + +; threshold for sending an alarm signalling that too many MGCP DLCX transactions have timed out. Default is 0 (no alarm) +;max_deletes_timeouts=0 + +; reset interval in seconds. Defaults to 0 (no reset) +;reset_time=0 + + diff --git a/conf.d/ysnmpagent.conf.sample b/conf.d/ysnmpagent.conf.sample new file mode 100644 index 00000000..13cf888a --- /dev/null +++ b/conf.d/ysnmpagent.conf.sample @@ -0,0 +1,86 @@ +[general] +; general SNMP configuration + +; port on which the module listens for SNMP messages. Defaults to 161. +;port=161 + +;thread priority for SNMP message processing. Defaults to normal. +;thread=normal + +[snmp_v2] +; SNMPv2 configuration + +; read only access community string. Mandatory. +ro_community= +; read write access community string. Mandatory. +rw_community= +; read create access community string. +rc_community= + + +[snmp_v3] +; SNMPv3 configuration + +; format for generating the snmpEngineID +; values are +; 1 = IPv4 address format, +; 2 = IPv6 address format, +; 3 = MAC address format, +; 4 = TEXT format, +; 5 = OCTETS format, +; 128 = ENTERPRISE specific format +; Defaults to 4 (TEXT) +;engine_format=4 + +; information for generating the snmpEngineID. Must correspond to the format set (i.e. if engine_format=1, engine_info must be a IPv4 address) +; NOTE! IPv6 address must not use the IPv6 short format. Mandatory. +; NOTE! OCTETS format must be a hexified string +engine_info= + +[traps] +; SNMP traps configuration + +;enable or disable all_notifications. Defaults to true. +;enable_traps=true + +; list traps to disable. Must be separated by ','. +; An entire substree of traps can be disabled by ending the name of the trap with ".*" +; (e.g. disable the whole database status traps by adding database.*) +disable_traps= + +; IP address to which the traps are sent. Defaults to localhost. +;remote_ip=localhost + +; port for the remote IP. Defaults to 162. +;remote_port=162 + +;SNMP protocol version to use for sending traps (values are SNMPv2c or SNMPv3). Defaults to SNMPv2c. +;proto_version=SNMPv2c + +; if SNMPv2 is used, set the community string used for the remote SNMP entity. Mandatory if SNMPv2c traps are used. +community= + +; if SNMPv3 is used, specify which configured user should be used for sending traps (there must be a section named like the given value to trap_user) +; see the example bellow (section [userV3]) for configuring a SNMPv3 user +; the specified user will not allowed to interrogate this SNMP agent, it will only be used to send traps to the configured traps receiver +;trap_user= + +;[userV3] +; Configure a section for a SNMPv3 user. The name of the user is the name of the section. +; To allow SNMPv3 interrogation, at least one SNMPv3 user must be configured + +; authentication pass phrase. If it is not set, authentication will not be required +;auth_password= + +; authentication method ( MD5 | SHA1 ) in case it is used. +;auth_protocol=MD5 + +; privacy pass phrase. If it is not set, encryption will not be required +;priv_password= + +; privacy encryption method ( DES | AES). Default is DES. +;priv_protocol=DES + +; user access level. Mandatory. Acceptable values are: readonly, readwrite, readcreate. +;access= + diff --git a/configure.in b/configure.in index a147a391..50e42030 100644 --- a/configure.in +++ b/configure.in @@ -1272,11 +1272,14 @@ AC_CONFIG_FILES([packing/rpm/yate.spec libs/ysig/Makefile libs/ypbx/Makefile libs/ymodem/Makefile + libs/yasn/Makefile + libs/ysnmp/Makefile share/Makefile share/scripts/Makefile share/skins/Makefile share/sounds/Makefile share/help/Makefile + share/data/Makefile conf.d/Makefile]) AC_CONFIG_FILES([yate-config],[chmod +x yate-config]) AC_CONFIG_FILES([run],[chmod +x run]) diff --git a/libs/yasn/Makefile.in b/libs/yasn/Makefile.in new file mode 100644 index 00000000..c8dcf2f8 --- /dev/null +++ b/libs/yasn/Makefile.in @@ -0,0 +1,56 @@ +# Makefile +# This file holds the make rules for the libyasn + +DEBUG := + +CXX := @CXX@ -Wall +AR := ar +DEFS := +INCLUDES := -I@top_srcdir@ -I../.. -I@srcdir@ +CFLAGS := @CFLAGS@ @MODULE_CPPFLAGS@ @INLINE_FLAGS@ +LDFLAGS:= @LDFLAGS@ -L../.. -lyate +INCFILES := @top_srcdir@/yateclass.h @srcdir@/yateasn.h + +PROGS= +LIBS = libyasn.a +OBJS = asn.o + +LOCALFLAGS = +LOCALLIBS = +COMPILE = $(CXX) $(DEFS) $(DEBUG) $(INCLUDES) $(CFLAGS) +LINK = $(CXX) $(LDFLAGS) + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +# include optional local make rules +-include YateLocal.mak + +.PHONY: all debug ddebug xdebug +all: $(LIBS) $(LIBD) $(PROGS) + +debug: + $(MAKE) all DEBUG=-g3 MODSTRIP= + +ddebug: + $(MAKE) all DEBUG='-g3 -DDEBUG' MODSTRIP= + +xdebug: + $(MAKE) all DEBUG='-g3 -DXDEBUG' MODSTRIP= + +.PHONY: strip +strip: all + strip --strip-debug --discard-locals $(PROGS) + +.PHONY: clean +clean: + @-$(RM) $(PROGS) $(LIBS) $(OBJS) core 2>/dev/null + +%.o: @srcdir@/%.cpp $(INCFILES) + $(COMPILE) -c $< + +Makefile: @srcdir@/Makefile.in ../../config.status + cd ../.. && ./config.status + +libyasn.a: $(OBJS) + $(AR) rcs $@ $^ diff --git a/libs/yasn/asn.cpp b/libs/yasn/asn.cpp new file mode 100644 index 00000000..d21cc2a8 --- /dev/null +++ b/libs/yasn/asn.cpp @@ -0,0 +1,1431 @@ +/** + * asn.cpp + * This file is part of the YATE Project http://YATE.null.ro + * + * ASN.1 Library + * + * Yet Another Telephony Engine - a fully featured software PBX and IVR + * Copyright (C) 2004-2010 Null Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "yateasn.h" + +using namespace TelEngine; + +static String s_libName = "ASNLib"; + +ASNLib::ASNLib() +{} + +ASNLib::~ASNLib() +{} + +int ASNLib::decodeLength(DataBlock& data) { + + XDebug(s_libName.c_str(),DebugAll,"::decodeLength() - from data='%p'",&data); + int length = 0; + uint8_t lengthByte = data[0]; + + if (lengthByte & ASN_LONG_LENGTH) { // the length is represented on more than one byte + + lengthByte &= ~ASN_LONG_LENGTH; /* turn MSB off */ + if (lengthByte == 0) + return InvalidLengthOrTag; + + if (lengthByte > sizeof(int)) + return InvalidLengthOrTag; + + for (int i = 0 ; i < lengthByte ; i++) + length = (length << 8) + data[1 + i]; + + data.cut(-lengthByte - 1); + return length; + + } else { // one byte for length + length = (int) lengthByte; + data.cut(-1); + return length; + } +} + +DataBlock ASNLib::buildLength(DataBlock& data) +{ + XDebug(s_libName.c_str(),DebugAll,"::buildLength() - encode length=%d",data.length()); + DataBlock lenDb; + if (data.length() < 0) + return lenDb; + if (data.length() < ASN_LONG_LENGTH) { + uint8_t l = data.length(); + lenDb.append(&l, 1); + return lenDb; + } + else { + uint8_t longLen = ASN_LONG_LENGTH; + int len = data.length(); + while (len > 0) { + uint8_t v = len & 0xFF; + lenDb.insert(DataBlock(&v,1)); + len >>= 8; + } + longLen |= lenDb.length(); + lenDb.insert(DataBlock(&longLen,1)); + return lenDb; + } + return lenDb; +} + +int ASNLib::decodeBoolean(DataBlock& data, bool* val, bool tagCheck) +{ + /** + * boolean = 0x01 length byte (byte == 0 => false, byte != 0 => true) + */ + XDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() from data='%p'",&data); + if (data.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = data.length(); +#endif + if (tagCheck) { + int type = data[0]; + if ((type != BOOLEAN)) { + XDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + data.cut(-1); + } + int length = decodeLength(data); + if (length < 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid Length in data='%p'",&data); + return length; + } + + if ((unsigned int)length > data.length() || length != 1) { + DDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid Length in data='%p'",&data); + return InvalidLengthOrTag; + } + if (!val) { + data.cut(-1); + DDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - Invalid buffer for return data"); + return InvalidContentsError; + } + *val = false; + if ((data[0] & 0xFF) != 0) + *val = true; + data.cut(-1); + DDebug(s_libName.c_str(),DebugAll,"::decodeBoolean() - decoded boolean value from data='%p', consumed %u bytes", + &data, initLen - data.length()); + return length; +} + +int ASNLib::decodeInteger(DataBlock& data, u_int64_t& intVal, unsigned int bytes, bool tagCheck) +{ + /** + * integer = 0x02 length byte {byte}* + */ + XDebug(s_libName.c_str(),DebugAll,"::decodeInteger() from data='%p'",&data); + u_int64_t value = 0; + if (data.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = data.length(); +#endif + if (tagCheck) { + int type = data[0]; + if ((type != INTEGER)) { + XDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + data.cut(-1); + } + int length = decodeLength(data); + if (length < 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Length in data='%p'",&data); + return length; + } + + if ((unsigned int)length > data.length()) { + DDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - Invalid Length in data='%p'",&data); + return InvalidLengthOrTag; + } + + if (data[0] & 0x80) + value = -1; /* integer is negative */ + int j = 0; + while (j < length) { + value = (value << 8) | data[j]; + j++; + } + intVal = value; + data.cut(-length); + DDebug(s_libName.c_str(),DebugAll,"::decodeInteger() - decoded integer value from data='%p', consumed %u bytes", + &data, initLen - data.length()); + return length; +} + +int ASNLib::decodeUINT8(DataBlock& data, u_int8_t* intVal, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeUINT8()"); + u_int64_t val; + int l = decodeInteger(data,val,sizeof(u_int8_t),tagCheck); + if (!intVal) { + DDebug(s_libName.c_str(),DebugAll,"::decodeUINT8() - Invalid buffer for return data"); + return InvalidContentsError; + } + *intVal = (u_int8_t) val; + return l; +} + +int ASNLib::decodeUINT16(DataBlock& data, u_int16_t* intVal, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeUINT16() from data='%p'",&data); + u_int64_t val; + int l = decodeInteger(data,val,sizeof(u_int16_t),tagCheck); + if (!intVal) { + DDebug(s_libName.c_str(),DebugAll,"::decodeUINT16() - Invalid buffer for return data"); + return InvalidContentsError; + } + *intVal = (u_int16_t) val; + return l; +} + +int ASNLib::decodeUINT32(DataBlock& data, u_int32_t* intVal, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeUINT32() from data='%p'",&data); + u_int64_t val; + int l = decodeInteger(data,val,sizeof(u_int32_t),tagCheck); + if (!intVal) { + DDebug(s_libName.c_str(),DebugAll,"::decodeUINT32() - Invalid buffer for return data"); + return InvalidContentsError; + } + *intVal = (u_int32_t) val; + return l; +} + +int ASNLib::decodeUINT64(DataBlock& data, u_int64_t* intVal, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeUINT64() from data='%p'",&data); + u_int64_t val; + int l = decodeInteger(data,val,sizeof(u_int64_t),tagCheck); + if (!intVal) { + DDebug(s_libName.c_str(),DebugAll,"::decodeUINT64() - Invalid buffer for return data"); + return InvalidContentsError; + } + *intVal = val; + return l; +} + +int ASNLib::decodeINT8(DataBlock& data, int8_t* intVal, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeINT8() from data='%p'",&data); + u_int64_t val; + int l = decodeInteger(data,val,sizeof(int8_t),tagCheck); + if (!intVal) { + DDebug(s_libName.c_str(),DebugAll,"::decodeINT8() - Invalid buffer for return data"); + return InvalidContentsError; + } + *intVal = (int8_t) val; + return l; +} + +int ASNLib::decodeINT16(DataBlock& data, int16_t* intVal, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeINT16() from data='%p'",&data); + u_int64_t val; + int l = decodeInteger(data,val,sizeof(int16_t),tagCheck); + if (!intVal) { + DDebug(s_libName.c_str(),DebugAll,"::decodeINT16() - Invalid buffer for return data"); + return InvalidContentsError; + } + *intVal = (int16_t) val; + return l; +} + +int ASNLib::decodeINT32(DataBlock& data, int32_t* intVal, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeINT32() from data='%p'",&data); + u_int64_t val; + int l = decodeInteger(data,val,sizeof(int32_t),tagCheck); + if (!intVal) { + DDebug(s_libName.c_str(),DebugAll,"::decodeINT32() - Invalid buffer for return data"); + return InvalidContentsError; + } + *intVal = (int32_t) val; + return l; +} + +int ASNLib::decodeINT64(DataBlock& data, int64_t* intVal, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeINT64() from data='%p'",&data); + u_int64_t val; + int l = decodeInteger(data,val,sizeof(int64_t),tagCheck); + if (!intVal) { + DDebug(s_libName.c_str(),DebugAll,"::decodeINT64() - Invalid buffer for return data"); + return InvalidContentsError; + } + *intVal = val; + return l; +} + +int ASNLib::decodeBitString(DataBlock& data, String* val, bool tagCheck) +{ + /** + * bitstring ::= 0x03 asnlength unusedBytes {byte}* + */ + XDebug(s_libName.c_str(),DebugAll, "::decodeBitString() from data='%p'",&data); + if (data.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = data.length(); +#endif + if (tagCheck) { + int type = data[0]; + if ((type != BIT_STRING)) { + XDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + data.cut(-1); + } + int length = decodeLength(data); + if (length < 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid Length in data='%p'",&data); + return length; + } + + if ((unsigned int)length > data.length()) { + DDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid Length in data='%p'",&data); + return InvalidLengthOrTag; + } + + if (data[0] > 7){ + DDebug(s_libName.c_str(),DebugAll, "::decodeBitString() - Invalid bitstring, unused bytes > 7 in data='%p'",&data); + return InvalidLengthOrTag; + } + int unused = data[0]; + data.cut(-1); + length--; + int j = 0; + if (!val) { + DDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - Invalid buffer for return data"); + data.cut(-length); + return InvalidContentsError; + } + *val = ""; + while (j < length) { + uint8_t byte = data[j]; + for (int i = 7; i > -1; i--) { + int c = (byte >> i) % 2; + *val += c; + } + j++; + } + *val = val->substr(0, length * 8 - unused); + data.cut(-length); + DDebug(s_libName.c_str(),DebugAll,"::decodeBitString() - decoded bit string value from data='%p', consumed %u bytes", + &data, initLen - data.length()); + return length; +} + +int ASNLib::decodeOctetString(DataBlock& db, OctetString* strVal, bool tagCheck) +{ + /** + * octet string ::= 0x04 asnlength {byte}* + */ + XDebug(s_libName.c_str(),DebugAll,":decodeOctetString() from data='%p'",&db); + if (db.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = db.length(); +#endif + if (tagCheck) { + int type = db[0]; + if (type != OCTET_STRING) { + XDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid Tag in data='%p'",&db); + return InvalidLengthOrTag; + } + db.cut(-1); + } + int length = decodeLength(db); + if (length < 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid Length in data='%p'",&db); + return length; + } + if ((unsigned int)length > db.length()) { + DDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid Length in data='%p'",&db); + return InvalidLengthOrTag; + } + if (!strVal) { + DDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - Invalid buffer for return data"); + return InvalidContentsError; + } + strVal->assign((void*)db.data(0,length),length); + db.cut(-length); + DDebug(s_libName.c_str(),DebugAll,"::decodeOctetString() - decoded octet string value from data='%p', consumed %u bytes", + &db, initLen - db.length()); + return length; +} + +int ASNLib::decodeNull(DataBlock& data, bool tagCheck) +{ + /** + * ASN.1 null := 0x05 00 + */ + XDebug(s_libName.c_str(),DebugAll,"::decodeNull() from data='%p'",&data); + if (tagCheck) { + if (data.length() < 2) + return InvalidLengthOrTag; + + if (data[0] != NULL_ID) { + XDebug(s_libName.c_str(),DebugAll, "::decodeNull() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + data.cut(-1); + } + int length = decodeLength(data); + if (length != 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeNull() - Invalid Length in data='%p'",&data); + return InvalidLengthOrTag;; + } + DDebug(s_libName.c_str(),DebugAll,"::decodeNull() - decoded null value from data='%p', consumed %u bytes", + &data, (tagCheck ? 2 : 1)); + return length; +} + +int ASNLib::decodeOID(DataBlock& data, ASNObjId* obj, bool tagCheck) +{ + /** + * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}* + * subidentifier ::= {leadingbyte}* lastbyte + * leadingbyte ::= 1 7bites + * lastbyte ::= 0 7bites + */ + XDebug(s_libName.c_str(),DebugAll,"::decodeOID() from data='%p'",&data); + if (data.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = data.length(); +#endif + if (tagCheck) { + if (data[0] != OBJECT_ID) { + XDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + data.cut(-1); + } + int length = decodeLength(data); + if (length < 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid Length in data='%p'",&data); + return length; + } + + if ((unsigned int)length > data.length()) { + DDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid Length in data='%p'",&data); + return InvalidLengthOrTag; + } + + if (length == 0) { + obj = 0; + return length; + } + + int j = 0; + String oid = ""; + unsigned int longNo = 0; + while (j < length) { + if (j == 0 && data[j] == 0x2b) // iso.3 identifier + oid += "1.3."; + else { + uint8_t byte = data[j]; + longNo += byte & ~ASN_BIT8; + if ((byte & ASN_BIT8) == ASN_BIT8) + longNo <<= 7; + else { + oid += longNo; + longNo = 0; + if (j != length -1) + oid += "."; + } + } + j++; + } + data.cut(-length); + if (!obj) { + DDebug(s_libName.c_str(),DebugAll,"::decodeOID() - Invalid buffer for return data"); + return InvalidContentsError; + } + *obj = oid; + DDebug(s_libName.c_str(),DebugAll,"::decodeOID() - decoded object ID from data='%p', consumed %u bytes", + &data, initLen - data.length()); + return length; +} + +int ASNLib::decodeReal(DataBlock& db, float* realVal, bool tagCheck) +{ + if (db.length() < 2) + return InvalidLengthOrTag; + unsigned int initLen = db.length(); + if (tagCheck) { + if (db[0] != REAL) { + XDebug(s_libName.c_str(),DebugAll,"::decodeReal() - Invalid Tag in data='%p'",&db); + return InvalidLengthOrTag; + } + db.cut(-1); + } + int length = decodeLength(db); + if (length < 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeReal() - Invalid Length in data='%p'",&db); + return length; + } + if ((unsigned int)length > db.length()) { + DDebug(s_libName.c_str(),DebugAll,"::decodeReal() - Invalid Length in data='%p'",&db); + return InvalidLengthOrTag; + } + db.cut(-length); + Debug(s_libName.c_str(),DebugInfo,"::decodeReal() - real value decoding not implemented, skipping over the %u bytes of the encoding", + initLen - db.length()); + return 0; +} + +int ASNLib::decodeString(DataBlock& data, String* str, int* type, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeString() from data='%p'",&data); + if (data.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = data.length(); +#endif + if (tagCheck) { + if (data[0] != NUMERIC_STR || + data[0] != PRINTABLE_STR || + data[0] != IA5_STR || + data[0] != VISIBLE_STR + ) { + XDebug(s_libName.c_str(),DebugAll,"::decodeString() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + if (type) + *type = data[0]; + data.cut(-1); + } + int length = decodeLength(data); + if (length < 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeString() -Invalid Length in data='%p'",&data); + return length; + } + + if ((unsigned int)length > data.length()) { + DDebug(s_libName.c_str(),DebugAll,"::decodeString() -Invalid Length in data='%p'",&data); + return InvalidLengthOrTag; + } + + String var = ""; + for (int i = 0; i < length; i++) + var += (char) (data[i] & 0x7f); + data.cut(-length); + if (!str || !type) { + DDebug(s_libName.c_str(),DebugAll,"::decodeString() - Invalid buffer for return data"); + return InvalidContentsError; + } + *str = var; + DDebug(s_libName.c_str(),DebugInfo,"::decodeString() - decode string value from data='%p', consumed %u bytes", + &data,initLen - data.length()); + return length; +} + + +int ASNLib::decodeUtf8(DataBlock& data, String* str, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeUtf8() from data='%p'",&data); + if (data.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = data.length(); +#endif + if (tagCheck) { + if (data[0] != UTF8_STR) { + XDebug(s_libName.c_str(),DebugAll,"::decodeUtf8() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + data.cut(-1); + } + int length = decodeLength(data); + if (length < 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeUtf8() -Invalid Length in data='%p'",&data); + return length; + } + + if ((unsigned int)length > data.length()) { + Debug(s_libName.c_str(),DebugAll,"::decodeUtf8() - Invalid Length in data='%p'",&data); + return InvalidLengthOrTag; + } + + String var = ""; + for (int i = 0; i < length; i++) + var += (char) (data[i]); + data.cut(-length); + if (String::lenUtf8(var.c_str()) < 0) + return ParseError; + if (!str) { + DDebug(s_libName.c_str(),DebugAll,"::decodeUTF8() - Invalid buffer for return data"); + return InvalidContentsError; + } + *str = var; + DDebug(s_libName.c_str(),DebugAll,"::decodeUtf8() - decoded an UTF8 string value from data='%p', consumed %u bytes",&data,initLen - data.length()); + return length; +} + +int ASNLib::decodeGenTime(DataBlock& data, unsigned int* time, unsigned int* fractions, bool* utc, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() from data='%p'",&data); + if (data.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = data.length(); +#endif + if (tagCheck) { + if (data[0] != GENERALIZED_TIME) { + XDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + data.cut(-1); + } + int length = decodeLength(data); + if (length < 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid Length in data='%p'",&data); + return length; + } + + if ((unsigned int)length > data.length() || length < 14) { + DDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid Length in data='%p'",&data); + return InvalidLengthOrTag; + } + String date = ""; + for (int i = 0; i < length; i++) + date += (char) (data[i]); + data.cut(-length); + + if (!(utc && fractions && time)) { + DDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - Invalid buffer for return data"); + return InvalidContentsError; + } + + unsigned int year, month, day, hours, minutes, seconds; + int timeDiff = 0; + + *utc = false; + *fractions = 0; + + if (date[date.length() - 1] == 'Z') { + *utc = true; + date = date.substr(0,date.length() - 1); + } + else { + int pos = date.find('-'); + if (pos < 0) + pos = date.find('+'); + if (pos >0 && pos != (int)date.length() - 5) + return InvalidContentsError; + if (pos > 0) { + char sign = date.at(pos); + unsigned int hDiff = (unsigned int) date.substr(date.length() - 4,2).toInteger(-1,10); + if (hDiff > 11) + return InvalidContentsError; + unsigned int mDiff = (unsigned int) date.substr(date.length() - 2,2).toInteger(-1,10); + if (mDiff > 59) + return InvalidContentsError; + unsigned int diff = Time::toEpoch(1970,1,1,hDiff,mDiff,0); + if (sign == '-') + timeDiff = diff; + else + timeDiff -= diff; + *utc = true; + date = date.substr(0,date.length() - 5); + } + } + ObjList* list = date.split('.'); + if (!list || list->count() > 2) + return InvalidContentsError; + if (list->count() == 2) + *fractions = (*list)[1]->toString().toInteger(0,10); + + String dateTime = (*list)[0]->toString(); + TelEngine::destruct(list); + + year = dateTime.substr(0,4).toInteger(-1,10); + month = dateTime.substr(4,2).toInteger(-1,10); + day = dateTime.substr(6,2).toInteger(-1,10); + hours = dateTime.substr(8,2).toInteger(-1,10); + minutes = dateTime.substr(10,2).toInteger(-1,10); + seconds = dateTime.substr(12,2).toInteger(-1,10); + if (year < 1970 || month > 12 || day > 31 || hours > 23 || minutes > 59 || seconds > 59) + return InvalidContentsError; + + unsigned int epochTime = Time::toEpoch(year,month,day,hours,minutes,seconds); + if (epochTime == (unsigned int) -1) + return InvalidContentsError; + *time = epochTime + timeDiff; + DDebug(s_libName.c_str(),DebugAll,"::decodeGenTime() - decoded time value from data='%p', consumed %u bytes",&data,initLen - data.length()); + return length; +} + +int ASNLib::decodeUTCTime(DataBlock& data, unsigned int* time, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() from data='%p'",&data); + if (data.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = data.length(); +#endif + if (tagCheck) { + if (data[0] != UTC_TIME) { + XDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + data.cut(-1); + } + int length = decodeLength(data); + if (length < 0) { + DDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid Length in data='%p'",&data); + return length; + } + + if ((unsigned int)length > data.length() || length < 11) { + DDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid Length in data='%p'",&data); + return InvalidLengthOrTag; + } + String date = ""; + for (int i = 0; i < length; i++) + date += (char) (data[i]); + data.cut(-length); + + if (!time) { + DDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - Invalid buffer for return data"); + return InvalidContentsError; + } + unsigned int year = 0, month = 0, day = 0, hours = 0, minutes = 0, seconds = 0; + int timeDiff = 0; + + int len = date.length(); + if (date[date.length() - 1] == 'Z') + date = date.substr(0,len - 1); + else { + int pos = date.find('-'); + if (pos < 0) + pos = date.find('+'); + if ((pos >0 && pos != len - 5) || pos < 0) + return InvalidContentsError; + if (pos > 0) { + char sign = date.at(pos); + unsigned int hDiff = (unsigned int) date.substr(len - 4,2).toInteger(-1,10); + if (hDiff > 11) + return InvalidContentsError; + unsigned int mDiff = (unsigned int) date.substr(len - 2,2).toInteger(-1,10); + if (mDiff > 59) + return InvalidContentsError; + unsigned int diff = Time::toEpoch(1970,1,1,hDiff,mDiff,0); + if (sign == '-') + timeDiff = diff; + else + timeDiff -= diff; + date = date.substr(0,len - 5); + } + } + year = date.substr(0,2).toInteger(-1,10); + year = (year > 50) ? 1900 + year : 2000 + year; + month = date.substr(2,2).toInteger(-1,10); + day = date.substr(4,2).toInteger(-1,10); + hours = date.substr(6,2).toInteger(-1,10); + minutes = date.substr(8,2).toInteger(-1,10); + if (date.length() > 10) + seconds = date.substr(10,2).toInteger(-1,10); + if (year < 1970 || month > 12 || day > 31 || hours > 23 || minutes > 59 || seconds > 59) + return InvalidContentsError; + + unsigned int epochTime = Time::toEpoch(year,month,day,hours,minutes,seconds); + if (epochTime == (unsigned int) -1) + return InvalidContentsError; + *time = epochTime + timeDiff; + DDebug(s_libName.c_str(),DebugAll,"::decodeUTCTime() - decoded time value from data='%p', consumed %u bytes",&data,initLen - data.length()); + return length; +} + +int ASNLib::decodeAny(DataBlock data, DataBlock* val, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeAny() from data='%p'",&data); + if (!val) { + DDebug(s_libName.c_str(),DebugAll,"::decodeAny() - Invalid buffer for return data"); + return InvalidContentsError; + } + val->append(data); + return data.length(); +} + +int ASNLib::decodeSequence(DataBlock& data, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeSequence() from data='%p'",&data); + if (data.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = data.length(); +#endif + if (tagCheck) { + if (data[0] != SEQUENCE) { + DDebug(s_libName.c_str(),DebugAll,"::decodeSequence() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + data.cut(-1); + } + int length = decodeLength(data); + if (length < 0) + Debug(s_libName.c_str(),DebugAll,"::decodeSequence() - Invalid Length in data='%p'",&data); + DDebug(s_libName.c_str(),DebugAll,"::decodeSequence() - decoded sequence tags from data='%p', consumed %u bytes",&data,initLen - data.length()); + return length; +} + +int ASNLib::decodeSet(DataBlock& data, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::decodeSet() from data='%p",&data); + if (data.length() < 2) + return InvalidLengthOrTag; +#ifdef DEBUG + unsigned int initLen = data.length(); +#endif + if (tagCheck) { + if (data[0] != SET) { + DDebug(s_libName.c_str(),DebugAll,"::decodeSet() - Invalid Tag in data='%p'",&data); + return InvalidLengthOrTag; + } + data.cut(-1); + } + int length = decodeLength(data); + if (length < 0) + DDebug(s_libName.c_str(),DebugAll,"::decodeSet() - Invalid Length in data='%p'",&data); + DDebug(s_libName.c_str(),DebugAll,"::decodeSet() - decoded set tags from data='%p', consumed %u bytes",&data,initLen - data.length()); + return length; +} + +DataBlock ASNLib::encodeBoolean(bool val, bool tagCheck) +{ + /** + * ASN.1 boolean ::= 0x01 asnlength=0x01 byte + */ + DataBlock data; + uint8_t b = BOOLEAN; + if (tagCheck) { + data.append(&b, 1); + b = 1; + data.append(&b, 1); + } + b = val ? 1 : 0; + data.append(&b, 1); + XDebug(s_libName.c_str(),DebugAll,"::encodeBoolean('%s') - encoded boolean value into %u bytes",String::boolText(val),data.length()); + return data; +} + +DataBlock ASNLib::encodeInteger(u_int64_t intVal, bool tagCheck) +{ + /** + * ASN.1 integer ::= 0x02 asnlength byte {byte}* + */ + DataBlock data; + uint8_t tag = INTEGER; + + // 9 consecutive ones or zeros are not allowed at the beginning of an integer + int size = sizeof(u_int64_t); + uint16_t msb = intVal >> ((size - 1) * 8 - 1); + + while (((msb & 0x1FF) == 0 || (msb & 0x1FF) == 0xFF) && (size - 1 >= 1)) { + size--; + msb = intVal >> ((size - 1) * 8 - 1); + } + if (size == 0) + return data; + + DataBlock contents; + while(size) { + uint8_t byte = intVal >> ((size - 1) * 8); + contents.append(&byte, 1); + size--; + } + + if (contents.length() == 0) + return data; + if (tagCheck) { + data.append(&tag, 1); + DataBlock len = buildLength(contents); + data.append(len); + } + data.append(contents); + XDebug(s_libName.c_str(),DebugAll,"::encodeInteger('"FMT64"') - encoded into %u bytes",intVal,data.length()); + return data; +} + +DataBlock ASNLib::encodeBitString(String val, bool tagCheck) +{ + /** + * ASN.1 bit string ::= 0x03 asnlength unused {byte}* + */ + DataBlock data; + uint8_t tag = BIT_STRING; + DataBlock contents; + + int l = val.length(); + uint8_t trail = 8 - l % 8; + for (int i = 0; i < trail; i++) + val += "0"; + contents.append(&trail, 1); + + for (unsigned int i = 0; i < val.length(); i += 8) { + uint8_t hex = val.substr(i, 8).toInteger(0,2); + contents.append(&hex, 1); + } + + if (tagCheck) { + data.append(&tag,1); + DataBlock len = buildLength(contents); + data.append(len); + } + data.append(contents); + XDebug(s_libName.c_str(),DebugAll,"::encodeBitString('%s') - encoded bit string into %u bytes",val.c_str(),data.length()); + return data; +} + +DataBlock ASNLib::encodeOctetString(OctetString strVal, bool tagCheck) +{ + /** + * ASN.1 octet string ::= 0x04 asnlength byte {byte}* + */ + DataBlock data; + uint8_t tag = OCTET_STRING; + if (tagCheck) { + data.append(&tag, 1); + DataBlock len = buildLength(strVal); + data.append(len); + } + data.append(strVal); + XDebug(s_libName.c_str(),DebugAll,"ASNLib::encodeOctetString('%s') - encoded octet string into %u bytes", + strVal.toHexString().c_str(),data.length()); + return data; +} + +DataBlock ASNLib::encodeNull(bool tagCheck) +{ + /** + * ASN.1 null ::= 0x05 00 + */ + XDebug(s_libName.c_str(),DebugAll,"::encodeNull()"); + DataBlock data; + uint8_t tag = NULL_ID; + if (tagCheck) { + data.append(&tag, 1); + tag = 0; + data.append(&tag, 1); + } + return data; +} + +DataBlock ASNLib::encodeOID(ASNObjId obj, bool tagCheck) +{ + /** + * ASN.1 object id ::= 0x06 asnlength byte {byte}* + */ + DataBlock data; + uint8_t tag = OBJECT_ID; + + DataBlock cont = obj.getIds(); + DataBlock contents; + + if (cont.length() == 0) + return data; + + if (cont[0] == 1 && cont[1] == 3) { + cont.cut(-2); + uint8_t first = 0x2b; + contents.append(&first, 1); + } + + contents.append(cont); + if (tagCheck) { + data.append(&tag,1); + DataBlock len = buildLength(contents); + data.append(len); + } + data.append(contents); + XDebug(s_libName.c_str(),DebugAll,"::encodeOID('%s') - encoded object ID into %u bytes",obj.toString().c_str(),data.length()); + return data; +} + +DataBlock ASNLib::encodeReal(float val, bool tagCheck) +{ + Debug(s_libName.c_str(),DebugInfo,"::encodeReal() - STUB: encoding for real values not implemented"); + DataBlock data; + return data; +} + +DataBlock ASNLib::encodeString(String str, int type, bool tagCheck) +{ + DataBlock data; + uint8_t tag = type; + + DataBlock contents; + if (type == NUMERIC_STR || + type == PRINTABLE_STR || + type == IA5_STR || + type == VISIBLE_STR ) + contents.append(str); + + if (contents.length() == 0) + return data; + + if (tagCheck) { + data.append(&tag, 1); + DataBlock len = buildLength(contents); + data.append(len); + } + data.append(contents); + XDebug(s_libName.c_str(),DebugAll,"::encodeString() - encoded string into %u bytes",data.length()); + return data; +} + +DataBlock ASNLib::encodeUtf8(String str, bool tagCheck) +{ + DDebug(s_libName.c_str(),DebugAll,"::encodeUtf8()"); + DataBlock data; + uint8_t tag = UTF8_STR; + DataBlock contents; + contents.append(str); + if (tagCheck) { + data.append(&tag, 1); + DataBlock len = buildLength(contents); + data.append(len); + } + data.append(contents); + XDebug(s_libName.c_str(),DebugAll,"::encodeString() - encoded UTF8 string into %u bytes",data.length()); + return data; +} + +DataBlock ASNLib::encodeGenTime(unsigned int time, unsigned int fractions, bool tagCheck) +{ + DataBlock data; + uint8_t tag = GENERALIZED_TIME; + + int year; + unsigned int month, day, hours, minutes, seconds; + if (!Time::toDateTime(time, year, month, day, hours, minutes, seconds)) + return data; + String dateTime = ""; + dateTime += year; + (month < 10) ? dateTime += 0 : ""; + dateTime += month; + (day < 10) ? dateTime += 0 : ""; + dateTime += day; + (hours < 10) ? dateTime += 0 : ""; + dateTime += hours; + (minutes < 10) ? dateTime += 0 : ""; + dateTime += minutes; + (seconds < 10) ? dateTime += 0 : ""; + dateTime += seconds; + if (fractions != 0) { + dateTime += "."; + dateTime += fractions; + } + dateTime += 'Z'; + DataBlock contents; + contents.append(dateTime); + if (tagCheck) { + data.append(&tag, 1); + DataBlock len = buildLength(contents); + data.append(len); + } + data.append(contents); + XDebug(s_libName.c_str(),DebugAll,"::encodeGenTime(time='%u', fractions='%u') - encoded time value into %u bytes",time,fractions,data.length()); + return data; +} + +DataBlock ASNLib::encodeUTCTime(unsigned int time, bool tagCheck) +{ + DataBlock data; + uint8_t tag = UTC_TIME; + + int year; + unsigned int month, day, hours, minutes, seconds; + if (!Time::toDateTime(time, year, month, day, hours, minutes, seconds)) + return data; + String dateTime = ""; + (year % 100 < 10) ? dateTime += 0 : ""; + dateTime += (year % 100); + (month < 10) ? dateTime += 0 : ""; + dateTime += month; + (day < 10) ? dateTime += 0 : ""; + dateTime += day; + (hours < 10) ? dateTime += 0 : ""; + dateTime += hours; + (minutes < 10) ? dateTime += 0 : ""; + dateTime += minutes; + (seconds < 10) ? dateTime += 0 : ""; + dateTime += seconds; + + dateTime += 'Z'; + + DataBlock contents; + contents.append(dateTime); + if (tagCheck) { + data.append(&tag, 1); + DataBlock len = buildLength(contents); + data.append(len); + } + data.append(contents); + XDebug(s_libName.c_str(),DebugAll,"::encodeUTCTime(time='%u') - encoded time value into %u bytes",time,data.length()); + return data; +} + +DataBlock ASNLib::encodeAny(DataBlock data, bool tagCheck) +{ + XDebug(s_libName.c_str(),DebugAll,"::encodeAny()"); + DataBlock db; + db.append(data); + return db; +} + +int ASNLib::encodeSequence(DataBlock& data, bool tagCheck) +{ + DataBlock len; + if (tagCheck) { + len = buildLength(data); + data.insert(len); + DataBlock db; + u_int8_t tag = SEQUENCE; + db.append(&tag, 1); + data.insert(db); + } + XDebug(s_libName.c_str(),DebugAll,"::encodeSequence() - added sequence tag and length for a block of %d bytes",data.length()); + return len.length(); +} + +int ASNLib::encodeSet(DataBlock& data, bool tagCheck) +{ + DDebug(s_libName.c_str(),DebugAll,"::encodeSet()"); + DataBlock len; + if (tagCheck) { + len = buildLength(data); + data.insert(len); + DataBlock db; + u_int8_t tag = SET; + db.append(&tag, 1); + data.insert(db); + } + XDebug(s_libName.c_str(),DebugAll,"::encodeSet() - added set tag and length for a block of %d bytes",data.length()); + return len.length(); +} + + +/** + * ASNObjId + */ +ASNObjId::ASNObjId() +{ +} + +ASNObjId::ASNObjId(const String& val) + : m_value(val) +{ + DDebug(s_libName.c_str(),DebugAll,"ASNObjId('%s') created",val.c_str()); +} + +ASNObjId::ASNObjId(const String& name, const String& val) + : m_value(val), m_name(name) +{ + DDebug(s_libName.c_str(),DebugAll,"ASNObjId('%s', '%s') created",name.c_str(),val.c_str()); +} + +ASNObjId::ASNObjId(AsnMib* mib) +{ + DDebug(s_libName.c_str(),DebugAll,"ASNObjId() created from AsnMib [%p]",mib); + if (mib) { + m_name = mib->getName(); + m_value = mib->getOID(); + } +} + +ASNObjId::~ASNObjId() +{ + m_ids.clear(); +} + +ASNObjId& ASNObjId::operator=(const String& val) +{ + m_value = val; + return *this; +} + +ASNObjId& ASNObjId::operator=(const char* val) +{ + m_value.assign(val); + return *this; +} + +void ASNObjId::toDataBlock() +{ + DDebug(s_libName.c_str(),DebugAll,"ASNObjId::toDataBlock() '%s'", m_value.c_str()); + m_ids.clear(); + ObjList* list = m_value.split('.',false); + if (list) { + for (ObjList* o = list->skipNull(); o; o = o->skipNext()) { + String* s = static_cast(o->get()); + int val = s->toInteger(); + if (val < 128) + m_ids.append(&val, 1); + else { + DataBlock db; + int size = sizeof(int); + uint8_t v = val; + v = v & 0x7f; + db.append(&v,1); + size--; + val = val >> 7; + while (val != 0) { + v = val; + v = v & 0x7f; + v = v | 0x80; + DataBlock tmp; + tmp.append(&v,1); + db.insert(tmp); + size--; + val = val >> 7; + } + m_ids.append(db); + } + } + TelEngine::destruct(list); + } +} + +DataBlock ASNObjId::getIds() +{ + toDataBlock(); + return m_ids; +} + +/** + * AsnMib + */ +TokenDict AsnMib::s_access[] = { + {"accessible-for-notify", AsnMib::accessibleForNotify}, + {"read-only", AsnMib::readOnly}, + {"read-write", AsnMib::readWrite}, + {"read-create", AsnMib::readCreate}, + {0,0} +}; + +AsnMib::AsnMib(NamedList* params) +{ + if (!params) + return; + m_index = 0; + m_oid = *params; + m_name = params->getValue("name",""); + m_access = params->getValue("access",""); + m_accessVal = lookup(m_access,s_access,0); + m_type = params->getValue("type",""); + m_revision = params->getValue("revision",""); + XDebug(s_libName.c_str(),DebugAll,"new AsnMib created with oid : '%s', access : '%s', type : '%s'", + m_oid.c_str(),m_access.c_str(),m_type.c_str()); + TelEngine::destruct(params); +} + +int AsnMib::compareTo(AsnMib* mib) +{ + if (!mib) + return 1; + DDebug(s_libName,DebugInfo,"AsnMib::compareTo('%s'='%s' [%p]) this=%s[%s] [%p]", + mib->getName().c_str(),mib->toString().c_str(),mib,getName().c_str(),toString().c_str(),this); + + // they're equal + if (toString() == mib->toString()) + return 0; + + ObjList* myIDs = toString().split('.',false); + ObjList* mibIDs = mib->toString().split('.',false); + + ObjList* o1 = myIDs->skipNull(); + ObjList* o2 = mibIDs->skipNull(); + while (o1 && o2) { + String* str1 = static_cast(o1->get()); + o1 = o1->skipNext(); + String* str2 = static_cast(o2->get()); + o2 = o2->skipNext(); + int diff = str1->toInteger() - str2->toInteger(); + if (diff == 0) + continue; + if (diff > 0) { + TelEngine::destruct(myIDs); + TelEngine::destruct(mibIDs); + return 1; + } + if (diff < 0) { + TelEngine::destruct(myIDs); + TelEngine::destruct(mibIDs); + return -1; + } + } + + int retValue = 0; + if (!o1) + retValue = -1; + else if (!o2) + retValue = 1; + TelEngine::destruct(myIDs); + TelEngine::destruct(mibIDs); + return retValue; +} + +/** + * AsnMibTree + */ +AsnMibTree::AsnMibTree(const String& fileName) +{ + DDebug(s_libName.c_str(),DebugAll,"AsnMibTree object created from %s", fileName.c_str()); + m_treeConf = fileName; + if(!m_treeConf.load()) + Debug(s_libName.c_str(),DebugWarn,"Failed to load MIB tree"); + else + buildTree(); +} + +AsnMibTree::~AsnMibTree() +{ + m_mibs.clear(); +} + +void AsnMibTree::buildTree() +{ + for (unsigned int i = 0; i < m_treeConf.sections(); i++) { + AsnMib* mib = new AsnMib(m_treeConf.getSection(i)); + m_mibs.append(mib); + } +} + +String AsnMibTree::findRevision(const String& name) +{ + AsnMib* mib = find(name); + if (!mib) + return ""; + String revision = ""; + while (revision.null()) { + ASNObjId parentID = mib->getParent(); + AsnMib* parent = find(parentID); + if (!parent) + return revision; + revision = parent->getRevision(); + mib = parent; + } + return revision; +} + +AsnMib* AsnMibTree::find(const String& name) +{ + DDebug(s_libName.c_str(),DebugAll,"AsnMibTree::find('%s')",name.c_str()); + const ObjList *n = m_mibs.skipNull(); + AsnMib* mib = 0; + while (n) { + mib = static_cast(n->get()); + if (name == mib->getName()) + break; + n = n->skipNext(); + mib = 0; + } + return mib; +} + +AsnMib* AsnMibTree::find(const ASNObjId& id) +{ + DDebug(s_libName.c_str(),DebugAll,"AsnMibTree::find('%s')",id.toString().c_str()); + + String value = id.toString(); + int pos = 0; + int index = 0; + AsnMib* searched = 0; + unsigned int cycles = 0; + while (cycles < 2) { + ObjList* n = m_mibs.find(value); + searched = n ? static_cast(n->get()) : 0; + if (searched) { + searched->setIndex(index); + return searched; + } + pos = value.rfind('.'); + if (pos < 0) + return 0; + index = value.substr(pos + 1).toInteger(); + value = value.substr(0,pos); + cycles++; + } + return searched; +} + +AsnMib* AsnMibTree::findNext(const ASNObjId& id) +{ + DDebug(s_libName.c_str(),DebugAll,"AsnMibTree::findNext('%s')",id.toString().c_str()); + AsnMib* searched = static_cast(m_mibs[id.toString()]); + if (searched) { + if (searched->getAccessValue() > AsnMib::accessibleForNotify) { + DDebug(s_libName.c_str(),DebugInfo,"AsnMibTree::findNext('%s') - found an exact match to be '%s'", + id.toString().c_str(), searched->toString().c_str()); + return searched; + } + } + String value = id.toString(); + int pos = 0; + int index = 0; + while (true) { + ObjList* n = m_mibs.find(value); + searched = n ? static_cast(n->get()) : 0; + if (searched) { + if (id.toString() == searched->getOID() || id.toString() == searched->toString()) { + ObjList* aux = n->skipNext(); + if (!aux) + return 0; + while (aux) { + AsnMib* mib = static_cast(aux->get()); + if (mib && mib->getAccessValue() > AsnMib::accessibleForNotify) + return mib; + aux = aux->skipNext(); + } + } + else { + searched->setIndex(index + 1); + return searched; + } + } + pos = value.rfind('.'); + if (pos < 0) + return 0; + index = value.substr(pos + 1).toInteger(); + value = value.substr(0,pos); + } + return 0; +} + +int AsnMibTree::getAccess(const ASNObjId& id) +{ + DDebug(s_libName.c_str(),DebugAll,"AsnMibTree::getAccess('%s')",id.toString().c_str()); + AsnMib* mib = find(id); + if (!mib) + return 0; + return mib->getAccessValue(); +} + + diff --git a/libs/yasn/yateasn.h b/libs/yasn/yateasn.h new file mode 100644 index 00000000..46a52b84 --- /dev/null +++ b/libs/yasn/yateasn.h @@ -0,0 +1,938 @@ +/** + * yateasn.h + * This file is part of the YATE Project http://YATE.null.ro + * + * ASN.1 Library + * + * Yet Another Telephony Engine - a fully featured software PBX and IVR + * Copyright (C) 2004-2010 Null Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __YATEASN_H +#define __YATEASN_H + +#include + +#ifdef _WINDOWS + +#ifdef LIBYASN_EXPORTS +#define YASN_API __declspec(dllexport) +#else +#ifndef LIBYASN_STATIC +#define YASN_API __declspec(dllimport) +#endif +#endif + +#endif /* _WINDOWS */ + +#ifndef YASN_API +#define YASN_API +#endif + +namespace TelEngine { + +#define ASN_LONG_LENGTH 0x80 +#define ASN_BIT8 0x80 +#define ASN_EXTENSION_ID 31 +#define IS_EXTENSION_ID(byte) (((byte) & ASN_EXTENSION_ID) == ASN_EXTENSION_ID) + +class AsnObject; +class AsnValue; +class AsnMibTree; +class ASNObjId; +class ASNLib; +class ASNError; + +/** + * Helper class for operations with octet strings. Helps with conversions from String to/from DataBlock + * @short Helper class for operations with octet strings + */ +class OctetString : public DataBlock +{ +public: + /** + * Get the String contained in this buffer + * @return String containing the internal data + */ + inline String getString() + { + String str((const char*)data(),length()); + return str; + } + inline DataBlock& operator=(const String& value) + { + clear(); + append(value); + return *this; + } + inline DataBlock& operator=(const DataBlock& value) + { + clear(); + append(value); + return *this; + } + /** + * Get the content of the buffer in form of a hexified string + * @return Hexified string + */ + inline const String toHexString() const + { + String str; + str = str.hexify(data(),length()); + return str; + } + /** + * Builed this DataBlock from a hexified string + * @return The DataBlock built from the given hexified string + */ + inline DataBlock& fromHexString(const String& value) + { + unHexify(value,value.length()); + return *this; + } +}; + +/** + * Abstract class implemented by all ASN.1 type objects + * @short Base Class for ASN.1 objects + */ +class YASN_API AsnObject : public GenObject { + YCLASS(AsnObject, GenObject) +public: + /** + * Constructor + */ + inline AsnObject() + {} + /** + * Constructor + * @param data Data from which the object is built + * @param len Length of the given data + */ + AsnObject(void* data, int len) + {} + /** + * Destructor + */ + virtual inline ~AsnObject() + {} + + /** + * Function to decode the parameters of this object from given data + * @param data DataBlock from which the object is decoded + */ + virtual int decode(DataBlock& data) = 0; + + /** + * Function to encode this object into a datablock + * @param data The DataBlock in which the object should be encoded + */ + virtual int encode(DataBlock& data) = 0; + + /** + * Function for obtaining this object's data + * @param params NamedList in which this object's data should be put + */ + virtual void getParams(NamedList* params) = 0; + + /** + * Function for setting this object's data + * @param params NamedList containing the values to which this object's data should be set + */ + virtual void setParams(NamedList* params) = 0; +}; + +/** + * Class wrapper for different types of ASN.1 values + * @short An ASN.1 value + */ +class YASN_API AsnValue : public GenObject { + YCLASS(AsnValue, GenObject) +public: + /** + * Type of value + */ + enum ValType { + INTEGER = 1, + STRING = 2, + OBJECT_ID = 3, + IPADDRESS = 4, + COUNTER = 5, + TIMETICKS = 6, + ARBITRARY = 7, + BIG_COUNTER = 8, + UNSIGNED_INTEGER = 9 + }; + + /** + * Constructor + */ + inline AsnValue() + : m_type(0), m_data("") + {} + + /** + * Constructor + * @param value Object value + * @param type AsnValue type, default is String + */ + inline AsnValue(const String& value, int type = STRING) + : m_type(type), m_data(value) + { } + + /** + * Destructor + */ + virtual inline ~AsnValue() + {} + + /** + * Get the value in the form of a string + * @return String containing the internal data + */ + inline String getValue() + { return m_data;} + + /** + * Get the type of the data so that we know how to interpret it + * @return The type of the data + */ + inline int type() + { return m_type;} + + /** + * Assign operator + */ + inline AsnValue& operator=( AsnValue* val) + { + if (!val) + return *this; + m_data = val->getValue(); + m_type = val->type(); + return *this; + } + + /** + * Assign operator + */ + inline AsnValue& operator=( AsnValue val) + { + m_data = val.getValue(); + m_type = val.type(); + return *this; + } + + /** + * Set data + * @param data The data to which the internal data will be set + */ + inline void setValue(const String& data) + { m_data.clear();m_data = data; } + + /** + * Set data type + * @param type The type assigned + */ + inline void setType(int type) + { m_type = type; } + +private: + int m_type; + String m_data; +}; + +/** + * Class describing an ASN.1 OID + */ +class YASN_API AsnMib : public GenObject { + YCLASS(AsnMib, GenObject) +public: + /** + * Access levels + */ + enum Access { + notAccessible = 0, + accessibleForNotify = 1, + readOnly = 2, + readWrite = 3, + readCreate = 4 + }; + /** + * Constructor + */ + inline AsnMib() + : m_access(""), m_accessVal(0), m_index(0) + {} + + /** + * Constructor + * @param params NamedList containing data for building this object, it should contain name, access level, value type + */ + AsnMib(NamedList* params); + + /** + * Destructor + */ + inline ~AsnMib() + {} + + /** + * Get OID access level in string form + * @return String containing the access level for this OID. It's one of the following values : not-accessible, read-only, read-write, + read-create, accessible-for-notify. + */ + inline String& getAccess() + { return m_access;} + + /** + * Get OID access level + * @return String containing the access level for this OID. It's one of the following values : not-accessible, read-only, read-write, + read-create, accessible-for-notify. + */ + inline int getAccessValue() + { return m_accessVal;} + + /** + * Get the name of this OID + * @return Name of the OID + */ + inline String& getName() + { return m_name;} + + /** + * Get the oid + * @return The OID + */ + inline String getOID() + { String str = "."; + str += m_index; + return m_oid + str;} + + /** + * Get the type of the value of this OID + * @return String containing the type of value + */ + inline String& getType() + { return m_type;} + + /** + * Get the revision of this OID + * @return String containing the revision string + */ + inline String& getRevision() + { return m_revision; } + + /** + * Get the string representation of this OID + * @return String representation of this OID + */ + inline const String& toString() const + { return m_oid;} + + /** + * Set the index of an OID in case this OID is part of a table. + * @param ind Given index + */ + inline void setIndex(unsigned int ind) + { m_index = ind;} + + /** + * Obtain the index of this OID + * @return This OID's index in the OID table + */ + inline unsigned int index() + { return m_index;} + + /** + * Compare this object ID with another + * @param mib The object ID with which this object should be compared + * @return 0 if they're equal, -1 if this object is less lexicographically then the given parameter, 1 if it's greater + */ + int compareTo(AsnMib* mib); + + /** + * Get the parent object ID of this object + * @return String version of the parent ID + */ + inline String getParent() + { + int pos = m_oid.rfind('.'); + return m_oid.substr(0,pos); + } + +private: + String m_name; + String m_oid; + String m_access; + int m_accessVal; + String m_type; + String m_revision; + int size; + int maxVal; + int minVal; + unsigned int m_index; + + static TokenDict s_access[]; +}; + +/** + * Tree of OIDs. + */ +class YASN_API AsnMibTree : public GenObject { + YCLASS(AsnMibTree, GenObject) +public: + /** + * Constructor + */ + inline AsnMibTree() + {} + + /** + * Constructor + * @param fileName File from which the tree is to be built + */ + AsnMibTree(const String& fileName); + + /** + * Destructor + */ + virtual ~AsnMibTree(); + + /** + * Find a MIB object given the object id + * @param id The object id + * @return A pointer to the MIB with the searched object id, 0 if not found + */ + AsnMib* find(const ASNObjId& id); + + /** + * Find a MIB given the MIB name + * @param name The name of the MIB object + * @return A pointer to the MIB with the searched object id, 0 if not found + */ + AsnMib* find(const String& name); + + /** + * Find the next MIB object in the tree + * @param id Object id of the current MIB object + * @return A pointer to the next MIB object in the tree, 0 if there is no next + */ + AsnMib* findNext(const ASNObjId& id); + + /** + * Get access level for the given object id + * @param oid Object id for which the access level is required + * @return Enum value describing the access level required for this object + */ + int getAccess(const ASNObjId& oid); + + /** + * Build the tree of MIB objects + */ + void buildTree(); + + /** + * Find the module revision of which this OID is part of + * @param name Name of the OID + * @return String value of the module revision + */ + String findRevision(const String& name); + +private: + Configuration m_treeConf; + ObjList m_mibs; +}; + +/** + * Class for holding only an OID + */ +class YASN_API ASNObjId : public GenObject { + YCLASS(ASNObjId, GenObject) +public: + /** + * Constructor + */ + ASNObjId(); + + /** + * Constructor + * @param val OID value in string format + */ + ASNObjId(const String& val); + + /** + * Constructor + * @param name Name of the OID + * @param val OID value in string format + */ + ASNObjId(const String& name, const String& val); + + /** + * Constructor + * @param mib Mib used for creating this OID + */ + ASNObjId(AsnMib* mib); + + /** + * Destructor + */ + ~ASNObjId(); + + /** + * Assign operator from a string value + */ + ASNObjId& operator=(const String& val); + + /** + * Assign operator from a const char* value + */ + ASNObjId& operator=(const char* val); + + /** + * Transform the value of this OID from a string value to a sequence of numbers + */ + void toDataBlock(); + + /** + * Get the sequence form of the OID + * @return Datablock sequence of ids + */ + DataBlock getIds(); + + /** + * String representation of the OID + */ + inline const String& toString() const + { return m_value; } + + /** + * Get the name of the OID + * @return String representation of the name + */ + inline const String& getName() const + { return m_name; } + + /** + * Set the OID value + * @param value OID value + */ + inline void setValue(const String& value) + { m_value = value; toDataBlock();} + +private: + String m_value; + String m_name; + DataBlock m_ids; +}; + +/** + * Class ASNLib + * @short Class containing functions for decoding/encoding ASN.1 basic data types + */ +class YASN_API ASNLib { +public: + /** + * ASN.1 Type tags + */ + enum TypeTag { + UNIVERSAL = 0x00, + BOOLEAN = 0x01, + INTEGER = 0x02, + BIT_STRING = 0x03, + OCTET_STRING = 0x04, + NULL_ID = 0x05, + OBJECT_ID = 0x06, + REAL = 0x09, //not implemented + UTF8_STR = 0x0c, + SEQUENCE = 0x30, + SET = 0x31, + NUMERIC_STR = 0x12, + PRINTABLE_STR = 0x13, + IA5_STR = 0x16, + UTC_TIME = 0x17, + GENERALIZED_TIME = 0x18, + VISIBLE_STR = 0x1a, + GENERAL_STR = 0x1b, // not implemented + UNIVERSAL_STR = 0x1c, // not implemented + CHARACTER_STR = 0x1d, // not implemented + BMP_STR = 0x1e, // not implemented + CHOICE = 0x1f, // does not have a value + DEFINED = 0x2d + }; + // values not implemented + // 10 ENUMERATED + // 11 EMBEDDED PDV + // 13 RELATIVE-OID + // 20 TeletexString, T61String + // 21 VideotexString + // 25 GraphicString + // 27 GeneralString + // 28 UniversalString + // 29 CHARACTER STRING + // 30 BMPString + /** + * Error types + */ + enum Error { + InvalidLengthOrTag = -1, + ConstraintBreakError = -2, + ParseError, + InvalidContentsError + }; + + /** + * Constructor + */ + ASNLib(); + + /** + * Destructor + */ + ~ASNLib(); + + /** + * Decode the length of the block data containing the ASN.1 type data + * @param data Input block from which to extract the length + * @return The length of the data block containing data, -1 if it couldn't be decoded + */ + static int decodeLength(DataBlock& data); + + /** + * Decode a boolean value from the encoded data + * @param data Input block from which the boolean value should be extracted + * @param val Pointer to a boolean to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for boolean (0x01) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the boolean value could not be decoded + */ + static int decodeBoolean(DataBlock& data, bool* val, bool tagCheck); + + /** + * Decode an integer value from the encoded data + * @param data Input block from which the integer value should be extracted + * @param intVal Integer to be filled with the decoded value + * @param bytes Width of the decoded integer field + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x02) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeInteger(DataBlock& data, u_int64_t& intVal, unsigned int bytes, bool tagCheck); + + /** + * Decode an unsigned integer value from the encoded data - helper function for casting from u_int64_t to u_int8_t in case of size constraints + * @param data Input block from which the integer value should be extracted + * @param intVal Integer to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x02) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeUINT8(DataBlock& data, u_int8_t* intVal, bool tagCheck); + + /** + * Decode an unsigned integer value from the encoded data - helper function for casting from u_int64_t to u_int16_t in case of size constraints + * @param data Input block from which the integer value should be extracted + * @param intVal Integer to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x02) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeUINT16(DataBlock& data, u_int16_t* intVal, bool tagCheck); + + /** + * Decode an unsigned integer value from the encoded data - helper function for casting from u_int64_t to u_int32_t in case of size constraints + * @param data Input block from which the integer value should be extracted + * @param intVal Integer to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x02) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeUINT32(DataBlock& data, u_int32_t* intVal, bool tagCheck); + + /** + * Decode an unsigned integer value from the encoded data - helper function for casting in case of size constraints + * @param data Input block from which the integer value should be extracted + * @param intVal Integer to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x02) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeUINT64(DataBlock& data, u_int64_t* intVal, bool tagCheck); + + /** + * Decode an integer value from the encoded data - helper function for casting from u_int64_t to int8_t in case of size constraints + * @param data Input block from which the integer value should be extracted + * @param intVal Integer to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x02) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeINT8(DataBlock& data, int8_t* intVal, bool tagCheck); + + /** + * Decode an integer value from the encoded data - helper function for casting from u_int64_t to int16_t in case of size constraints + * @param data Input block from which the integer value should be extracted + * @param intVal Integer to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x02) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeINT16(DataBlock& data, int16_t* intVal, bool tagCheck); + + /** + * Decode an integer value from the encoded data - helper function for casting from u_int64_t to int32_t in case of size constraints + * @param data Input block from which the integer value should be extracted + * @param intVal Integer to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x02) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeINT32(DataBlock& data, int32_t* intVal, bool tagCheck); + + /** + * Decode an integer value from the encoded data - helper function for casting in case of size constraints + * @param data Input block from which the integer value should be extracted + * @param intVal Integer to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x02) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeINT64(DataBlock& data, int64_t* intVal, bool tagCheck); + + /** + * Decode a bitstring value from the encoded data + * @param data Input block from which the bitstring value should be extracted + * @param val String to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x03) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeBitString(DataBlock& data, String* val, bool tagCheck); + + /** + * Decode a string value from the encoded data + * @param data Input block from which the octet string value should be extracted + * @param strVal String to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x04) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeOctetString(DataBlock& data, OctetString* strVal, bool tagCheck); + + /** + * Decode a null value from the encoded data + * @param data Input block from which the null value should be extracted + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x05) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeNull(DataBlock& data, bool tagCheck); + + /** + * Decode an object id value from the encoded data + * @param data Input block from which the OID value should be extracted + * @param obj ASNObjId to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x06) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeOID(DataBlock& data, ASNObjId* obj, bool tagCheck); + + /** + * Decode a real value from the encoded data - not implemented + * @param data Input block from which the real value should be extracted + * @param realVal Float to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag for integer (0x09) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeReal(DataBlock& data, float* realVal, bool tagCheck); + + /** + * Decode other types of ASN.1 strings from the encoded data (NumericString, PrintableString, VisibleString, IA5String) + * @param data Input block from which the string value should be extracted + * @param str String to be filled with the decoded value + * @param type Integer to be filled with the value indicating which type of string has been decoded + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeString(DataBlock& data, String* str, int* type, bool tagCheck); + + /** + * Decode an UTF8 string from the encoded data + * @param data Input block from which the string value should be extracted + * @param str String to be filled with the decoded value + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag (0x0c) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeUtf8(DataBlock& data, String* str, bool tagCheck); + + /** + * Decode a GeneralizedTime value from the encoded data + * @param data Input block from which the value should be extracted + * @param time Integer to be filled with time in seconds since epoch + * @param fractions Integer to be filled with fractions of a second + * @param utc Flag indicating if the decode time value represent local time or UTC time + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag (0x18) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeGenTime(DataBlock& data, unsigned int* time, unsigned int* fractions, bool* utc, bool tagCheck); + + /** + * Decode a UTC time value from the encoded data + * @param data Input block from which the value should be extracted + * @param time Integer to be filled with time in seconds since epoch + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 tag (0x17) should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeUTCTime(DataBlock& data, unsigned int* time, bool tagCheck); + + /** + * Decode a block of arbitrary data + * @param data Input block from which the value should be extracted + * @param val DataBlock in which the data shoulb be copied + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 should be verified + * @return Length of data consumed from the input data it the decoding was successful, -1 if the integer value could not be decoded + */ + static int decodeAny(DataBlock data, DataBlock* val, bool tagCheck); + + /** + * Decode the header of an ASN.1 sequence ( decodes the tag and the length of the sequence) + * @param data Input block from which the header should be extracted + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 (0x30) should be verified + * @return Length of data consumed from the input data it the decoding was succesful, -1 if the integer value could not be decoded + */ + static int decodeSequence(DataBlock& data, bool tagCheck); + + /** + * Decode the header of an ASN.1 set ( decodes the tag and the length of the sequence) + * @param data Input block from which the header should be extracted + * @param tagCheck Flag for indicating if in the process of decoding the value the presence of the ASN.1 (0x31) should be verified + * @return Length of data consumed from the input data it the decoding was succesful, -1 if the integer value could not be decoded + */ + static int decodeSet(DataBlock& data, bool tagCheck); + + /** + * Encode the length of the given data + * @param data The data for which the length should be encoded + * @return The data block which now contains the length encoding + */ + static DataBlock buildLength(DataBlock& data); + + /** + * Encode the given boolean value + * @param val The boolean value to encode + * @param tagCheck Flag to specify if the boolean type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeBoolean(bool val, bool tagCheck); + + /** + * Encode the given integer value + * @param intVal The integer value to encode + * @param tagCheck Flag to specify if the integer type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeInteger(u_int64_t intVal, bool tagCheck); + + /** + * Encode the given octet string value + * @param strVal The octet string value to encode + * @param tagCheck Flag to specify if the octet string type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeOctetString(OctetString strVal, bool tagCheck); + + /** + * Encode a null value + * @param tagCheck Flag to specify if the null tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeNull(bool tagCheck); + + /** + * Encode the given bitstring value + * @param val The bitstring value to encode + * @param tagCheck Flag to specify if the type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeBitString(String val, bool tagCheck); + + /** + * Encode the given OID value + * @param obj The OID value to encode + * @param tagCheck Flag to specify if the type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeOID(ASNObjId obj, bool tagCheck); + + /** + * Encode the given real value - not implemented + * @param val The real value to encode + * @param tagCheck Flag to specify if the type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeReal(float val, bool tagCheck); + + /** + * Encode the given string value to NumericString, PrintableString, IA5String, VisibleString + * @param str The string value to encode + * @param type The type of the encoding + * @param tagCheck Flag to specify if the type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeString(String str, int type, bool tagCheck); + + /** + * Encode the UTF8 string value + * @param str The string value to encode + * @param tagCheck Flag to specify if the type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeUtf8(String str, bool tagCheck); + + /** + * Encode the given time value into a GeneralizedTime format + * @param time Time in seconds since epoch to encode + * @param fractions Fractions of a seconds to encode + * @param tagCheck Flag to specify if the type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeGenTime(unsigned int time, unsigned int fractions, bool tagCheck); + + /** + * Encode the given time value into an UTCTime format + * @param time Time in seconds since epoch to encode + * @param tagCheck Flag to specify if the type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeUTCTime(unsigned int time, bool tagCheck); + + /** + * Encode an arbitrary block a data + * @param data data + * @param tagCheck Flag to specify if the type tag should be inserted in the encoding + * @return The data block encoding of the value + */ + static DataBlock encodeAny(DataBlock data, bool tagCheck); + + /** + * Encode the header for a sequence + * @param data Sequence data for which the header is encoded + * @param tagCheck Flag to specify if the ype tag should be inserted in the encoding + * @return The length of the data block length encoding + */ + static int encodeSequence(DataBlock& data, bool tagCheck); + + /** + * Encode the header for a set + * @param data Sequence data for which the header is encoded + * @param tagCheck Flag to specify if the type tag should be inserted in the encoding + * @return The length of the data block length encoding + */ + static int encodeSet(DataBlock& data, bool tagCheck); +}; + +} + +#endif /* __YATEASN_H */ + +/* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/libs/yjabber/yatejabber.h b/libs/yjabber/yatejabber.h index 4e759a3e..19bf960d 100644 --- a/libs/yjabber/yatejabber.h +++ b/libs/yjabber/yatejabber.h @@ -2151,6 +2151,13 @@ public: JBClientStream* create(const String& account, const NamedList& params, const String& name = String::empty()); + /** + * Retrieve the list of streams of a given type + * @param list The destination list to set + * @param type Stream type + */ + virtual void getStreamList(RefPointer& list, int type); + protected: /** * Add a stream to one of the stream lists @@ -2172,13 +2179,6 @@ protected: */ virtual void stopStreamSets(bool waitTerminate = true); - /** - * Retrieve the list of streams of a given type - * @param list The destination list to set - * @param type Stream type - */ - virtual void getStreamList(RefPointer& list, int type); - JBStreamSetList* m_receive; // Streams receive list JBStreamSetList* m_process; // Streams process list }; diff --git a/libs/ymgcp/transaction.cpp b/libs/ymgcp/transaction.cpp index aa0325d8..bfb90343 100644 --- a/libs/ymgcp/transaction.cpp +++ b/libs/ymgcp/transaction.cpp @@ -394,6 +394,8 @@ MGCPEvent* MGCPTransaction::checkTimeout(u_int64_t time) } m_timeout = (state() == Initiated || state() == Trying); + if (m_timeout) + engine()->timeout(this); return terminate(); } diff --git a/libs/ymgcp/yatemgcp.h b/libs/ymgcp/yatemgcp.h index 4f559861..ac6d93b6 100644 --- a/libs/ymgcp/yatemgcp.h +++ b/libs/ymgcp/yatemgcp.h @@ -1014,6 +1014,13 @@ public: static inline int defaultPort(bool gateway) { return gateway ? 2427 : 2727; } + /** + * Handle a transaction that has timed out + * @param tr The transaction that has timed out + */ + virtual void timeout(MGCPTransaction* tr) + { } + /** * The list of commands defined in RFC 3435 */ diff --git a/libs/yrtp/session.cpp b/libs/yrtp/session.cpp index 3786cf0c..5f9fb371 100644 --- a/libs/yrtp/session.cpp +++ b/libs/yrtp/session.cpp @@ -184,6 +184,7 @@ void RTPReceiver::rtpData(const void* data, int len) Debug(DebugWarn,"RTP Received SSRC %08X but expecting %08X [%p]", ss,m_ssrc,this); } + m_wrongSSRC++; return; } // SSRC accepted, sync sequence and resync the timestamp offset @@ -196,6 +197,8 @@ void RTPReceiver::rtpData(const void* data, int len) // substraction with overflow int16_t ds = seq - m_seq; + if (ds != 1) + m_seqLost++; // check if we received duplicate or delayed packet // be much more tolerant when authenticating as we cannot resync if ((ds <= 0) || ((ds > SEQ_DESYNC_COUNT) && !secPtr)) { @@ -212,6 +215,7 @@ void RTPReceiver::rtpData(const void* data, int len) m_ts = ts - m_tsLast; m_seqCount = 0; m_warn = true; + m_syncLost++; // drop this packet, next packet will come in correctly return; } @@ -377,6 +381,15 @@ bool RTPReceiver::rtpCheckIntegrity(const unsigned char* data, int len, const vo : true; } +void RTPReceiver::stats(NamedList& stat) const +{ + if (m_session) + stat.setParam("remoteip",m_session->UDPSession::transport()->remoteAddr().host()); + stat.setParam("lostpkts",String(m_ioLostPkt)); + stat.setParam("synclost",String(m_syncLost)); + stat.setParam("wrongssrc",String(m_wrongSSRC)); + stat.setParam("seqslost",String(m_seqLost)); +} RTPSender::RTPSender(RTPSession* session, bool randomTs) : RTPBaseIO(session), m_evTime(0), m_padding(0) @@ -551,6 +564,9 @@ void RTPSender::rtpAddIntegrity(const unsigned char* data, int len, unsigned cha m_secure->rtpAddIntegrity(data,len,authData); } +void RTPSender::stats(NamedList& stat) const +{ +} UDPSession::UDPSession() : m_transport(0), m_timeoutTime(0), m_timeoutInterval(0) @@ -872,6 +888,15 @@ void RTPSession::setReports(int interval) m_reportTime = 0; } +void RTPSession::getStats(NamedList& stats) const +{ + if (m_send) + m_send->stats(stats); + if (m_recv) + m_recv->stats(stats); + stats.setParam("wrongsrc",String(m_wrongSrc)); +} + static void store32(unsigned char* buf, unsigned int& len, u_int32_t val) { buf[len++] = (unsigned char)(val >> 24); @@ -945,6 +970,11 @@ void RTPSession::sendRtcpBye() static_cast(m_transport)->rtcpData(buf,8); } +void RTPSession::incWrongSrc() +{ + Debug(DebugAll,"RTPSession::incWrongSrc() [%p]",this); + m_wrongSrc++; +} UDPTLSession::UDPTLSession(u_int16_t maxLen, u_int8_t maxSec) : m_rxSeq(0xffff), m_txSeq(0xffff), diff --git a/libs/yrtp/transport.cpp b/libs/yrtp/transport.cpp index 5042cd92..d19f1bbe 100644 --- a/libs/yrtp/transport.cpp +++ b/libs/yrtp/transport.cpp @@ -126,7 +126,7 @@ void RTPGroup::setMinSleep(int msec) RTPProcessor::RTPProcessor() - : m_group(0) + : m_wrongSrc(0), m_group(0) { DDebug(DebugAll,"RTPProcessor::RTPProcessor() [%p]",this); } @@ -218,6 +218,8 @@ void RTPTransport::timerTick(const Time& when) if (m_monitor) m_monitor->rtpData(buf,len); } + else + m_processor->incWrongSrc(); } m_rtpSock.timerTick(when); } diff --git a/libs/yrtp/yatertp.h b/libs/yrtp/yatertp.h index ff04a07f..e4d29ce3 100644 --- a/libs/yrtp/yatertp.h +++ b/libs/yrtp/yatertp.h @@ -105,6 +105,19 @@ public: */ virtual void getStats(String& stats) const; + /** + * Increase the counter for number of RTP packets received from a wrong source + */ + virtual inline void incWrongSrc() + { } + + /** + * Get the number of RTP packets that were received from a wrong source + * @return Number of RTP packets received from a wrong source + */ + inline unsigned int wrongSrc() + { return m_wrongSrc; } + protected: /** * Set a new RTP group for this processor @@ -118,6 +131,8 @@ protected: */ virtual void timerTick(const Time& when) = 0; + unsigned int m_wrongSrc; + private: RTPGroup* m_group; }; @@ -578,7 +593,8 @@ public: inline RTPReceiver(RTPSession* session = 0) : RTPBaseIO(session), m_ioLostPkt(0), m_dejitter(0), - m_seqSync(0), m_seqCount(0), m_warn(true) + m_seqSync(0), m_seqCount(0), m_warn(true), + m_seqLost(0), m_wrongSSRC(0), m_syncLost(0) { } /** @@ -662,6 +678,12 @@ public: */ virtual void rtpNewSSRC(u_int32_t newSsrc, bool marker); + /** + * Retrieve the statistical data from this receiver in a NamedList. Reset all the data. + * @param NamedList to populate with the values for different counters + */ + virtual void stats(NamedList& stat) const; + protected: /** * Method called periodically to finish lingering events @@ -706,6 +728,9 @@ private: u_int16_t m_seqSync; u_int16_t m_seqCount; bool m_warn; + unsigned int m_seqLost; + unsigned int m_wrongSSRC; + unsigned int m_syncLost; }; /** @@ -786,6 +811,12 @@ public: */ bool padding(int chunk); + /** + * Retrieve the statistical data from this receiver in a NamedList. Reset all the data. + * @param NamedList to populate with the values for different counters + */ + virtual void stats(NamedList& stat) const; + protected: /** * Method called periodically to send events and buffered data @@ -1219,6 +1250,17 @@ public: */ void setReports(int interval); + /** + * Put the collected statistical data + * @param stats NamedList to populate with the data + */ + virtual void getStats(NamedList& stats) const; + + /** + * Increase the counter for number of RTP packets received from a wrong source + */ + virtual void incWrongSrc(); + protected: /** * Method called periodically to push any asynchronous data or statistics diff --git a/libs/ysig/engine.cpp b/libs/ysig/engine.cpp index 1be375e0..7cbb2b61 100644 --- a/libs/ysig/engine.cpp +++ b/libs/ysig/engine.cpp @@ -129,10 +129,11 @@ void* SignallingFactory::buildInternal(const String& type, const NamedList* name SignallingComponent::SignallingComponent(const char* name, const NamedList* params) - : m_engine(0) + : m_engine(0), m_compType("unknown") { if (params) { name = params->getValue("debugname",name); + m_compType = params->getValue("type",m_compType); debugLevel(params->getIntValue("debuglevel",-1)); } DDebug(engine(),DebugAll,"Component '%s' created [%p]",name,this); @@ -237,6 +238,15 @@ unsigned long SignallingComponent::tickSleep(unsigned long usec) const return m_engine ? m_engine->tickSleep(usec) : 0; } +void SignallingNotifier::notify(NamedList& notifs) +{ + DDebug(DebugInfo,"SignallingNotifier::notify() [%p] stub",this); +} + +void SignallingNotifier::cleanup() +{ + DDebug(DebugInfo,"SignallingNotifier::cleanup() [%p] stub",this); +} static SignallingEngine* s_self = 0; @@ -376,6 +386,14 @@ bool SignallingEngine::remove(const String& name) return true; } +void SignallingEngine::notify(SignallingComponent* component, NamedList notifs) +{ + if (!(m_notifier && component)) + return; + Debug(this,DebugAll,"Engine [%p] sending notify from '%s' [%p]",this,component->toString().c_str(),component); + m_notifier->notify(notifs); +} + bool SignallingEngine::control(NamedList& params) { bool ok = false; diff --git a/libs/ysig/isup.cpp b/libs/ysig/isup.cpp index cd55e3dd..1ec3d8b5 100644 --- a/libs/ysig/isup.cpp +++ b/libs/ysig/isup.cpp @@ -3693,7 +3693,15 @@ void SS7ISUP::notify(SS7Layer3* link, int sls) if (!link) return; Lock mylock(this); - m_l3LinkUp = link->operational(-1); + // Ignore links not routing our remote point code + if ((unsigned int)-1 == link->getRoutePriority(m_type,m_remotePoint->pack(m_type))) + return; + bool linkTmp = m_l3LinkUp; + // Link is not operational + if (link->operational()) + m_l3LinkUp = true; + else + m_l3LinkUp = false; // Reset remote user part's availability state if supported // Force UPT re-send if (m_uptTimer.interval() && !m_l3LinkUp) { @@ -3705,6 +3713,13 @@ void SS7ISUP::notify(SS7Layer3* link, int sls) link,link->toString().safe(), (m_l3LinkUp ? "" : "not "),sls, (m_userPartAvail ? "" : "un")); + if (linkTmp != m_l3LinkUp) { + NamedList params(""); + params.addParam("type","trunk"); + params.addParam("operational",String::boolText(m_l3LinkUp)); + params.addParam("from",link->toString()); + engine()->notify(this,params); + } } SS7MSU* SS7ISUP::buildMSU(SS7MsgISUP::Type type, unsigned char sio, diff --git a/libs/ysig/layer3.cpp b/libs/ysig/layer3.cpp index 30deb52b..e0f5d44c 100644 --- a/libs/ysig/layer3.cpp +++ b/libs/ysig/layer3.cpp @@ -1174,6 +1174,16 @@ void SS7MTP3::notify(SS7Layer2* link) if (cnt) Debug(this,DebugNote,"Attempted to uninhibit/resume %u links [%p]",cnt,this); SS7Layer3::notify(link ? link->sls() : -1); + + NamedList notif(""); + notif.addParam("from", toString()); + notif.addParam("type","ss7-mtp3"); + notif.addParam("operational",String::boolText(operational())); + notif.addParam("active",String(m_active)); + notif.addParam("total",String(m_total)); + notif.addParam("link", link ? link->toString() : ""); + notif.addParam("linkup", link ? String::boolText(link->operational()) : ""); + engine()->notify(this,notif); } } diff --git a/libs/ysig/q931.cpp b/libs/ysig/q931.cpp index 96a8552c..3d39e2be 100644 --- a/libs/ysig/q931.cpp +++ b/libs/ysig/q931.cpp @@ -2570,7 +2570,15 @@ bool ISDNQ931::sendMessage(ISDNQ931Message* msg, u_int8_t tei, String* reason) void ISDNQ931::multipleFrameEstablished(u_int8_t tei, bool confirmation, bool timeout, ISDNLayer2* layer2) { l3Mutex().lock(); + bool q921Tmp = m_q921Up; m_q921Up = true; + if (m_q921Up != q921Tmp) { + NamedList p(""); + p.addParam("type","isdn-q921"); + p.addParam("operational",String::boolText(m_q921Up)); + p.addParam("from",m_q921->toString()); + engine()->notify(this,p); + } DDebug(this,DebugNote,"'Established' %s TEI %u", confirmation ? "confirmation" :"indication",tei); endReceiveSegment("Data link is up"); @@ -2590,7 +2598,15 @@ void ISDNQ931::multipleFrameEstablished(u_int8_t tei, bool confirmation, bool ti void ISDNQ931::multipleFrameReleased(u_int8_t tei, bool confirmation, bool timeout, ISDNLayer2* layer2) { Lock lockLayer(l3Mutex()); + bool q921Tmp = m_q921Up; m_q921Up = false; + if (m_q921Up != q921Tmp) { + NamedList p(""); + p.addParam("type","isdn-q921"); + p.addParam("operational",String::boolText(m_q921Up)); + p.addParam("from",m_q921->toString()); + engine()->notify(this,p); + } DDebug(this,DebugNote,"'Released' %s TEI %u. Timeout: %s", confirmation ? "confirmation" :"indication",tei,String::boolText(timeout)); endReceiveSegment("Data link is down"); diff --git a/libs/ysig/yatesig.h b/libs/ysig/yatesig.h index 293332cd..36ead9f3 100644 --- a/libs/ysig/yatesig.h +++ b/libs/ysig/yatesig.h @@ -51,6 +51,7 @@ namespace TelEngine { // Signalling classes class SignallingDumper; // A generic data dumper class SignallingDumpable; // A component that can dump data +class SignallingNotifier; // A signalling notifier class SignallingTimer; // A signalling timer class SignallingCounter; // A signalling counter class SignallingFactory; // A signalling component factory @@ -350,6 +351,30 @@ private: SignallingDumper* m_dumper; }; +/** + * Notifying class. Used to handle notifications. + * @short Notifier class + */ + +class YSIG_API SignallingNotifier +{ +public: + /** + * Destructor. + */ + inline ~SignallingNotifier() + { cleanup(); } + /** + * Handle the received notifications + * @param notifs Received notifications + */ + virtual void notify(NamedList& notifs); + /** + * Handle necessary clean up + */ + virtual void cleanup(); +}; + /** * Timer management class. Used to manage timeouts. The time is kept in miliseconds * @short A signalling timer @@ -659,6 +684,13 @@ public: inline int debugLevel(int level) { return (level >= 0) ? DebugEnabler::debugLevel(level) : DebugEnabler::debugLevel(); } + /** + * Return the type of this component + * @return A string version of the component type + */ + inline const String& componentType() const + { return m_compType; } + protected: /** * Constructor with a default empty component name @@ -711,6 +743,7 @@ protected: private: SignallingEngine* m_engine; String m_name; + String m_compType; }; /** @@ -799,6 +832,13 @@ public: */ bool find(const SignallingComponent* component); + /** + * Handle notifications from a SignallingComponent + * @param component The SignallingComponent from which the notifications were received + * @param notifs The notifications sent by this SignallingComponent + */ + void notify(SignallingComponent* component, NamedList notifs); + /** * Starts the worker thread that keeps components alive * @param name Static name of the thread @@ -813,6 +853,23 @@ public: */ void stop(); + /** + * Add to this engine a notifier object + * @param notifier The SignallingNotifier object to be added to the engine + */ + inline void setNotifier(SignallingNotifier* notifier) + { m_notifier = notifier; } + + /** + * Remove from this engine a notifier object + * @param notifier The SignallingNotifier object to be removed from the engine + */ + inline void removeNotifier(SignallingNotifier* notifier) + { + if (m_notifier == notifier) + m_notifier = 0; + } + /** * Return a pointer to the worker thread * @return Pointer to running worker thread or NULL @@ -863,6 +920,7 @@ protected: private: SignallingThreadPrivate* m_thread; + SignallingNotifier* m_notifier; unsigned long m_usecSleep; unsigned long m_tickSleep; }; @@ -7035,6 +7093,13 @@ public: inline unsigned int linksActive() const { return m_active; } + /** + * Get a list of the links held by this linkset + * @return A list containing the links + */ + inline const ObjList* links() const + { return &m_links; } + protected: /** * Detach all links and user. Destroys the object, disposes the memory diff --git a/libs/ysnmp/Makefile.in b/libs/ysnmp/Makefile.in new file mode 100644 index 00000000..fb7407e1 --- /dev/null +++ b/libs/ysnmp/Makefile.in @@ -0,0 +1,55 @@ +# Makefile +# This file holds the make rules for the libysnmp +DEBUG := + +CXX := @CXX@ -Wall +AR := ar +DEFS := +INCLUDES := -I@top_srcdir@ -I../.. -I@top_srcdir@/libs/yasn -I@srcdir@ +CFLAGS := @CFLAGS@ @MODULE_CPPFLAGS@ @INLINE_FLAGS@ +LDFLAGS:= @LDFLAGS@ -L../yasn -lyasn -L../.. -lyate +INCFILES := @top_srcdir@/yateclass.h @top_srcdir@/libs/yasn/yateasn.h @srcdir@/yatesnmp.h + +PROGS= +LIBS = libysnmp.a +OBJS = snmp.o + +LOCALFLAGS = +LOCALLIBS = +COMPILE = $(CXX) $(DEFS) $(DEBUG) $(INCLUDES) $(CFLAGS) +LINK = $(CXX) $(LDFLAGS) + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +# include optional local make rules +-include YateLocal.mak + +.PHONY: all debug ddebug xdebug +all: $(LIBS) $(LIBD) $(PROGS) + +debug: + $(MAKE) all DEBUG=-g3 MODSTRIP= + +ddebug: + $(MAKE) all DEBUG='-g3 -DDEBUG' MODSTRIP= + +xdebug: + $(MAKE) all DEBUG='-g3 -DXDEBUG' MODSTRIP= + +.PHONY: strip +strip: all + strip --strip-debug --discard-locals $(PROGS) + +.PHONY: clean +clean: + @-$(RM) $(PROGS) $(LIBS) $(LIBD) $(OBJS) core 2>/dev/null + +%.o: @srcdir@/%.cpp $(INCFILES) + $(COMPILE) -c $< + +Makefile: @srcdir@/Makefile.in ../../config.status + cd ../.. && ./config.status + +libysnmp.a: $(OBJS) + $(AR) rcs $@ $^ diff --git a/libs/ysnmp/snmp.cpp b/libs/ysnmp/snmp.cpp new file mode 100644 index 00000000..4e486d98 --- /dev/null +++ b/libs/ysnmp/snmp.cpp @@ -0,0 +1,3005 @@ +// generated on Sep 17, 2010 4:11 PM + +#include "yatesnmp.h" + +namespace Snmp { + +/** + * ObjectName + */ +ObjectName::ObjectName() +{ +} + +ObjectName::ObjectName(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +ObjectName::~ObjectName() +{ +} + +int ObjectName::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOID(data,&m_ObjectName,true); + return length; +} + +int ObjectName::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOID(m_ObjectName,true); + data.append(db); + length = db.length(); + return length; +} + +void ObjectName::getParams(NamedList* params) +{} + +void ObjectName::setParams(NamedList* params) +{} + +/** + * ObjectSyntax + */ +ObjectSyntax::ObjectSyntax() +{ + m_simple = new SimpleSyntax(); + m_application_wide = new ApplicationSyntax(); +} + +ObjectSyntax::ObjectSyntax(void* data, int len) +{ + m_simple = new SimpleSyntax(); + m_application_wide = new ApplicationSyntax(); + + DataBlock db(data,len); + decode(db); +} + +ObjectSyntax::~ObjectSyntax() +{ + if (m_simple) + TelEngine::destruct(m_simple); + if (m_application_wide) + TelEngine::destruct(m_application_wide); +} + +int ObjectSyntax::decode(DataBlock& data) +{ + int length = 0; + length = m_simple->decode(data); + if (length >= 0) { + m_choiceType = SIMPLE; + return length; + } + length = m_application_wide->decode(data); + if (length >= 0) { + m_choiceType = APPLICATION_WIDE; + return length; + } + return length; +} + +int ObjectSyntax::encode(DataBlock& data) +{ + int length = -1; + if (m_choiceType == SIMPLE) { + length = m_simple->encode(data); + } + if (m_choiceType == APPLICATION_WIDE) { + length = m_application_wide->encode(data); + } + return length; +} + +void ObjectSyntax::getParams(NamedList* params) +{} + +void ObjectSyntax::setParams(NamedList* params) +{} + +/** + * SimpleSyntax + */ +SimpleSyntax::SimpleSyntax() +{ +} + +SimpleSyntax::SimpleSyntax(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +SimpleSyntax::~SimpleSyntax() +{ +} + +int SimpleSyntax::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeINT32(data,&m_integer_value,true); + if (m_integer_value < s_integer_valueMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_integer_valueMaxSize < m_integer_value) + DDebug(DebugAll,"Constraint break error"); + if (length >= 0) { + m_choiceType = INTEGER_VALUE; + return length; + } + length = ASNLib::decodeOctetString(data,&m_string_value,true); + if (length < s_string_valueSizeMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_string_valueSizeMaxSize < length) + DDebug(DebugAll,"Constraint break error"); + if (length >= 0) { + m_choiceType = STRING_VALUE; + return length; + } + length = ASNLib::decodeOID(data,&m_objectID_value,true); + if (length >= 0) { + m_choiceType = OBJECTID_VALUE; + return length; + } + return length; +} + +int SimpleSyntax::encode(DataBlock& data) +{ + int length = -1; + if (m_choiceType == INTEGER_VALUE) { + const DataBlock db = ASNLib::encodeInteger(m_integer_value,true); + data.append(db); + length = db.length(); + } + if (m_choiceType == STRING_VALUE) { + const DataBlock db = ASNLib::encodeOctetString(m_string_value,true); + data.append(db); + length = db.length(); + } + if (m_choiceType == OBJECTID_VALUE) { + const DataBlock db = ASNLib::encodeOID(m_objectID_value,true); + data.append(db); + length = db.length(); + } + return length; +} + +void SimpleSyntax::getParams(NamedList* params) +{} + +void SimpleSyntax::setParams(NamedList* params) +{} + +/** + * ApplicationSyntax + */ +ApplicationSyntax::ApplicationSyntax() +{ + m_ipAddress_value = new IpAddress(); + m_counter_value = new Counter32(); + m_timeticks_value = new TimeTicks(); + m_arbitrary_value = new Opaque(); + m_big_counter_value = new Counter64(); + m_unsigned_integer_value = new Unsigned32(); +} + +ApplicationSyntax::ApplicationSyntax(void* data, int len) +{ + m_ipAddress_value = new IpAddress(); + m_counter_value = new Counter32(); + m_timeticks_value = new TimeTicks(); + m_arbitrary_value = new Opaque(); + m_big_counter_value = new Counter64(); + m_unsigned_integer_value = new Unsigned32(); + + DataBlock db(data,len); + decode(db); +} + +ApplicationSyntax::~ApplicationSyntax() +{ + if (m_ipAddress_value) + TelEngine::destruct(m_ipAddress_value); + if (m_counter_value) + TelEngine::destruct(m_counter_value); + if (m_timeticks_value) + TelEngine::destruct(m_timeticks_value); + if (m_arbitrary_value) + TelEngine::destruct(m_arbitrary_value); + if (m_big_counter_value) + TelEngine::destruct(m_big_counter_value); + if (m_unsigned_integer_value) + TelEngine::destruct(m_unsigned_integer_value); +} + +int ApplicationSyntax::decode(DataBlock& data) +{ + int length = 0; + length = m_ipAddress_value->decode(data); + if (length >= 0) { + m_choiceType = IPADDRESS_VALUE; + return length; + } + length = m_counter_value->decode(data); + if (length >= 0) { + m_choiceType = COUNTER_VALUE; + return length; + } + length = m_timeticks_value->decode(data); + if (length >= 0) { + m_choiceType = TIMETICKS_VALUE; + return length; + } + length = m_arbitrary_value->decode(data); + if (length >= 0) { + m_choiceType = ARBITRARY_VALUE; + return length; + } + length = m_big_counter_value->decode(data); + if (length >= 0) { + m_choiceType = BIG_COUNTER_VALUE; + return length; + } + length = m_unsigned_integer_value->decode(data); + if (length >= 0) { + m_choiceType = UNSIGNED_INTEGER_VALUE; + return length; + } + return length; +} + +int ApplicationSyntax::encode(DataBlock& data) +{ + int length = -1; + if (m_choiceType == IPADDRESS_VALUE) { + length = m_ipAddress_value->encode(data); + } + if (m_choiceType == COUNTER_VALUE) { + length = m_counter_value->encode(data); + } + if (m_choiceType == TIMETICKS_VALUE) { + length = m_timeticks_value->encode(data); + } + if (m_choiceType == ARBITRARY_VALUE) { + length = m_arbitrary_value->encode(data); + } + if (m_choiceType == BIG_COUNTER_VALUE) { + length = m_big_counter_value->encode(data); + } + if (m_choiceType == UNSIGNED_INTEGER_VALUE) { + length = m_unsigned_integer_value->encode(data); + } + return length; +} + +void ApplicationSyntax::getParams(NamedList* params) +{} + +void ApplicationSyntax::setParams(NamedList* params) +{} + +/** + * IpAddress + */ +IpAddress::IpAddress() +{ +} + +IpAddress::IpAddress(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +IpAddress::~IpAddress() +{ +} + +int IpAddress::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_IpAddress) { + data.cut(-1); + length = ASNLib::decodeOctetString(data,&m_IpAddress,false); + if (length != s_IpAddressSize) + DDebug(DebugAll,"Constraint break error"); + } + return length; +} + +int IpAddress::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_IpAddress; + const DataBlock db = ASNLib::encodeOctetString(m_IpAddress,false); + contents.append(db); + length = db.length(); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void IpAddress::getParams(NamedList* params) +{} + +void IpAddress::setParams(NamedList* params) +{} + +/** + * Counter32 + */ +Counter32::Counter32() +{ +} + +Counter32::Counter32(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +Counter32::~Counter32() +{ +} + +int Counter32::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_Counter32) { + data.cut(-1); + length = ASNLib::decodeUINT32(data,&m_Counter32,false); + if (m_Counter32 < s_Counter32MinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_Counter32MaxSize < m_Counter32) + DDebug(DebugAll,"Constraint break error"); + } + return length; +} + +int Counter32::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_Counter32; + const DataBlock db = ASNLib::encodeInteger(m_Counter32,false); + contents.append(db); + length = db.length(); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void Counter32::getParams(NamedList* params) +{} + +void Counter32::setParams(NamedList* params) +{} + +/** + * Unsigned32 + */ +Unsigned32::Unsigned32() +{ +} + +Unsigned32::Unsigned32(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +Unsigned32::~Unsigned32() +{ +} + +int Unsigned32::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_Unsigned32) { + data.cut(-1); + length = ASNLib::decodeUINT32(data,&m_Unsigned32,false); + if (m_Unsigned32 < s_Unsigned32MinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_Unsigned32MaxSize < m_Unsigned32) + DDebug(DebugAll,"Constraint break error"); + } + return length; +} + +int Unsigned32::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_Unsigned32; + const DataBlock db = ASNLib::encodeInteger(m_Unsigned32,false); + contents.append(db); + length = db.length(); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void Unsigned32::getParams(NamedList* params) +{} + +void Unsigned32::setParams(NamedList* params) +{} + +/** + * Gauge32 + */ +Gauge32::Gauge32() +{ + m_Gauge32 = new Unsigned32(); +} + +Gauge32::Gauge32(void* data, int len) +{ + m_Gauge32 = new Unsigned32(); + + DataBlock db(data,len); + decode(db); +} + +Gauge32::~Gauge32() +{ + if (m_Gauge32) + TelEngine::destruct(m_Gauge32); +} + +int Gauge32::decode(DataBlock& data) +{ + int length = 0; + length = m_Gauge32->decode(data); + return length; +} + +int Gauge32::encode(DataBlock& data) +{ + int length = -1; + length = m_Gauge32->encode(data); + return length; +} + +void Gauge32::getParams(NamedList* params) +{} + +void Gauge32::setParams(NamedList* params) +{} + +/** + * TimeTicks + */ +TimeTicks::TimeTicks() +{ +} + +TimeTicks::TimeTicks(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +TimeTicks::~TimeTicks() +{ +} + +int TimeTicks::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_TimeTicks) { + data.cut(-1); + length = ASNLib::decodeUINT32(data,&m_TimeTicks,false); + if (m_TimeTicks < s_TimeTicksMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_TimeTicksMaxSize < m_TimeTicks) + DDebug(DebugAll,"Constraint break error"); + } + return length; +} + +int TimeTicks::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_TimeTicks; + const DataBlock db = ASNLib::encodeInteger(m_TimeTicks,false); + contents.append(db); + length = db.length(); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void TimeTicks::getParams(NamedList* params) +{} + +void TimeTicks::setParams(NamedList* params) +{} + +/** + * Opaque + */ +Opaque::Opaque() +{ +} + +Opaque::Opaque(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +Opaque::~Opaque() +{ +} + +int Opaque::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_Opaque) { + data.cut(-1); + length = ASNLib::decodeOctetString(data,&m_Opaque,false); + } + return length; +} + +int Opaque::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_Opaque; + const DataBlock db = ASNLib::encodeOctetString(m_Opaque,false); + contents.append(db); + length = db.length(); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void Opaque::getParams(NamedList* params) +{} + +void Opaque::setParams(NamedList* params) +{} + +/** + * Counter64 + */ +Counter64::Counter64() +{ +} + +Counter64::Counter64(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +Counter64::~Counter64() +{ +} + +int Counter64::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_Counter64) { + data.cut(-1); + length = ASNLib::decodeUINT64(data,&m_Counter64,false); + if (m_Counter64 < s_Counter64MinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_Counter64MaxSize < m_Counter64) + DDebug(DebugAll,"Constraint break error"); + } + return length; +} + +int Counter64::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_Counter64; + const DataBlock db = ASNLib::encodeInteger(m_Counter64,false); + contents.append(db); + length = db.length(); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void Counter64::getParams(NamedList* params) +{} + +void Counter64::setParams(NamedList* params) +{} + +/** + * PDUs + */ +PDUs::PDUs() +{ + m_get_request = new GetRequest_PDU(); + m_get_next_request = new GetNextRequest_PDU(); + m_get_bulk_request = new GetBulkRequest_PDU(); + m_response = new Response_PDU(); + m_set_request = new SetRequest_PDU(); + m_inform_request = new InformRequest_PDU(); + m_snmpV2_trap = new SNMPv2_Trap_PDU(); + m_report = new Report_PDU(); +} + +PDUs::PDUs(void* data, int len) +{ + m_get_request = new GetRequest_PDU(); + m_get_next_request = new GetNextRequest_PDU(); + m_get_bulk_request = new GetBulkRequest_PDU(); + m_response = new Response_PDU(); + m_set_request = new SetRequest_PDU(); + m_inform_request = new InformRequest_PDU(); + m_snmpV2_trap = new SNMPv2_Trap_PDU(); + m_report = new Report_PDU(); + + DataBlock db(data,len); + decode(db); +} + +PDUs::~PDUs() +{ + if (m_get_request) + TelEngine::destruct(m_get_request); + if (m_get_next_request) + TelEngine::destruct(m_get_next_request); + if (m_get_bulk_request) + TelEngine::destruct(m_get_bulk_request); + if (m_response) + TelEngine::destruct(m_response); + if (m_set_request) + TelEngine::destruct(m_set_request); + if (m_inform_request) + TelEngine::destruct(m_inform_request); + if (m_snmpV2_trap) + TelEngine::destruct(m_snmpV2_trap); + if (m_report) + TelEngine::destruct(m_report); +} + +int PDUs::decode(DataBlock& data) +{ + int length = 0; + length = m_get_request->decode(data); + if (length >= 0) { + m_choiceType = GET_REQUEST; + return length; + } + length = m_get_next_request->decode(data); + if (length >= 0) { + m_choiceType = GET_NEXT_REQUEST; + return length; + } + length = m_get_bulk_request->decode(data); + if (length >= 0) { + m_choiceType = GET_BULK_REQUEST; + return length; + } + length = m_response->decode(data); + if (length >= 0) { + m_choiceType = RESPONSE; + return length; + } + length = m_set_request->decode(data); + if (length >= 0) { + m_choiceType = SET_REQUEST; + return length; + } + length = m_inform_request->decode(data); + if (length >= 0) { + m_choiceType = INFORM_REQUEST; + return length; + } + length = m_snmpV2_trap->decode(data); + if (length >= 0) { + m_choiceType = SNMPV2_TRAP; + return length; + } + length = m_report->decode(data); + if (length >= 0) { + m_choiceType = REPORT; + return length; + } + return length; +} + +int PDUs::encode(DataBlock& data) +{ + int length = -1; + if (m_choiceType == GET_REQUEST) { + length = m_get_request->encode(data); + } + if (m_choiceType == GET_NEXT_REQUEST) { + length = m_get_next_request->encode(data); + } + if (m_choiceType == GET_BULK_REQUEST) { + length = m_get_bulk_request->encode(data); + } + if (m_choiceType == RESPONSE) { + length = m_response->encode(data); + } + if (m_choiceType == SET_REQUEST) { + length = m_set_request->encode(data); + } + if (m_choiceType == INFORM_REQUEST) { + length = m_inform_request->encode(data); + } + if (m_choiceType == SNMPV2_TRAP) { + length = m_snmpV2_trap->encode(data); + } + if (m_choiceType == REPORT) { + length = m_report->encode(data); + } + return length; +} + +void PDUs::getParams(NamedList* params) +{} + +void PDUs::setParams(NamedList* params) +{} + +/** + * GetRequest_PDU + */ +GetRequest_PDU::GetRequest_PDU() +{ + m_GetRequest_PDU = new PDU(); +} + +GetRequest_PDU::GetRequest_PDU(void* data, int len) +{ + m_GetRequest_PDU = new PDU(); + DataBlock db(data,len); + decode(db); +} + +GetRequest_PDU::~GetRequest_PDU() +{ + if (m_GetRequest_PDU) + TelEngine::destruct(m_GetRequest_PDU); +} + +int GetRequest_PDU::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_GetRequest_PDU) { + data.cut(-1); + length = m_GetRequest_PDU->decode(data); + } + return length; +} + +int GetRequest_PDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_GetRequest_PDU; + length = m_GetRequest_PDU->encode(contents); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void GetRequest_PDU::getParams(NamedList* params) +{} + +void GetRequest_PDU::setParams(NamedList* params) +{} + +/** + * GetNextRequest_PDU + */ +GetNextRequest_PDU::GetNextRequest_PDU() +{ + m_GetNextRequest_PDU = new PDU(); +} + +GetNextRequest_PDU::GetNextRequest_PDU(void* data, int len) +{ + m_GetNextRequest_PDU = new PDU(); + DataBlock db(data,len); + decode(db); +} + +GetNextRequest_PDU::~GetNextRequest_PDU() +{ + if (m_GetNextRequest_PDU) + TelEngine::destruct(m_GetNextRequest_PDU); +} + +int GetNextRequest_PDU::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_GetNextRequest_PDU) { + data.cut(-1); + length = m_GetNextRequest_PDU->decode(data); + } + return length; +} + +int GetNextRequest_PDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_GetNextRequest_PDU; + length = m_GetNextRequest_PDU->encode(contents); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void GetNextRequest_PDU::getParams(NamedList* params) +{} + +void GetNextRequest_PDU::setParams(NamedList* params) +{} + +/** + * Response_PDU + */ +Response_PDU::Response_PDU() +{ + m_Response_PDU = new PDU(); +} + +Response_PDU::Response_PDU(void* data, int len) +{ + m_Response_PDU = new PDU(); + DataBlock db(data,len); + decode(db); +} + +Response_PDU::~Response_PDU() +{ + if (m_Response_PDU) + TelEngine::destruct(m_Response_PDU); +} + +int Response_PDU::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_Response_PDU) { + data.cut(-1); + length = m_Response_PDU->decode(data); + } + return length; +} + +int Response_PDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_Response_PDU; + length = m_Response_PDU->encode(contents); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void Response_PDU::getParams(NamedList* params) +{} + +void Response_PDU::setParams(NamedList* params) +{} + +/** + * SetRequest_PDU + */ +SetRequest_PDU::SetRequest_PDU() +{ + m_SetRequest_PDU = new PDU(); +} + +SetRequest_PDU::SetRequest_PDU(void* data, int len) +{ + m_SetRequest_PDU = new PDU(); + DataBlock db(data,len); + decode(db); +} + +SetRequest_PDU::~SetRequest_PDU() +{ + if (m_SetRequest_PDU) + TelEngine::destruct(m_SetRequest_PDU); +} + +int SetRequest_PDU::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_SetRequest_PDU) { + data.cut(-1); + length = m_SetRequest_PDU->decode(data); + } + return length; +} + +int SetRequest_PDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_SetRequest_PDU; + length = m_SetRequest_PDU->encode(contents); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void SetRequest_PDU::getParams(NamedList* params) +{} + +void SetRequest_PDU::setParams(NamedList* params) +{} + +/** + * GetBulkRequest_PDU + */ +GetBulkRequest_PDU::GetBulkRequest_PDU() +{ + m_GetBulkRequest_PDU = new BulkPDU(); +} + +GetBulkRequest_PDU::GetBulkRequest_PDU(void* data, int len) +{ + m_GetBulkRequest_PDU = new BulkPDU(); + DataBlock db(data,len); + decode(db); +} + +GetBulkRequest_PDU::~GetBulkRequest_PDU() +{ + if (m_GetBulkRequest_PDU) + TelEngine::destruct(m_GetBulkRequest_PDU); +} + +int GetBulkRequest_PDU::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_GetBulkRequest_PDU) { + data.cut(-1); + length = m_GetBulkRequest_PDU->decode(data); + } + return length; +} + +int GetBulkRequest_PDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_GetBulkRequest_PDU; + length = m_GetBulkRequest_PDU->encode(contents); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void GetBulkRequest_PDU::getParams(NamedList* params) +{} + +void GetBulkRequest_PDU::setParams(NamedList* params) +{} + +/** + * InformRequest_PDU + */ +InformRequest_PDU::InformRequest_PDU() +{ + m_InformRequest_PDU = new PDU(); +} + +InformRequest_PDU::InformRequest_PDU(void* data, int len) +{ + m_InformRequest_PDU = new PDU(); + DataBlock db(data,len); + decode(db); +} + +InformRequest_PDU::~InformRequest_PDU() +{ + if (m_InformRequest_PDU) + TelEngine::destruct(m_InformRequest_PDU); +} + +int InformRequest_PDU::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_InformRequest_PDU) { + data.cut(-1); + length = m_InformRequest_PDU->decode(data); + } + return length; +} + +int InformRequest_PDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_InformRequest_PDU; + length = m_InformRequest_PDU->encode(contents); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void InformRequest_PDU::getParams(NamedList* params) +{} + +void InformRequest_PDU::setParams(NamedList* params) +{} + +/** + * SNMPv2_Trap_PDU + */ +SNMPv2_Trap_PDU::SNMPv2_Trap_PDU() +{ + m_SNMPv2_Trap_PDU = new PDU(); +} + +SNMPv2_Trap_PDU::SNMPv2_Trap_PDU(void* data, int len) +{ + m_SNMPv2_Trap_PDU = new PDU(); + DataBlock db(data,len); + decode(db); +} + +SNMPv2_Trap_PDU::~SNMPv2_Trap_PDU() +{ + if (m_SNMPv2_Trap_PDU) + TelEngine::destruct(m_SNMPv2_Trap_PDU); +} + +int SNMPv2_Trap_PDU::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_SNMPv2_Trap_PDU) { + data.cut(-1); + length = m_SNMPv2_Trap_PDU->decode(data); + } + return length; +} + +int SNMPv2_Trap_PDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_SNMPv2_Trap_PDU; + length = m_SNMPv2_Trap_PDU->encode(contents); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void SNMPv2_Trap_PDU::getParams(NamedList* params) +{} + +void SNMPv2_Trap_PDU::setParams(NamedList* params) +{} + +/** + * Report_PDU + */ +Report_PDU::Report_PDU() +{ + m_Report_PDU = new PDU(); +} + +Report_PDU::Report_PDU(void* data, int len) +{ + m_Report_PDU = new PDU(); + DataBlock db(data,len); + decode(db); +} + +Report_PDU::~Report_PDU() +{ + if (m_Report_PDU) + TelEngine::destruct(m_Report_PDU); +} + +int Report_PDU::decode(DataBlock& data) +{ + int length = 0; + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_Report_PDU) { + data.cut(-1); + length = m_Report_PDU->decode(data); + } + return length; +} + +int Report_PDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock contents; + u_int8_t tag = tag_Report_PDU; + length = m_Report_PDU->encode(contents); + DataBlock len = ASNLib::buildLength(contents); + data.append(&tag,1); + data.append(len); + data.append(contents); + return length; +} + +void Report_PDU::getParams(NamedList* params) +{} + +void Report_PDU::setParams(NamedList* params) +{} + +/** + * PDU + */ +PDU::PDU() +{ + m_variable_bindings = new VarBindList(); +} + +PDU::PDU(void* data, int len) +{ + m_variable_bindings = new VarBindList(); + DataBlock db(data,len); + decode(db); +} + +PDU::~PDU() +{ + if (m_variable_bindings) + TelEngine::destruct(m_variable_bindings); +} + +int PDU::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeSequence(data,false); + if (length < 0) + return length; + length = ASNLib::decodeINT32(data,&m_request_id,true); + if (m_request_id < s_request_idMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_request_idMaxSize < m_request_id) + DDebug(DebugAll,"Constraint break error"); + length = ASNLib::decodeINT32(data,&m_error_status,true); + if ( m_error_status < s_noError_error_status || m_error_status > s_inconsistentName_error_status) + return ASNLib::InvalidContentsError; + length = ASNLib::decodeINT32(data,&m_error_index,true); + if (m_error_index < s_error_indexMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_error_indexMaxSize < m_error_index) + DDebug(DebugAll,"Constraint break error"); + length = m_variable_bindings->decode(data); + return length; +} + +int PDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock seqDb; + DataBlock db; + length = 0; + db = ASNLib::encodeInteger(m_request_id,true); + seqDb.append(db); + db = ASNLib::encodeInteger(m_error_status,true); + seqDb.append(db); + db = ASNLib::encodeInteger(m_error_index,true); + seqDb.append(db); + m_variable_bindings->encode(seqDb); + length = ASNLib::encodeSequence(seqDb,false); + data.append(seqDb); + return length; +} + +void PDU::getParams(NamedList* params) +{} + +void PDU::setParams(NamedList* params) +{} + +/** + * BulkPDU + */ +BulkPDU::BulkPDU() +{ + m_variable_bindings = new VarBindList(); +} + +BulkPDU::BulkPDU(void* data, int len) +{ + m_variable_bindings = new VarBindList(); + DataBlock db(data,len); + decode(db); +} + +BulkPDU::~BulkPDU() +{ + if (m_variable_bindings) + TelEngine::destruct(m_variable_bindings); +} + +int BulkPDU::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeSequence(data,false); + if (length < 0) + return length; + length = ASNLib::decodeINT32(data,&m_request_id,true); + if (m_request_id < s_request_idMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_request_idMaxSize < m_request_id) + DDebug(DebugAll,"Constraint break error"); + length = ASNLib::decodeINT32(data,&m_non_repeaters,true); + if (m_non_repeaters < s_non_repeatersMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_non_repeatersMaxSize < m_non_repeaters) + DDebug(DebugAll,"Constraint break error"); + length = ASNLib::decodeINT32(data,&m_max_repetitions,true); + if (m_max_repetitions < s_max_repetitionsMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_max_repetitionsMaxSize < m_max_repetitions) + DDebug(DebugAll,"Constraint break error"); + length = m_variable_bindings->decode(data); + return length; +} + +int BulkPDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock seqDb; + DataBlock db; + length = 0; + db = ASNLib::encodeInteger(m_request_id,true); + seqDb.append(db); + db = ASNLib::encodeInteger(m_non_repeaters,true); + seqDb.append(db); + db = ASNLib::encodeInteger(m_max_repetitions,true); + seqDb.append(db); + m_variable_bindings->encode(seqDb); + length = ASNLib::encodeSequence(seqDb,false); + data.append(seqDb); + return length; +} + +void BulkPDU::getParams(NamedList* params) +{} + +void BulkPDU::setParams(NamedList* params) +{} + +/** + * VarBind + */ +VarBind::VarBind() +{ + m_name = new ObjectName(); + m_value = new ObjectSyntax(); +} + +VarBind::VarBind(void* data, int len) +{ + m_name = new ObjectName(); + m_value = new ObjectSyntax(); + DataBlock db(data,len); + decode(db); +} + +VarBind::~VarBind() +{ + if (m_name) + TelEngine::destruct(m_name); + if (m_value) + TelEngine::destruct(m_value); +} + +int VarBind::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeSequence(data,true); + if (length < 0) + return length; + length = m_name->decode(data); + length = m_value->decode(data); + if (length >= 0) { + m_choiceType = VALUE; + return length; + } + length = ASNLib::decodeNull(data,true); + if (length >= 0) { + m_choiceType = UNSPECIFIED; + return length; + } + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_noSuchObject) { + data.cut(-1); + length = ASNLib::decodeNull(data,false); + } + if (length >= 0) { + m_choiceType = NOSUCHOBJECT; + return length; + } + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_noSuchInstance) { + data.cut(-1); + length = ASNLib::decodeNull(data,false); + } + if (length >= 0) { + m_choiceType = NOSUCHINSTANCE; + return length; + } + length = -1; + if (data.length() < 2) + return ASNLib::InvalidLengthOrTag; + if (data[0] == tag_endOfMibView) { + data.cut(-1); + length = ASNLib::decodeNull(data,false); + } + if (length >= 0) { + m_choiceType = ENDOFMIBVIEW; + return length; + } + return length; +} + +int VarBind::encode(DataBlock& data) +{ + int length = -1; + DataBlock seqDb; + DataBlock db; + length = 0; + m_name->encode(seqDb); + if (m_choiceType == VALUE) { + length = m_value->encode(seqDb); + } + if (m_choiceType == UNSPECIFIED) { + DataBlock db = ASNLib::encodeNull(true); + seqDb.append(db); + length += seqDb.length(); + } + if (m_choiceType == NOSUCHOBJECT) { + DataBlock contents; + u_int8_t tag = tag_noSuchObject; + DataBlock db = ASNLib::encodeNull(false); + contents.append(db); + length += contents.length(); + DataBlock len = ASNLib::buildLength(contents); + seqDb.append(&tag,1); + seqDb.append(len); + seqDb.append(contents); + } + if (m_choiceType == NOSUCHINSTANCE) { + DataBlock contents; + u_int8_t tag = tag_noSuchInstance; + DataBlock db = ASNLib::encodeNull(false); + contents.append(db); + length += contents.length(); + DataBlock len = ASNLib::buildLength(contents); + seqDb.append(&tag,1); + seqDb.append(len); + seqDb.append(contents); + } + if (m_choiceType == ENDOFMIBVIEW) { + DataBlock contents; + u_int8_t tag = tag_endOfMibView; + DataBlock db = ASNLib::encodeNull(false); + contents.append(db); + length += contents.length(); + DataBlock len = ASNLib::buildLength(contents); + seqDb.append(&tag,1); + seqDb.append(len); + seqDb.append(contents); + } + + seqDb.append(db); + length = ASNLib::encodeSequence(seqDb,true); + data.append(seqDb); + return length; +} + +void VarBind::getParams(NamedList* params) +{} + +void VarBind::setParams(NamedList* params) +{} + +/** + * VarBindList + */ +VarBindList::VarBindList() +{ +} + +VarBindList::VarBindList(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +VarBindList::~VarBindList() +{ +} + +int VarBindList::decode(DataBlock& data) +{ + int length = 0; + length = 0; + length = ASNLib::decodeSequence(data,true); + if (length < 0) + return length; + int l = 0; + while (l > -1) { + VarBind* obj = new VarBind(); + l = obj->decode(data); + if (l > -1) { + length += l; + m_list.append(obj); + } + } + return length; +} + +int VarBindList::encode(DataBlock& data) +{ + int length = -1; + DataBlock db; + length = 0; + for (unsigned int i = 0; i < m_list.count(); i++) { + VarBind* obj = static_cast(m_list[i]); + int l = obj->encode(db); + if (l <= -1) + return -1; + length += l; + } + length = ASNLib::encodeSequence(db,true); + if (length < 0) + return length; + data.append(db); + return length; +} + +void VarBindList::getParams(NamedList* params) +{} + +void VarBindList::setParams(NamedList* params) +{} + +/** + * DisplayString + */ +DisplayString::DisplayString() +{ +} + +DisplayString::DisplayString(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +DisplayString::~DisplayString() +{ +} + +int DisplayString::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOctetString(data,&m_DisplayString,true); + if (length < s_DisplayStringSizeMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_DisplayStringSizeMaxSize < length) + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int DisplayString::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOctetString(m_DisplayString,true); + data.append(db); + length = db.length(); + return length; +} + +void DisplayString::getParams(NamedList* params) +{} + +void DisplayString::setParams(NamedList* params) +{} + +/** + * PhysAddress + */ +PhysAddress::PhysAddress() +{ +} + +PhysAddress::PhysAddress(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +PhysAddress::~PhysAddress() +{ +} + +int PhysAddress::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOctetString(data,&m_PhysAddress,true); + return length; +} + +int PhysAddress::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOctetString(m_PhysAddress,true); + data.append(db); + length = db.length(); + return length; +} + +void PhysAddress::getParams(NamedList* params) +{} + +void PhysAddress::setParams(NamedList* params) +{} + +/** + * MacAddress + */ +MacAddress::MacAddress() +{ +} + +MacAddress::MacAddress(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +MacAddress::~MacAddress() +{ +} + +int MacAddress::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOctetString(data,&m_MacAddress,true); + if (length != s_MacAddressSize) + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int MacAddress::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOctetString(m_MacAddress,true); + data.append(db); + length = db.length(); + return length; +} + +void MacAddress::getParams(NamedList* params) +{} + +void MacAddress::setParams(NamedList* params) +{} + +/** + * TruthValue + */ +TruthValue::TruthValue() +{ +} + +TruthValue::TruthValue(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +TruthValue::~TruthValue() +{ +} + +int TruthValue::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeINT32(data,&m_TruthValue,true); + if ( m_TruthValue < s_true_TruthValue || m_TruthValue > s_false_TruthValue) + return ASNLib::InvalidContentsError; + return length; +} + +int TruthValue::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeInteger(m_TruthValue,true); + data.append(db); + length = db.length(); + return length; +} + +void TruthValue::getParams(NamedList* params) +{} + +void TruthValue::setParams(NamedList* params) +{} + +/** + * TestAndIncr + */ +TestAndIncr::TestAndIncr() +{ +} + +TestAndIncr::TestAndIncr(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +TestAndIncr::~TestAndIncr() +{ +} + +int TestAndIncr::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeUINT32(data,&m_TestAndIncr,true); + if (m_TestAndIncr < s_TestAndIncrMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_TestAndIncrMaxSize < m_TestAndIncr) + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int TestAndIncr::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeInteger(m_TestAndIncr,true); + data.append(db); + length = db.length(); + return length; +} + +void TestAndIncr::getParams(NamedList* params) +{} + +void TestAndIncr::setParams(NamedList* params) +{} + +/** + * AutonomousType + */ +AutonomousType::AutonomousType() +{ +} + +AutonomousType::AutonomousType(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +AutonomousType::~AutonomousType() +{ +} + +int AutonomousType::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOID(data,&m_AutonomousType,true); + return length; +} + +int AutonomousType::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOID(m_AutonomousType,true); + data.append(db); + length = db.length(); + return length; +} + +void AutonomousType::getParams(NamedList* params) +{} + +void AutonomousType::setParams(NamedList* params) +{} + +/** + * InstancePointer + */ +InstancePointer::InstancePointer() +{ +} + +InstancePointer::InstancePointer(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +InstancePointer::~InstancePointer() +{ +} + +int InstancePointer::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOID(data,&m_InstancePointer,true); + return length; +} + +int InstancePointer::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOID(m_InstancePointer,true); + data.append(db); + length = db.length(); + return length; +} + +void InstancePointer::getParams(NamedList* params) +{} + +void InstancePointer::setParams(NamedList* params) +{} + +/** + * VariablePointer + */ +VariablePointer::VariablePointer() +{ +} + +VariablePointer::VariablePointer(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +VariablePointer::~VariablePointer() +{ +} + +int VariablePointer::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOID(data,&m_VariablePointer,true); + return length; +} + +int VariablePointer::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOID(m_VariablePointer,true); + data.append(db); + length = db.length(); + return length; +} + +void VariablePointer::getParams(NamedList* params) +{} + +void VariablePointer::setParams(NamedList* params) +{} + +/** + * RowPointer + */ +RowPointer::RowPointer() +{ +} + +RowPointer::RowPointer(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +RowPointer::~RowPointer() +{ +} + +int RowPointer::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOID(data,&m_RowPointer,true); + return length; +} + +int RowPointer::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOID(m_RowPointer,true); + data.append(db); + length = db.length(); + return length; +} + +void RowPointer::getParams(NamedList* params) +{} + +void RowPointer::setParams(NamedList* params) +{} + +/** + * RowStatus + */ +RowStatus::RowStatus() +{ +} + +RowStatus::RowStatus(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +RowStatus::~RowStatus() +{ +} + +int RowStatus::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeINT32(data,&m_RowStatus,true); + if ( m_RowStatus < s_active_RowStatus || m_RowStatus > s_destroy_RowStatus) + return ASNLib::InvalidContentsError; + return length; +} + +int RowStatus::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeInteger(m_RowStatus,true); + data.append(db); + length = db.length(); + return length; +} + +void RowStatus::getParams(NamedList* params) +{} + +void RowStatus::setParams(NamedList* params) +{} + +/** + * TimeStamp + */ +TimeStamp::TimeStamp() +{ +} + +TimeStamp::TimeStamp(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +TimeStamp::~TimeStamp() +{ +} + +int TimeStamp::decode(DataBlock& data) +{ + int length = 0; + length = m_TimeStamp->decode(data); + return length; +} + +int TimeStamp::encode(DataBlock& data) +{ + int length = -1; + length = m_TimeStamp->encode(data); + return length; +} + +void TimeStamp::getParams(NamedList* params) +{} + +void TimeStamp::setParams(NamedList* params) +{} + +/** + * TimeInterval + */ +TimeInterval::TimeInterval() +{ +} + +TimeInterval::TimeInterval(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +TimeInterval::~TimeInterval() +{ +} + +int TimeInterval::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeUINT32(data,&m_TimeInterval,true); + if (m_TimeInterval < s_TimeIntervalMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_TimeIntervalMaxSize < m_TimeInterval) + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int TimeInterval::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeInteger(m_TimeInterval,true); + data.append(db); + length = db.length(); + return length; +} + +void TimeInterval::getParams(NamedList* params) +{} + +void TimeInterval::setParams(NamedList* params) +{} + +/** + * DateAndTime + */ +DateAndTime::DateAndTime() +{ +} + +DateAndTime::DateAndTime(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +DateAndTime::~DateAndTime() +{ +} + +int DateAndTime::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOctetString(data,&m_DateAndTime,true); + if (length != s_DateAndTimeSize_0) + DDebug(DebugAll,"Constraint break error"); + if (length != s_DateAndTimeSize_1) + DDebug(DebugAll,"Constraint break error"); + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int DateAndTime::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOctetString(m_DateAndTime,true); + data.append(db); + length = db.length(); + return length; +} + +void DateAndTime::getParams(NamedList* params) +{} + +void DateAndTime::setParams(NamedList* params) +{} + +/** + * StorageType + */ +StorageType::StorageType() +{ +} + +StorageType::StorageType(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +StorageType::~StorageType() +{ +} + +int StorageType::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeINT32(data,&m_StorageType,true); + if ( m_StorageType < s_other_StorageType || m_StorageType > s_readOnly_StorageType) + return ASNLib::InvalidContentsError; + return length; +} + +int StorageType::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeInteger(m_StorageType,true); + data.append(db); + length = db.length(); + return length; +} + +void StorageType::getParams(NamedList* params) +{} + +void StorageType::setParams(NamedList* params) +{} + +/** + * TDomain + */ +TDomain::TDomain() +{ +} + +TDomain::TDomain(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +TDomain::~TDomain() +{ +} + +int TDomain::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOID(data,&m_TDomain,true); + return length; +} + +int TDomain::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOID(m_TDomain,true); + data.append(db); + length = db.length(); + return length; +} + +void TDomain::getParams(NamedList* params) +{} + +void TDomain::setParams(NamedList* params) +{} + +/** + * TAddress + */ +TAddress::TAddress() +{ +} + +TAddress::TAddress(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +TAddress::~TAddress() +{ +} + +int TAddress::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOctetString(data,&m_TAddress,true); + if (length < s_TAddressSizeMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_TAddressSizeMaxSize < length) + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int TAddress::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOctetString(m_TAddress,true); + data.append(db); + length = db.length(); + return length; +} + +void TAddress::getParams(NamedList* params) +{} + +void TAddress::setParams(NamedList* params) +{} + +/** + * SNMPv3Message + */ +SNMPv3Message::SNMPv3Message() +{ + m_msgGlobalData = new HeaderData(); + m_msgData = new ScopedPduData(); +} + +SNMPv3Message::SNMPv3Message(void* data, int len) +{ + m_msgGlobalData = new HeaderData(); + m_msgData = new ScopedPduData(); + DataBlock db(data,len); + decode(db); +} + +SNMPv3Message::~SNMPv3Message() +{ + if (m_msgGlobalData) + TelEngine::destruct(m_msgGlobalData); + if (m_msgData) + TelEngine::destruct(m_msgData); +} + +int SNMPv3Message::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeSequence(data,true); + if (length < 0) + return length; + length = ASNLib::decodeUINT32(data,&m_msgVersion,true); + if (m_msgVersion < s_msgVersionMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_msgVersionMaxSize < m_msgVersion) + DDebug(DebugAll,"Constraint break error"); + length = m_msgGlobalData->decode(data); + length = ASNLib::decodeOctetString(data,&m_msgSecurityParameters,true); + length = m_msgData->decode(data); + return length; +} + +int SNMPv3Message::encode(DataBlock& data) +{ + int length = -1; + DataBlock seqDb; + DataBlock db; + length = 0; + db = ASNLib::encodeInteger(m_msgVersion,true); + seqDb.append(db); + m_msgGlobalData->encode(seqDb); + db = ASNLib::encodeOctetString(m_msgSecurityParameters,true); + seqDb.append(db); + m_msgData->encode(seqDb); + length = ASNLib::encodeSequence(seqDb,true); + data.append(seqDb); + return length; +} + +void SNMPv3Message::getParams(NamedList* params) +{} + +void SNMPv3Message::setParams(NamedList* params) +{} + +/** + * HeaderData + */ +HeaderData::HeaderData() +{ +} + +HeaderData::HeaderData(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +HeaderData::~HeaderData() +{ +} + +int HeaderData::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeSequence(data,true); + if (length < 0) + return length; + length = ASNLib::decodeUINT32(data,&m_msgID,true); + if (m_msgID < s_msgIDMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_msgIDMaxSize < m_msgID) + DDebug(DebugAll,"Constraint break error"); + length = ASNLib::decodeUINT32(data,&m_msgMaxSize,true); + if (m_msgMaxSize < s_msgMaxSizeMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_msgMaxSizeMaxSize < m_msgMaxSize) + DDebug(DebugAll,"Constraint break error"); + length = ASNLib::decodeOctetString(data,&m_msgFlags,true); + if (length != s_msgFlagsSize) + DDebug(DebugAll,"Constraint break error"); + length = ASNLib::decodeUINT32(data,&m_msgSecurityModel,true); + if (m_msgSecurityModel < s_msgSecurityModelMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_msgSecurityModelMaxSize < m_msgSecurityModel) + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int HeaderData::encode(DataBlock& data) +{ + int length = -1; + DataBlock seqDb; + DataBlock db; + length = 0; + db = ASNLib::encodeInteger(m_msgID,true); + seqDb.append(db); + db = ASNLib::encodeInteger(m_msgMaxSize,true); + seqDb.append(db); + db = ASNLib::encodeOctetString(m_msgFlags,true); + seqDb.append(db); + db = ASNLib::encodeInteger(m_msgSecurityModel,true); + seqDb.append(db); + length = ASNLib::encodeSequence(seqDb,true); + data.append(seqDb); + return length; +} + +void HeaderData::getParams(NamedList* params) +{} + +void HeaderData::setParams(NamedList* params) +{} + +/** + * ScopedPduData + */ +ScopedPduData::ScopedPduData() +{ + m_plaintext = new ScopedPDU(); +} + +ScopedPduData::ScopedPduData(void* data, int len) +{ + m_plaintext = new ScopedPDU(); + DataBlock db(data,len); + decode(db); +} + +ScopedPduData::~ScopedPduData() +{ + if (m_plaintext) + TelEngine::destruct(m_plaintext); +} + +int ScopedPduData::decode(DataBlock& data) +{ + int length = 0; + length = m_plaintext->decode(data); + if (length >= 0) { + m_choiceType = PLAINTEXT; + return length; + } + length = ASNLib::decodeOctetString(data,&m_encryptedPDU,true); + if (length >= 0) { + m_choiceType = ENCRYPTEDPDU; + return length; + } + return length; +} + +int ScopedPduData::encode(DataBlock& data) +{ + int length = -1; + if (m_choiceType == PLAINTEXT) { + length = m_plaintext->encode(data); + } + if (m_choiceType == ENCRYPTEDPDU) { + const DataBlock db = ASNLib::encodeOctetString(m_encryptedPDU,true); + data.append(db); + length = db.length(); + } + return length; +} + +void ScopedPduData::getParams(NamedList* params) +{} + +void ScopedPduData::setParams(NamedList* params) +{} + +/** + * ScopedPDU + */ +ScopedPDU::ScopedPDU() +{ +} + +ScopedPDU::ScopedPDU(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +ScopedPDU::~ScopedPDU() +{ +} + +int ScopedPDU::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeSequence(data,true); + if (length < 0) + return length; + length = ASNLib::decodeOctetString(data,&m_contextEngineID,true); + length = ASNLib::decodeOctetString(data,&m_contextName,true); + length = ASNLib::decodeAny(data,&m_data,true); + if (length < 0) + return length; + return length; +} + +int ScopedPDU::encode(DataBlock& data) +{ + int length = -1; + DataBlock seqDb; + DataBlock db; + length = 0; + db = ASNLib::encodeOctetString(m_contextEngineID,true); + seqDb.append(db); + db = ASNLib::encodeOctetString(m_contextName,true); + seqDb.append(db); + db = ASNLib::encodeAny(m_data,true); + seqDb.append(db); + length = ASNLib::encodeSequence(seqDb,true); + data.append(seqDb); + return length; +} + +void ScopedPDU::getParams(NamedList* params) +{} + +void ScopedPDU::setParams(NamedList* params) +{} + +/** + * Message + */ +Message::Message() +{ +} + +Message::Message(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +Message::~Message() +{ +} + +int Message::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeSequence(data,true); + if (length < 0) + return length; + length = ASNLib::decodeINT32(data,&m_version,true); + if ( m_version < s_version_1_version || m_version > s_version_2_version) + return ASNLib::InvalidContentsError; + length = ASNLib::decodeOctetString(data,&m_community,true); + length = ASNLib::decodeAny(data,&m_data,true); + if (length < 0) + return length; + return length; +} + +int Message::encode(DataBlock& data) +{ + int length = -1; + DataBlock seqDb; + DataBlock db; + length = 0; + db = ASNLib::encodeInteger(m_version,true); + seqDb.append(db); + db = ASNLib::encodeOctetString(m_community,true); + seqDb.append(db); + db = ASNLib::encodeAny(m_data,true); + seqDb.append(db); + length = ASNLib::encodeSequence(seqDb,true); + data.append(seqDb); + return length; +} + +void Message::getParams(NamedList* params) +{} + +void Message::setParams(NamedList* params) +{} + +/** + * KeyChange + */ +KeyChange::KeyChange() +{ +} + +KeyChange::KeyChange(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +KeyChange::~KeyChange() +{ +} + +int KeyChange::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOctetString(data,&m_KeyChange,true); + return length; +} + +int KeyChange::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOctetString(m_KeyChange,true); + data.append(db); + length = db.length(); + return length; +} + +void KeyChange::getParams(NamedList* params) +{} + +void KeyChange::setParams(NamedList* params) +{} + +/** + * UsmUserEntry + */ +UsmUserEntry::UsmUserEntry() +{ + m_usmUserEngineID = new SnmpEngineID(); + m_usmUserName = new SnmpAdminString(); + m_usmUserSecurityName = new SnmpAdminString(); + m_usmUserCloneFrom = new RowPointer(); + m_usmUserAuthProtocol = new AutonomousType(); + m_usmUserAuthKeyChange = new KeyChange(); + m_usmUserOwnAuthKeyChange = new KeyChange(); + m_usmUserPrivProtocol = new AutonomousType(); + m_usmUserPrivKeyChange = new KeyChange(); + m_usmUserOwnPrivKeyChange = new KeyChange(); + m_usmUserStorageType = new StorageType(); + m_usmUserStatus = new RowStatus(); +} + +UsmUserEntry::UsmUserEntry(void* data, int len) +{ + m_usmUserEngineID = new SnmpEngineID(); + m_usmUserName = new SnmpAdminString(); + m_usmUserSecurityName = new SnmpAdminString(); + m_usmUserCloneFrom = new RowPointer(); + m_usmUserAuthProtocol = new AutonomousType(); + m_usmUserAuthKeyChange = new KeyChange(); + m_usmUserOwnAuthKeyChange = new KeyChange(); + m_usmUserPrivProtocol = new AutonomousType(); + m_usmUserPrivKeyChange = new KeyChange(); + m_usmUserOwnPrivKeyChange = new KeyChange(); + m_usmUserStorageType = new StorageType(); + m_usmUserStatus = new RowStatus(); + + DataBlock db(data,len); + decode(db); +} + +UsmUserEntry::~UsmUserEntry() +{ + if (m_usmUserEngineID) + TelEngine::destruct(m_usmUserEngineID); + if (m_usmUserName) + TelEngine::destruct(m_usmUserName); + if (m_usmUserSecurityName) + TelEngine::destruct(m_usmUserSecurityName); + if (m_usmUserCloneFrom) + TelEngine::destruct(m_usmUserCloneFrom); + if (m_usmUserAuthProtocol) + TelEngine::destruct(m_usmUserAuthProtocol); + if (m_usmUserAuthKeyChange) + TelEngine::destruct(m_usmUserAuthKeyChange); + if (m_usmUserOwnAuthKeyChange) + TelEngine::destruct(m_usmUserOwnAuthKeyChange); + if (m_usmUserPrivProtocol) + TelEngine::destruct(m_usmUserPrivProtocol); + if (m_usmUserPrivKeyChange) + TelEngine::destruct(m_usmUserPrivKeyChange); + if (m_usmUserOwnPrivKeyChange) + TelEngine::destruct(m_usmUserOwnPrivKeyChange); + if (m_usmUserStorageType) + TelEngine::destruct(m_usmUserStorageType); + if (m_usmUserStatus) + TelEngine::destruct(m_usmUserStatus); +} + +int UsmUserEntry::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeSequence(data,true); + if (length < 0) + return length; + length = m_usmUserEngineID->decode(data); + length = m_usmUserName->decode(data); + length = m_usmUserSecurityName->decode(data); + length = m_usmUserCloneFrom->decode(data); + length = m_usmUserAuthProtocol->decode(data); + length = m_usmUserAuthKeyChange->decode(data); + length = m_usmUserOwnAuthKeyChange->decode(data); + length = m_usmUserPrivProtocol->decode(data); + length = m_usmUserPrivKeyChange->decode(data); + length = m_usmUserOwnPrivKeyChange->decode(data); + length = ASNLib::decodeOctetString(data,&m_usmUserPublic,true); + length = m_usmUserStorageType->decode(data); + length = m_usmUserStatus->decode(data); + return length; +} + +int UsmUserEntry::encode(DataBlock& data) +{ + int length = -1; + DataBlock seqDb; + DataBlock db; + length = 0; + m_usmUserEngineID->encode(seqDb); + m_usmUserName->encode(seqDb); + m_usmUserSecurityName->encode(seqDb); + m_usmUserCloneFrom->encode(seqDb); + m_usmUserAuthProtocol->encode(seqDb); + m_usmUserAuthKeyChange->encode(seqDb); + m_usmUserOwnAuthKeyChange->encode(seqDb); + m_usmUserPrivProtocol->encode(seqDb); + m_usmUserPrivKeyChange->encode(seqDb); + m_usmUserOwnPrivKeyChange->encode(seqDb); + db = ASNLib::encodeOctetString(m_usmUserPublic,true); + seqDb.append(db); + m_usmUserStorageType->encode(seqDb); + m_usmUserStatus->encode(seqDb); + length = ASNLib::encodeSequence(seqDb,true); + data.append(seqDb); + return length; +} + +void UsmUserEntry::getParams(NamedList* params) +{} + +void UsmUserEntry::setParams(NamedList* params) +{} + +/** + * SnmpEngineID + */ +SnmpEngineID::SnmpEngineID() +{ +} + +SnmpEngineID::SnmpEngineID(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +SnmpEngineID::~SnmpEngineID() +{ +} + +int SnmpEngineID::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOctetString(data,&m_SnmpEngineID,true); + if (length < s_SnmpEngineIDSizeMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_SnmpEngineIDSizeMaxSize < length) + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int SnmpEngineID::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOctetString(m_SnmpEngineID,true); + data.append(db); + length = db.length(); + return length; +} + +void SnmpEngineID::getParams(NamedList* params) +{} + +void SnmpEngineID::setParams(NamedList* params) +{} + +/** + * SnmpSecurityModel + */ +SnmpSecurityModel::SnmpSecurityModel() +{ +} + +SnmpSecurityModel::SnmpSecurityModel(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +SnmpSecurityModel::~SnmpSecurityModel() +{ +} + +int SnmpSecurityModel::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeUINT32(data,&m_SnmpSecurityModel,true); + if (m_SnmpSecurityModel < s_SnmpSecurityModelMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_SnmpSecurityModelMaxSize < m_SnmpSecurityModel) + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int SnmpSecurityModel::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeInteger(m_SnmpSecurityModel,true); + data.append(db); + length = db.length(); + return length; +} + +void SnmpSecurityModel::getParams(NamedList* params) +{} + +void SnmpSecurityModel::setParams(NamedList* params) +{} + +/** + * SnmpMessageProcessingModel + */ +SnmpMessageProcessingModel::SnmpMessageProcessingModel() +{ +} + +SnmpMessageProcessingModel::SnmpMessageProcessingModel(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +SnmpMessageProcessingModel::~SnmpMessageProcessingModel() +{ +} + +int SnmpMessageProcessingModel::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeUINT32(data,&m_SnmpMessageProcessingModel,true); + if (m_SnmpMessageProcessingModel < s_SnmpMessageProcessingModelMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_SnmpMessageProcessingModelMaxSize < m_SnmpMessageProcessingModel) + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int SnmpMessageProcessingModel::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeInteger(m_SnmpMessageProcessingModel,true); + data.append(db); + length = db.length(); + return length; +} + +void SnmpMessageProcessingModel::getParams(NamedList* params) +{} + +void SnmpMessageProcessingModel::setParams(NamedList* params) +{} + +/** + * SnmpSecurityLevel + */ +SnmpSecurityLevel::SnmpSecurityLevel() +{ +} + +SnmpSecurityLevel::SnmpSecurityLevel(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +SnmpSecurityLevel::~SnmpSecurityLevel() +{ +} + +int SnmpSecurityLevel::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeINT32(data,&m_SnmpSecurityLevel,true); + if ( m_SnmpSecurityLevel < s_noAuthNoPriv_SnmpSecurityLevel || m_SnmpSecurityLevel > s_authPriv_SnmpSecurityLevel) + return ASNLib::InvalidContentsError; + return length; +} + +int SnmpSecurityLevel::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeInteger(m_SnmpSecurityLevel,true); + data.append(db); + length = db.length(); + return length; +} + +void SnmpSecurityLevel::getParams(NamedList* params) +{} + +void SnmpSecurityLevel::setParams(NamedList* params) +{} + +/** + * SnmpAdminString + */ +SnmpAdminString::SnmpAdminString() +{ +} + +SnmpAdminString::SnmpAdminString(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +SnmpAdminString::~SnmpAdminString() +{ +} + +int SnmpAdminString::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeOctetString(data,&m_SnmpAdminString,true); + if (length < s_SnmpAdminStringSizeMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_SnmpAdminStringSizeMaxSize < length) + DDebug(DebugAll,"Constraint break error"); + return length; +} + +int SnmpAdminString::encode(DataBlock& data) +{ + int length = -1; + const DataBlock db = ASNLib::encodeOctetString(m_SnmpAdminString,true); + data.append(db); + length = db.length(); + return length; +} + +void SnmpAdminString::getParams(NamedList* params) +{} + +void SnmpAdminString::setParams(NamedList* params) +{} + +/** + * UsmSecurityParameters + */ +UsmSecurityParameters::UsmSecurityParameters() +{ +} + +UsmSecurityParameters::UsmSecurityParameters(void* data, int len) +{ + DataBlock db(data,len); + decode(db); +} + +UsmSecurityParameters::~UsmSecurityParameters() +{ +} + +int UsmSecurityParameters::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeSequence(data,true); + if (length < 0) + return length; + length = ASNLib::decodeOctetString(data,&m_msgAuthoritativeEngineID,true); + length = ASNLib::decodeUINT32(data,&m_msgAuthoritativeEngineBoots,true); + if (m_msgAuthoritativeEngineBoots < s_msgAuthoritativeEngineBootsMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_msgAuthoritativeEngineBootsMaxSize < m_msgAuthoritativeEngineBoots) + DDebug(DebugAll,"Constraint break error"); + length = ASNLib::decodeUINT32(data,&m_msgAuthoritativeEngineTime,true); + if (m_msgAuthoritativeEngineTime < s_msgAuthoritativeEngineTimeMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_msgAuthoritativeEngineTimeMaxSize < m_msgAuthoritativeEngineTime) + DDebug(DebugAll,"Constraint break error"); + length = ASNLib::decodeOctetString(data,&m_msgUserName,true); + if (length < s_msgUserNameSizeMinSize) + DDebug(DebugAll,"Constraint break error"); + if (s_msgUserNameSizeMaxSize < length) + DDebug(DebugAll,"Constraint break error"); + length = ASNLib::decodeOctetString(data,&m_msgAuthenticationParameters,true); + length = ASNLib::decodeOctetString(data,&m_msgPrivacyParameters,true); + return length; +} + +int UsmSecurityParameters::encode(DataBlock& data) +{ + int length = -1; + DataBlock seqDb; + DataBlock db; + length = 0; + db = ASNLib::encodeOctetString(m_msgAuthoritativeEngineID,true); + seqDb.append(db); + db = ASNLib::encodeInteger(m_msgAuthoritativeEngineBoots,true); + seqDb.append(db); + db = ASNLib::encodeInteger(m_msgAuthoritativeEngineTime,true); + seqDb.append(db); + db = ASNLib::encodeOctetString(m_msgUserName,true); + seqDb.append(db); + db = ASNLib::encodeOctetString(m_msgAuthenticationParameters,true); + seqDb.append(db); + db = ASNLib::encodeOctetString(m_msgPrivacyParameters,true); + seqDb.append(db); + length = ASNLib::encodeSequence(seqDb,true); + data.append(seqDb); + return length; +} + +void UsmSecurityParameters::getParams(NamedList* params) +{} + +void UsmSecurityParameters::setParams(NamedList* params) +{} + +/** + * SysOREntry + */ +SysOREntry::SysOREntry() +{ + m_sysORDescr = new DisplayString(); + m_sysORUpTime = new TimeStamp(); +} + +SysOREntry::SysOREntry(void* data, int len) +{ + m_sysORDescr = new DisplayString(); + m_sysORUpTime = new TimeStamp(); + + DataBlock db(data,len); + decode(db); +} + +SysOREntry::~SysOREntry() +{ + if (m_sysORDescr) + TelEngine::destruct(m_sysORDescr); + if (m_sysORUpTime) + TelEngine::destruct(m_sysORUpTime); +} + +int SysOREntry::decode(DataBlock& data) +{ + int length = 0; + length = ASNLib::decodeSequence(data,true); + if (length < 0) + return length; + length = ASNLib::decodeINT32(data,&m_sysORIndex,true); + length = ASNLib::decodeOID(data,&m_sysORID,true); + length = m_sysORDescr->decode(data); + length = m_sysORUpTime->decode(data); + return length; +} + +int SysOREntry::encode(DataBlock& data) +{ + int length = -1; + DataBlock seqDb; + DataBlock db; + length = 0; + db = ASNLib::encodeInteger(m_sysORIndex,true); + seqDb.append(db); + db = ASNLib::encodeOID(m_sysORID,true); + seqDb.append(db); + m_sysORDescr->encode(seqDb); + m_sysORUpTime->encode(seqDb); + length = ASNLib::encodeSequence(seqDb,true); + data.append(seqDb); + return length; +} + +void SysOREntry::getParams(NamedList* params) +{} + +void SysOREntry::setParams(NamedList* params) +{} + +} diff --git a/libs/ysnmp/yatesnmp.h b/libs/ysnmp/yatesnmp.h new file mode 100644 index 00000000..061b26d0 --- /dev/null +++ b/libs/ysnmp/yatesnmp.h @@ -0,0 +1,1184 @@ +// generated on Sep 17, 2010 4:11 PM + +#ifndef __YATESNMP_H +#define __YATESNMP_H + +#include + +#ifdef _WINDOWS + +#ifdef LIBYSNMP_EXPORTS +#define YSNMP_API __declspec(dllexport) +#else +#ifndef LIBYSNMP_STATIC +#define YSNMP_API __declspec(dllimport) +#endif +#endif + +#endif /* _WINDOWS */ + +#ifndef YSNMP_API +#define YSNMP_API +#endif + +using namespace TelEngine; + +namespace Snmp { + +class ObjectName; +class ObjectSyntax; +class SimpleSyntax; +class ApplicationSyntax; +class IpAddress; +class Counter32; +class Unsigned32; +class Gauge32; +class TimeTicks; +class Opaque; +class Counter64; +class PDUs; +class GetRequest_PDU; +class GetNextRequest_PDU; +class Response_PDU; +class SetRequest_PDU; +class GetBulkRequest_PDU; +class InformRequest_PDU; +class SNMPv2_Trap_PDU; +class Report_PDU; +class PDU; +class BulkPDU; +class VarBind; +class VarBindList; + +class DisplayString; +class PhysAddress; +class MacAddress; +class TruthValue; +class TestAndIncr; +class AutonomousType; +class InstancePointer; +class VariablePointer; +class RowPointer; +class RowStatus; +class TimeStamp; +class TimeInterval; +class DateAndTime; +class StorageType; +class TDomain; +class TAddress; + +class SNMPv3Message; +class HeaderData; +class ScopedPduData; +class ScopedPDU; + + +class Message; + +class KeyChange; +class UsmUserEntry; + +class SnmpEngineID; +class SnmpSecurityModel; +class SnmpMessageProcessingModel; +class SnmpSecurityLevel; +class SnmpAdminString; + +class UsmSecurityParameters; + +class SysOREntry; + +// defined in SNMPv2-PDU +class YSNMP_API ObjectName : public AsnObject { + YCLASS(ObjectName, AsnObject) +public: + static const int s_type = ASNLib::OBJECT_ID; + ASNObjId m_ObjectName; + ObjectName(); + ObjectName(void* data, int len); + ~ObjectName(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API ObjectSyntax : public AsnObject { + YCLASS(ObjectSyntax, AsnObject) +public: + static const int s_type = ASNLib::CHOICE; + enum ObjectSyntaxType { + SIMPLE, + APPLICATION_WIDE, + }; + int m_choiceType; + SimpleSyntax* m_simple; + ApplicationSyntax* m_application_wide; + + ObjectSyntax(); + ObjectSyntax(void* data, int len); + ~ObjectSyntax(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API SimpleSyntax : public AsnObject { + YCLASS(SimpleSyntax, AsnObject) +public: + static const int s_type = ASNLib::CHOICE; + enum SimpleSyntaxType { + INTEGER_VALUE, + STRING_VALUE, + OBJECTID_VALUE, + }; + int m_choiceType; + int32_t m_integer_value; + static const int32_t s_integer_valueMinSize = -0x80000000; + static const int32_t s_integer_valueMaxSize = 0x7fffffff; + + static const u_int16_t s_string_valueSizeMinSize = 0x0; + static const u_int16_t s_string_valueSizeMaxSize = 0xffff; + OctetString m_string_value; + + ASNObjId m_objectID_value; + + SimpleSyntax(); + SimpleSyntax(void* data, int len); + ~SimpleSyntax(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API ApplicationSyntax : public AsnObject { + YCLASS(ApplicationSyntax, AsnObject) +public: + static const int s_type = ASNLib::CHOICE; + enum ApplicationSyntaxType { + IPADDRESS_VALUE, + COUNTER_VALUE, + TIMETICKS_VALUE, + ARBITRARY_VALUE, + BIG_COUNTER_VALUE, + UNSIGNED_INTEGER_VALUE, + }; + int m_choiceType; + IpAddress* m_ipAddress_value; + Counter32* m_counter_value; + TimeTicks* m_timeticks_value; + Opaque* m_arbitrary_value; + Counter64* m_big_counter_value; + Unsigned32* m_unsigned_integer_value; + + ApplicationSyntax(); + ApplicationSyntax(void* data, int len); + ~ApplicationSyntax(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API IpAddress : public AsnObject { + YCLASS(IpAddress, AsnObject) +public: + static const int s_type = ASNLib::OCTET_STRING; + static const int tag_IpAddress = 0x40; + static const u_int8_t s_IpAddressSize = 0x4; + OctetString m_IpAddress; + + IpAddress(); + IpAddress(void* data, int len); + ~IpAddress(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API Counter32 : public AsnObject { + YCLASS(Counter32, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + static const int tag_Counter32 = 0x41; + u_int32_t m_Counter32; + static const u_int32_t s_Counter32MinSize = 0x0; + static const u_int32_t s_Counter32MaxSize = 0xffffffff; + + Counter32(); + Counter32(void* data, int len); + ~Counter32(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API Unsigned32 : public AsnObject { + YCLASS(Unsigned32, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + static const int tag_Unsigned32 = 0x42; + u_int32_t m_Unsigned32; + static const u_int32_t s_Unsigned32MinSize = 0x0; + static const u_int32_t s_Unsigned32MaxSize = 0xffffffff; + + Unsigned32(); + Unsigned32(void* data, int len); + ~Unsigned32(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API Gauge32 : public AsnObject { + YCLASS(Gauge32, AsnObject) +public: + static const int s_type = ASNLib::DEFINED; + Unsigned32* m_Gauge32; + Gauge32(); + Gauge32(void* data, int len); + ~Gauge32(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API TimeTicks : public AsnObject { + YCLASS(TimeTicks, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + static const int tag_TimeTicks = 0x43; + u_int32_t m_TimeTicks; + static const u_int32_t s_TimeTicksMinSize = 0x0; + static const u_int32_t s_TimeTicksMaxSize = 0xffffffff; + + TimeTicks(); + TimeTicks(void* data, int len); + ~TimeTicks(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API Opaque : public AsnObject { + YCLASS(Opaque, AsnObject) +public: + static const int s_type = ASNLib::OCTET_STRING; + static const int tag_Opaque = 0x44; + OctetString m_Opaque; + + Opaque(); + Opaque(void* data, int len); + ~Opaque(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API Counter64 : public AsnObject { + YCLASS(Counter64, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + static const int tag_Counter64 = 0x46; + u_int64_t m_Counter64; + static const u_int64_t s_Counter64MinSize = 0x0; + static const u_int64_t s_Counter64MaxSize = 0xffffffffffffffffULL; + + Counter64(); + Counter64(void* data, int len); + ~Counter64(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API PDUs : public AsnObject { + YCLASS(PDUs, AsnObject) +public: + static const int s_type = ASNLib::CHOICE; + enum PDUsType { + GET_REQUEST, + GET_NEXT_REQUEST, + GET_BULK_REQUEST, + RESPONSE, + SET_REQUEST, + INFORM_REQUEST, + SNMPV2_TRAP, + REPORT, + }; + int m_choiceType; + GetRequest_PDU* m_get_request; + GetNextRequest_PDU* m_get_next_request; + GetBulkRequest_PDU* m_get_bulk_request; + Response_PDU* m_response; + SetRequest_PDU* m_set_request; + InformRequest_PDU* m_inform_request; + SNMPv2_Trap_PDU* m_snmpV2_trap; + Report_PDU* m_report; + + PDUs(); + PDUs(void* data, int len); + ~PDUs(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API GetRequest_PDU : public AsnObject { + YCLASS(GetRequest_PDU, AsnObject) +public: + static const int s_type = ASNLib::DEFINED; + static const int tag_GetRequest_PDU = 0xa0; + PDU* m_GetRequest_PDU; + GetRequest_PDU(); + GetRequest_PDU(void* data, int len); + ~GetRequest_PDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API GetNextRequest_PDU : public AsnObject { + YCLASS(GetNextRequest_PDU, AsnObject) +public: + static const int s_type = ASNLib::DEFINED; + static const int tag_GetNextRequest_PDU = 0xa1; + PDU* m_GetNextRequest_PDU; + GetNextRequest_PDU(); + GetNextRequest_PDU(void* data, int len); + ~GetNextRequest_PDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API Response_PDU : public AsnObject { + YCLASS(Response_PDU, AsnObject) +public: + static const int s_type = ASNLib::DEFINED; + static const int tag_Response_PDU = 0xa2; + PDU* m_Response_PDU; + Response_PDU(); + Response_PDU(void* data, int len); + ~Response_PDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API SetRequest_PDU : public AsnObject { + YCLASS(SetRequest_PDU, AsnObject) +public: + static const int s_type = ASNLib::DEFINED; + static const int tag_SetRequest_PDU = 0xa3; + PDU* m_SetRequest_PDU; + SetRequest_PDU(); + SetRequest_PDU(void* data, int len); + ~SetRequest_PDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API GetBulkRequest_PDU : public AsnObject { + YCLASS(GetBulkRequest_PDU, AsnObject) +public: + static const int s_type = ASNLib::DEFINED; + static const int tag_GetBulkRequest_PDU = 0xa5; + BulkPDU* m_GetBulkRequest_PDU; + GetBulkRequest_PDU(); + GetBulkRequest_PDU(void* data, int len); + ~GetBulkRequest_PDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API InformRequest_PDU : public AsnObject { + YCLASS(InformRequest_PDU, AsnObject) +public: + static const int s_type = ASNLib::DEFINED; + static const int tag_InformRequest_PDU = 0xa6; + PDU* m_InformRequest_PDU; + InformRequest_PDU(); + InformRequest_PDU(void* data, int len); + ~InformRequest_PDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API SNMPv2_Trap_PDU : public AsnObject { + YCLASS(SNMPv2_Trap_PDU, AsnObject) +public: + static const int s_type = ASNLib::DEFINED; + static const int tag_SNMPv2_Trap_PDU = 0xa7; + PDU* m_SNMPv2_Trap_PDU; + SNMPv2_Trap_PDU(); + SNMPv2_Trap_PDU(void* data, int len); + ~SNMPv2_Trap_PDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API Report_PDU : public AsnObject { + YCLASS(Report_PDU, AsnObject) +public: + static const int s_type = ASNLib::DEFINED; + static const int tag_Report_PDU = 0xa8; + PDU* m_Report_PDU; + Report_PDU(); + Report_PDU(void* data, int len); + ~Report_PDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API PDU : public AsnObject { + YCLASS(PDU, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + int32_t m_request_id; + static const int32_t s_request_idMinSize = -0xccd56a0; + static const int32_t s_request_idMaxSize = 0xccd569f; + + int32_t m_error_status; + static const int32_t s_noError_error_status = 0x0; + static const int32_t s_tooBig_error_status = 0x1; + static const int32_t s_noSuchName_error_status = 0x2; + static const int32_t s_badValue_error_status = 0x3; + static const int32_t s_readOnly_error_status = 0x4; + static const int32_t s_genErr_error_status = 0x5; + static const int32_t s_noAccess_error_status = 0x6; + static const int32_t s_wrongType_error_status = 0x7; + static const int32_t s_wrongLength_error_status = 0x8; + static const int32_t s_wrongEncoding_error_status = 0x9; + static const int32_t s_wrongValue_error_status = 0xa; + static const int32_t s_noCreation_error_status = 0xb; + static const int32_t s_inconsistentValue_error_status = 0xc; + static const int32_t s_resourceUnavailable_error_status = 0xd; + static const int32_t s_commitFailed_error_status = 0xe; + static const int32_t s_undoFailed_error_status = 0xf; + static const int32_t s_authorizationError_error_status = 0x10; + static const int32_t s_notWritable_error_status = 0x11; + static const int32_t s_inconsistentName_error_status = 0x12; + + int32_t m_error_index; + static const int32_t s_error_indexMinSize = 0x0; + static const int32_t s_error_indexMaxSize = 0x7fffffff; + + VarBindList* m_variable_bindings; + + PDU(); + PDU(void* data, int len); + ~PDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API BulkPDU : public AsnObject { + YCLASS(BulkPDU, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + int32_t m_request_id; + static const int32_t s_request_idMinSize = -0xccd56a0; + static const int32_t s_request_idMaxSize = 0xccd569f; + + int32_t m_non_repeaters; + static const int32_t s_non_repeatersMinSize = 0x0; + static const int32_t s_non_repeatersMaxSize = 0x7fffffff; + + int32_t m_max_repetitions; + static const int32_t s_max_repetitionsMinSize = 0x0; + static const int32_t s_max_repetitionsMaxSize = 0x7fffffff; + + VarBindList* m_variable_bindings; + + BulkPDU(); + BulkPDU(void* data, int len); + ~BulkPDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API VarBind : public AsnObject { + YCLASS(VarBind, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + ObjectName* m_name; + enum AsnChoiceTypeType { + VALUE, + UNSPECIFIED, + NOSUCHOBJECT, + NOSUCHINSTANCE, + ENDOFMIBVIEW, + }; + int m_choiceType; + ObjectSyntax* m_value; + int m_unSpecified; + + static const int tag_noSuchObject = 0x80; + int m_noSuchObject; + + static const int tag_noSuchInstance = 0x81; + int m_noSuchInstance; + + static const int tag_endOfMibView = 0x82; + int m_endOfMibView; + + VarBind(); + VarBind(void* data, int len); + ~VarBind(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-PDU +class YSNMP_API VarBindList : public AsnObject { + YCLASS(VarBindList, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + ObjList m_list; + // object list type = VarBind* + + VarBindList(); + VarBindList(void* data, int len); + ~VarBindList(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API DisplayString : public AsnObject { + YCLASS(DisplayString, AsnObject) +public: + static const int s_type = ASNLib::OCTET_STRING; + static const u_int8_t s_DisplayStringSizeMinSize = 0x0; + static const u_int8_t s_DisplayStringSizeMaxSize = 0xff; + OctetString m_DisplayString; + + DisplayString(); + DisplayString(void* data, int len); + ~DisplayString(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API PhysAddress : public AsnObject { + YCLASS(PhysAddress, AsnObject) +public: + static const int s_type = ASNLib::OCTET_STRING; + OctetString m_PhysAddress; + + PhysAddress(); + PhysAddress(void* data, int len); + ~PhysAddress(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API MacAddress : public AsnObject { + YCLASS(MacAddress, AsnObject) +public: + static const int s_type = ASNLib::OCTET_STRING; + static const u_int8_t s_MacAddressSize = 0x6; + OctetString m_MacAddress; + + MacAddress(); + MacAddress(void* data, int len); + ~MacAddress(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API TruthValue : public AsnObject { + YCLASS(TruthValue, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + int32_t m_TruthValue; + static const int32_t s_true_TruthValue = 0x1; + static const int32_t s_false_TruthValue = 0x2; + + TruthValue(); + TruthValue(void* data, int len); + ~TruthValue(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API TestAndIncr : public AsnObject { + YCLASS(TestAndIncr, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + u_int32_t m_TestAndIncr; + static const u_int32_t s_TestAndIncrMinSize = 0x0; + static const u_int32_t s_TestAndIncrMaxSize = 0x7fffffff; + + TestAndIncr(); + TestAndIncr(void* data, int len); + ~TestAndIncr(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API AutonomousType : public AsnObject { + YCLASS(AutonomousType, AsnObject) +public: + static const int s_type = ASNLib::OBJECT_ID; + ASNObjId m_AutonomousType; + AutonomousType(); + AutonomousType(void* data, int len); + ~AutonomousType(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API InstancePointer : public AsnObject { + YCLASS(InstancePointer, AsnObject) +public: + static const int s_type = ASNLib::OBJECT_ID; + ASNObjId m_InstancePointer; + InstancePointer(); + InstancePointer(void* data, int len); + ~InstancePointer(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API VariablePointer : public AsnObject { + YCLASS(VariablePointer, AsnObject) +public: + static const int s_type = ASNLib::OBJECT_ID; + ASNObjId m_VariablePointer; + VariablePointer(); + VariablePointer(void* data, int len); + ~VariablePointer(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API RowPointer : public AsnObject { + YCLASS(RowPointer, AsnObject) +public: + static const int s_type = ASNLib::OBJECT_ID; + ASNObjId m_RowPointer; + RowPointer(); + RowPointer(void* data, int len); + ~RowPointer(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API RowStatus : public AsnObject { + YCLASS(RowStatus, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + int32_t m_RowStatus; + static const int32_t s_active_RowStatus = 0x1; + static const int32_t s_notInService_RowStatus = 0x2; + static const int32_t s_notReady_RowStatus = 0x3; + static const int32_t s_createAndGo_RowStatus = 0x4; + static const int32_t s_createAndWait_RowStatus = 0x5; + static const int32_t s_destroy_RowStatus = 0x6; + + RowStatus(); + RowStatus(void* data, int len); + ~RowStatus(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API TimeStamp : public AsnObject { + YCLASS(TimeStamp, AsnObject) +public: + static const int s_type = ASNLib::DEFINED; + TimeTicks* m_TimeStamp; + TimeStamp(); + TimeStamp(void* data, int len); + ~TimeStamp(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API TimeInterval : public AsnObject { + YCLASS(TimeInterval, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + u_int32_t m_TimeInterval; + static const u_int32_t s_TimeIntervalMinSize = 0x0; + static const u_int32_t s_TimeIntervalMaxSize = 0x7fffffff; + + TimeInterval(); + TimeInterval(void* data, int len); + ~TimeInterval(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API DateAndTime : public AsnObject { + YCLASS(DateAndTime, AsnObject) +public: + static const int s_type = ASNLib::OCTET_STRING; + static const u_int8_t s_DateAndTimeSize_0 = 0x8; + static const u_int8_t s_DateAndTimeSize_1 = 0xb; + OctetString m_DateAndTime; + + DateAndTime(); + DateAndTime(void* data, int len); + ~DateAndTime(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API StorageType : public AsnObject { + YCLASS(StorageType, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + int32_t m_StorageType; + static const int32_t s_other_StorageType = 0x1; + static const int32_t s_volatile_StorageType = 0x2; + static const int32_t s_nonVolatile_StorageType = 0x3; + static const int32_t s_permanent_StorageType = 0x4; + static const int32_t s_readOnly_StorageType = 0x5; + + StorageType(); + StorageType(void* data, int len); + ~StorageType(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API TDomain : public AsnObject { + YCLASS(TDomain, AsnObject) +public: + static const int s_type = ASNLib::OBJECT_ID; + ASNObjId m_TDomain; + TDomain(); + TDomain(void* data, int len); + ~TDomain(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-TC +class YSNMP_API TAddress : public AsnObject { + YCLASS(TAddress, AsnObject) +public: + static const int s_type = ASNLib::OCTET_STRING; + static const u_int8_t s_TAddressSizeMinSize = 0x1; + static const u_int8_t s_TAddressSizeMaxSize = 0xff; + OctetString m_TAddress; + + TAddress(); + TAddress(void* data, int len); + ~TAddress(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv3MessageSyntax +class YSNMP_API SNMPv3Message : public AsnObject { + YCLASS(SNMPv3Message, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + u_int32_t m_msgVersion; + static const u_int32_t s_msgVersionMinSize = 0x0; + static const u_int32_t s_msgVersionMaxSize = 0x7fffffff; + + HeaderData* m_msgGlobalData; + OctetString m_msgSecurityParameters; + + ScopedPduData* m_msgData; + + SNMPv3Message(); + SNMPv3Message(void* data, int len); + ~SNMPv3Message(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv3MessageSyntax +class YSNMP_API HeaderData : public AsnObject { + YCLASS(HeaderData, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + u_int32_t m_msgID; + static const u_int32_t s_msgIDMinSize = 0x0; + static const u_int32_t s_msgIDMaxSize = 0x7fffffff; + + u_int32_t m_msgMaxSize; + static const u_int32_t s_msgMaxSizeMinSize = 0x1e4; + static const u_int32_t s_msgMaxSizeMaxSize = 0x7fffffff; + + static const u_int8_t s_msgFlagsSize = 0x1; + OctetString m_msgFlags; + + u_int32_t m_msgSecurityModel; + static const u_int32_t s_msgSecurityModelMinSize = 0x1; + static const u_int32_t s_msgSecurityModelMaxSize = 0x7fffffff; + + + HeaderData(); + HeaderData(void* data, int len); + ~HeaderData(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv3MessageSyntax +class YSNMP_API ScopedPduData : public AsnObject { + YCLASS(ScopedPduData, AsnObject) +public: + static const int s_type = ASNLib::CHOICE; + enum ScopedPduDataType { + PLAINTEXT, + ENCRYPTEDPDU, + }; + int m_choiceType; + ScopedPDU* m_plaintext; + OctetString m_encryptedPDU; + + + ScopedPduData(); + ScopedPduData(void* data, int len); + ~ScopedPduData(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv3MessageSyntax +class YSNMP_API ScopedPDU : public AsnObject { + YCLASS(ScopedPDU, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + OctetString m_contextEngineID; + + OctetString m_contextName; + + DataBlock m_data; + + ScopedPDU(); + ScopedPDU(void* data, int len); + ~ScopedPDU(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in COMMUNITY-BASED-SNMPv2 +class YSNMP_API Message : public AsnObject { + YCLASS(Message, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + int32_t m_version; + static const int32_t s_version_1_version = 0x0; + static const int32_t s_version_2_version = 0x1; + + OctetString m_community; + + DataBlock m_data; + + Message(); + Message(void* data, int len); + ~Message(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMP-USER-BASED-SM-MIB +class YSNMP_API KeyChange : public AsnObject { + YCLASS(KeyChange, AsnObject) +public: + static const int s_type = ASNLib::OCTET_STRING; + OctetString m_KeyChange; + + KeyChange(); + KeyChange(void* data, int len); + ~KeyChange(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMP-USER-BASED-SM-MIB +class YSNMP_API UsmUserEntry : public AsnObject { + YCLASS(UsmUserEntry, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + SnmpEngineID* m_usmUserEngineID; + SnmpAdminString* m_usmUserName; + SnmpAdminString* m_usmUserSecurityName; + RowPointer* m_usmUserCloneFrom; + AutonomousType* m_usmUserAuthProtocol; + KeyChange* m_usmUserAuthKeyChange; + KeyChange* m_usmUserOwnAuthKeyChange; + AutonomousType* m_usmUserPrivProtocol; + KeyChange* m_usmUserPrivKeyChange; + KeyChange* m_usmUserOwnPrivKeyChange; + OctetString m_usmUserPublic; + + StorageType* m_usmUserStorageType; + RowStatus* m_usmUserStatus; + + UsmUserEntry(); + UsmUserEntry(void* data, int len); + ~UsmUserEntry(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMP-FRAMEWORK-MIB +class YSNMP_API SnmpEngineID : public AsnObject { + YCLASS(SnmpEngineID, AsnObject) +public: + static const int s_type = ASNLib::OCTET_STRING; + static const u_int8_t s_SnmpEngineIDSizeMinSize = 0x5; + static const u_int8_t s_SnmpEngineIDSizeMaxSize = 0x20; + OctetString m_SnmpEngineID; + + SnmpEngineID(); + SnmpEngineID(void* data, int len); + ~SnmpEngineID(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMP-FRAMEWORK-MIB +class YSNMP_API SnmpSecurityModel : public AsnObject { + YCLASS(SnmpSecurityModel, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + u_int32_t m_SnmpSecurityModel; + static const u_int32_t s_SnmpSecurityModelMinSize = 0x0; + static const u_int32_t s_SnmpSecurityModelMaxSize = 0x7fffffff; + + SnmpSecurityModel(); + SnmpSecurityModel(void* data, int len); + ~SnmpSecurityModel(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMP-FRAMEWORK-MIB +class YSNMP_API SnmpMessageProcessingModel : public AsnObject { + YCLASS(SnmpMessageProcessingModel, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + u_int32_t m_SnmpMessageProcessingModel; + static const u_int32_t s_SnmpMessageProcessingModelMinSize = 0x0; + static const u_int32_t s_SnmpMessageProcessingModelMaxSize = 0x7fffffff; + + SnmpMessageProcessingModel(); + SnmpMessageProcessingModel(void* data, int len); + ~SnmpMessageProcessingModel(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMP-FRAMEWORK-MIB +class YSNMP_API SnmpSecurityLevel : public AsnObject { + YCLASS(SnmpSecurityLevel, AsnObject) +public: + static const int s_type = ASNLib::INTEGER; + int32_t m_SnmpSecurityLevel; + static const int32_t s_noAuthNoPriv_SnmpSecurityLevel = 0x1; + static const int32_t s_authNoPriv_SnmpSecurityLevel = 0x2; + static const int32_t s_authPriv_SnmpSecurityLevel = 0x3; + + SnmpSecurityLevel(); + SnmpSecurityLevel(void* data, int len); + ~SnmpSecurityLevel(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMP-FRAMEWORK-MIB +class YSNMP_API SnmpAdminString : public AsnObject { + YCLASS(SnmpAdminString, AsnObject) +public: + static const int s_type = ASNLib::OCTET_STRING; + static const u_int8_t s_SnmpAdminStringSizeMinSize = 0x0; + static const u_int8_t s_SnmpAdminStringSizeMaxSize = 0xff; + OctetString m_SnmpAdminString; + + SnmpAdminString(); + SnmpAdminString(void* data, int len); + ~SnmpAdminString(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in USMSecurityParametersSyntax +class YSNMP_API UsmSecurityParameters : public AsnObject { + YCLASS(UsmSecurityParameters, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + OctetString m_msgAuthoritativeEngineID; + + u_int32_t m_msgAuthoritativeEngineBoots; + static const u_int32_t s_msgAuthoritativeEngineBootsMinSize = 0x0; + static const u_int32_t s_msgAuthoritativeEngineBootsMaxSize = 0x7fffffff; + + u_int32_t m_msgAuthoritativeEngineTime; + static const u_int32_t s_msgAuthoritativeEngineTimeMinSize = 0x0; + static const u_int32_t s_msgAuthoritativeEngineTimeMaxSize = 0x7fffffff; + + static const u_int8_t s_msgUserNameSizeMinSize = 0x0; + static const u_int8_t s_msgUserNameSizeMaxSize = 0x20; + OctetString m_msgUserName; + + OctetString m_msgAuthenticationParameters; + + OctetString m_msgPrivacyParameters; + + + UsmSecurityParameters(); + UsmSecurityParameters(void* data, int len); + ~UsmSecurityParameters(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +// defined in SNMPv2-MIB +class YSNMP_API YSNMP_API SysOREntry : public AsnObject { + YCLASS(SysOREntry, AsnObject) +public: + static const int s_type = ASNLib::SEQUENCE; + int32_t m_sysORIndex; + + ASNObjId m_sysORID; + DisplayString* m_sysORDescr; + TimeStamp* m_sysORUpTime; + + SysOREntry(); + SysOREntry(void* data, int len); + ~SysOREntry(); + int decode(DataBlock& data); + int encode(DataBlock& data); + void getParams(NamedList* params); + void setParams(NamedList* params); +}; + +} + +#endif /* __YATESNMP_H */ diff --git a/modules/Makefile.in b/modules/Makefile.in index 6fc5fea0..ba18c19f 100644 --- a/modules/Makefile.in +++ b/modules/Makefile.in @@ -62,6 +62,8 @@ PROGS := cdrbuild.yate cdrfile.yate regexroute.yate \ server/callcounters.yate \ server/dbwave.yate \ server/yradius.yate \ + server/ysnmpagent.yate \ + server/monitoring.yate \ server/sipfeatures.yate \ server/heartbeat.yate server/clustering.yate \ server/mgcpgw.yate server/mgcpca.yate \ @@ -72,6 +74,7 @@ PROGS := cdrbuild.yate cdrfile.yate regexroute.yate \ server/analogdetect.yate \ client/jabberclient.yate \ callgen.yate analyzer.yate rmanager.yate msgsniff.yate + LIBS := DIRS := client server jabber qt4 @@ -346,6 +349,10 @@ server/sipfeatures.yate: LOCALLIBS = -L../libs/yxml -lyatexml zlibcompress.yate: LOCALFLAGS = $(ZLIB_INC) zlibcompress.yate: LOCALLIBS = $(ZLIB_LIB) +server/ysnmpagent.yate: ../libs/yasn/libyasn.a ../libs/ysnmp/libysnmp.a +server/ysnmpagent.yate: LOCALFLAGS = -I@top_srcdir@/libs/yasn -I@top_srcdir@/libs/ysnmp +server/ysnmpagent.yate: LOCALLIBS = -L../libs/yasn -lyasn -L../libs/ysnmp -lysnmp + ../libyatesig.so ../libs/ysig/libyatesig.a: $(MAKE) -C ../libs/ysig @@ -378,3 +385,9 @@ zlibcompress.yate: LOCALLIBS = $(ZLIB_LIB) ../libs/ypbx/libyatepbx.a: $(MAKE) -C ../libs/ypbx + +../libs/yasn/libyasn.a: + $(MAKE) -C ../libs/yasn + +../libs/ysnmp/libysnmp.a: + $(MAKE) -C ../libs/ysnmp diff --git a/modules/client/jabberclient.cpp b/modules/client/jabberclient.cpp index 8cb5d52e..3144b1d2 100644 --- a/modules/client/jabberclient.cpp +++ b/modules/client/jabberclient.cpp @@ -361,6 +361,9 @@ public: // Check if this module handles a given protocol inline bool canHandleProtocol(const String& proto) { return proto == "jabber"; } + // List accounts + void statusAccounts(String& retVal); + protected: // Inherited methods virtual bool received(Message& msg, int id); @@ -2136,8 +2139,12 @@ bool JBModule::received(Message& msg, int id) if (!target) return Module::received(msg,id); // Handle: status jabberclient stream_name - statusModule(msg.retValue()); - s_jabber->statusDetail(msg.retValue(),target); + if (target == "accounts") + statusAccounts(msg.retValue()); + else { + statusModule(msg.retValue()); + s_jabber->statusDetail(msg.retValue(),target); + } msg.retValue() << "\r\n"; return true; } @@ -2246,13 +2253,17 @@ bool JBModule::commandComplete(Message& msg, const String& partLine, if (word != name()) return Module::commandComplete(msg,partLine,partWord); getWord(line,word); + if (word == "accounts") + return false; if (word) { if (line) return false; s_jabber->completeStreamName(msg.retValue(),partWord); } - else + else { + itemComplete(msg.retValue(),"accounts",partWord); s_jabber->completeStreamName(msg.retValue(),partWord); + } return true; } return Module::commandComplete(msg,partLine,partWord); @@ -2314,6 +2325,35 @@ bool JBModule::commandExecute(String& retVal, const String& line) return true; } +void JBModule::statusAccounts(String& retVal) +{ + DDebug(this,DebugAll,"List the status of all accounts"); + RefPointer list; + s_jabber->getStreamList(list,JBStream::c2s); + if (!list) + return; + String str = ""; + list->lock(); + for (ObjList* o = list->sets().skipNull(); o; o = o->skipNext()) { + JBStreamSet* set = static_cast(o->get()); + for (ObjList* s = set->clients().skipNull(); s; s = s->skipNext()) { + JBClientStream* stream = static_cast(s->get()); + stream->lock(); + str.append(stream->local().bare(),","); + str << "=Jabber|"; + str << stream->stateName(); + stream->unlock(); + } + } + list->unlock(); + list = 0; + if (retVal.null()) { + retVal << "module=" << name(); + retVal << ",format=Protocol|Status;"; + } + retVal << str; +} + }; // anonymous namespace /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/modules/h323chan.cpp b/modules/h323chan.cpp index 07091a96..4fa173d7 100644 --- a/modules/h323chan.cpp +++ b/modules/h323chan.cpp @@ -275,6 +275,8 @@ public: virtual void statusParams(String& str); void cleanup(); YateH323EndPoint* findEndpoint(const String& ep) const; + bool commandComplete(Message& msg, const String& partLine, const String& partWord); + void msgStatus(Message& msg); private: ObjList m_endpoints; }; @@ -282,6 +284,8 @@ private: H323Process* s_process = 0; static H323Driver hplugin; +static String s_statusCmd = "status"; + class YateGatekeeperCall : public H323GatekeeperCall { PCLASSINFO(YateGatekeeperCall, H323GatekeeperCall); @@ -2340,6 +2344,12 @@ H323Driver::~H323Driver() bool H323Driver::received(Message &msg, int id) { + if (id == Status) { + String target = msg.getValue("module"); + if (target && target.startsWith(name()) && !target.startsWith(prefix())) + msgStatus(msg); + return false; + } bool ok = Driver::received(msg,id); if (id == Halt) cleanup(); @@ -2442,6 +2452,7 @@ void H323Driver::initialize() s_process = new H323Process; installRelay(Progress); installRelay(Route); + installRelay(Status); Engine::install(new UserHandler); } int dbg = s_cfg.getIntValue("general","debug"); @@ -2469,6 +2480,41 @@ void H323Driver::initialize() } } +bool H323Driver::commandComplete(Message& msg, const String& partLine, const String& partWord) +{ + String cmd = s_statusCmd; + cmd << " " << name(); + if (partLine == cmd) + itemComplete(msg.retValue(),"accounts",partWord); + else + return Driver::commandComplete(msg,partLine,partWord); + return false; +} + +void H323Driver::msgStatus(Message& msg) +{ + String str = msg.getValue("module"); + while (str.startSkip(name())) { + str.trimBlanks(); + if (str.null()) + break; + if (str.startSkip("accounts")) { + msg.retValue().clear(); + msg.retValue() << "module=" << name(); + msg.retValue() << ",format=Protocol|Status"; + for (ObjList* o = m_endpoints.skipNull(); o; o = o->skipNext()) { + YateH323EndPoint* ep = static_cast(o->get()); + str.append(ep->c_str(),",") << "=H323|"; + str << (ep->IsRegisteredWithGatekeeper() ? "registered" : "not-registered"); + } + msg.retValue().append(str,";"); + msg.retValue() << "\r\n"; + return; + } + } + Driver::msgStatus(msg); +} + }; // anonymous namespace /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/modules/server/mgcpca.cpp b/modules/server/mgcpca.cpp index ee0b5421..776181e0 100644 --- a/modules/server/mgcpca.cpp +++ b/modules/server/mgcpca.cpp @@ -41,10 +41,26 @@ class YMGCPEngine : public MGCPEngine { public: inline YMGCPEngine(const NamedList* params) - : MGCPEngine(false,0,params) + : MGCPEngine(false,0,params), m_timedOutTrans(0), m_timedOutDels(0) { } virtual ~YMGCPEngine(); virtual bool processEvent(MGCPTransaction* trans, MGCPMessage* msg, void* data); + virtual void timeout(MGCPTransaction* trans); + inline unsigned int trTimeouts() + { + unsigned int tmp = m_timedOutTrans; + m_timedOutTrans = 0; + return tmp; + } + inline unsigned int delTimeouts() + { + unsigned int tmp = m_timedOutDels; + m_timedOutDels = 0; + return tmp; + } +private: + unsigned int m_timedOutTrans; + unsigned int m_timedOutDels; }; class MGCPWrapper : public DataEndpoint @@ -270,8 +286,11 @@ public: virtual void statusDetail(String& str); inline SDPParser& parser() { return m_parser; } + virtual void genUpdate(Message& msg); + virtual void appendNotif(NamedString* notif); private: SDPParser m_parser; + NamedList m_notifs; }; YSIGFACTORY2(MGCPSpan); @@ -488,6 +507,24 @@ bool YMGCPEngine::processEvent(MGCPTransaction* trans, MGCPMessage* msg, void* d return false; } +void YMGCPEngine::timeout(MGCPTransaction* tr) +{ + DDebug(&splugin,DebugInfo,"Handle timed out transaction [%p]",tr); + if (!tr) + return; + if (tr->timeout()) { + const MGCPMessage* cmd = tr->initial(); + if (!cmd || !cmd->isCommand()) + return; + if (cmd->name() != "DLCX") + m_timedOutTrans++; + else + m_timedOutDels++; + MGCPEndpointId epId(tr->ep()); + splugin.appendNotif(new NamedString("mgcp_gw_down",epId.host())); + splugin.changed(); + } +} MGCPWrapper::MGCPWrapper(CallEndpoint* conn, const char* media, Message& msg, const char* epId) : DataEndpoint(conn,media), @@ -1830,7 +1867,8 @@ bool DTMFHandler::received(Message& msg) MGCPPlugin::MGCPPlugin() : Module("mgcpca","misc",true), - m_parser("mgcpca","PSTN Circuit") + m_parser("mgcpca","PSTN Circuit"), + m_notifs("notifs") { Output("Loaded module MGCP-CA"); m_parser.debugChain(this); @@ -1944,6 +1982,21 @@ void MGCPPlugin::initialize() m_parser.initialize(cfg.getSection("codecs"),cfg.getSection("hacks")); } +void MGCPPlugin::genUpdate(Message& msg) +{ + Lock l(this); + msg.copyParams(m_notifs); + msg.setParam("tr_timedout",String(s_engine->trTimeouts())); + msg.setParam("del_timedout",String(s_engine->delTimeouts())); + m_notifs.clearParams(); +} + +void MGCPPlugin::appendNotif(NamedString* notif) +{ + Lock l(this); + m_notifs.addParam(notif); +} + }; // anonymous namespace /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/modules/server/monitoring.cpp b/modules/server/monitoring.cpp new file mode 100644 index 00000000..155d44ef --- /dev/null +++ b/modules/server/monitoring.cpp @@ -0,0 +1,3629 @@ +/** + * monitoring.cpp + * This file is part of the YATE Project http://YATE.null.ro + * + * Module for monitoring and gathering information about YATE. + * + * Yet Another Telephony Engine - a fully featured software PBX and IVR + * Copyright (C) 2004-2010 Null Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#define SIP_PORT 5060 + +using namespace TelEngine; + +namespace { + +class Monitor; +class MsgUpdateHandler; +class CdrHandler; +class HangupHandler; +class CallMonitor; + +// structure to hold a counter, a threshold for the counter +// and an alarm for when the threshold had been surpassed +typedef struct { + unsigned int counter; + unsigned int threshold; + bool alarm; +} BaseInfo; + +// container for MGCP transaction information +typedef struct { + BaseInfo transactions; // MGCP transactions information + BaseInfo deletes; // MGCP delete connection transactions that have timed out + u_int64_t reset; // interval after which the data of this structure should be reset + u_int64_t resetTime; // time at which the data should be reset + bool gw_monitor; +} MGCPInfo; + +// container for SIP transaction information +typedef struct { + BaseInfo auths; // SIP authentication requests information + BaseInfo transactions; // SIP timed out transactions information + BaseInfo byes; // SIP timed out BYE transactions information + u_int64_t reset; + u_int64_t resetTime; +} SIPInfo; + +/** + * Class MsgUpdateHandler + * Class for handling a "module.update" message + */ +class MsgUpdateHandler : public MessageHandler +{ +public: + inline MsgUpdateHandler(unsigned int priority = 100) + : MessageHandler("module.update",priority) + { } + virtual ~MsgUpdateHandler() + { } + virtual bool received(Message& msg); +}; + +/** + * Class SnmpMsgHandler + * Class for handling a "monitor.query" message, message used for obtaining information from the monitor + */ +class SnmpMsgHandler : public MessageHandler +{ +public: + inline SnmpMsgHandler(unsigned int priority = 100) + : MessageHandler("monitor.query",priority) + { } + virtual ~SnmpMsgHandler() + { } + virtual bool received(Message& msg); +}; + +/** + * Class HangupHandler + * Handler for "chan.hangup" message" + */ +class HangupHandler : public MessageHandler +{ +public: + inline HangupHandler(unsigned int priority = 100) + : MessageHandler("chan.hangup",priority) + { } + virtual ~HangupHandler() + { } + virtual bool received(Message& msg); +}; + +/** + * Class EngineStartHandler + * Handler for "engine.start" message + */ +class EngineStartHandler : public MessageHandler +{ +public: + inline EngineStartHandler(unsigned int priority = 100) + : MessageHandler("engine.start",priority) + { } + virtual ~EngineStartHandler() + { } + virtual bool received(Message& msg); +}; + +/** + * Class AuthHandler + * Handler for a "user.auth" message. It counts the number of authentication requests + */ +class AuthHandler : public MessageHandler +{ +public: + inline AuthHandler() + : MessageHandler("user.auth",0), + m_count(0) + { } + virtual ~AuthHandler() + { } + virtual inline bool received(Message& msg) + { + String user = msg.getValue("username",""); + if (!user.null()) + m_count++; + return false; + } + // return the number of authentication requests + inline unsigned int getCount() + { return m_count; } +private: + unsigned int m_count; +}; + +/** + * Class RegisterHandler + * Handler for a "user.register" message. It counts the number of register requests + */ +class RegisterHandler : public MessageHandler +{ +public: + inline RegisterHandler() + : MessageHandler("user.register",0), + m_count(0) + { } + virtual ~RegisterHandler() + { } + virtual inline bool received(Message& msg) + { + m_count++; + return false; + } + // return the count + inline unsigned int getCount() + { return m_count; } +private: + unsigned int m_count; +}; + +/** + * Class Cache + * BaseClass for retaining and expiring different type of data + */ +class Cache : public Mutex, public GenObject +{ +public: + enum Info { + COUNT = 1, + INDEX = 2, + }; + inline Cache(const char* name) + : Mutex(false,name), + m_reload(true), m_expireTime(0), m_retainInfoTime(0) + { } + virtual ~Cache(); + + // set the time which is used for increasing the expire time for the cache at each access + inline void setRetainInfoTime(u_int64_t time) + { m_retainInfoTime = time; } + + // get information from the cached data + virtual String getInfo(const String& query, unsigned int& index, TokenDict* dict); + // check if the information has expired + inline bool isExpired() + { return Time::secNow() > m_expireTime; } + // update the time at which the data will expire + inline void updateExpire() + { + m_expireTime = Time::secNow() + m_retainInfoTime; + m_reload = false; + } + +protected: + // load data into this object from a engine.status message + virtual inline bool load() + { return false; } + // discard the cached data + virtual void discard(); + // table containing information about modules obtained from an engine.status message + ObjList m_table; + // flag for reloading + bool m_reload; +private: + // time at which the cached data will expire (in seconds) + u_int64_t m_expireTime; + // value with which increase the expire time at each access + u_int64_t m_retainInfoTime; +}; + +/** + * Class ActiveCallInfo + * Hold data about current calls + */ +class ActiveCallsInfo : public Cache +{ +public: + enum InfoType { + COUNT = 1, // count of current call + INDEX = 2, // index of a call + ID = 3, // id of a call + STATUS = 4, // status of a call + CALLER = 5, // caller party + CALLED = 6, // called party + PEER = 7, // peer(s) channel of a call + DURATION = 8 // call duration + }; + // Constructor + inline ActiveCallsInfo() + : Cache("Monitor::activeCallsInfo") + { } + // Destructor + inline ~ActiveCallsInfo() + { } + // add information about peers by checking the billing ID + String checkPeers(const String& billID, const String& callID); + +protected: + // load data into this object from a engine.status message + bool load(); +}; + +/** + * Class SigInfo + * Base class for handling information from the signalling channel module about signalling components + */ +class SigInfo : public Cache +{ +public: + // enum for types of information + enum InfoType { + COUNT = 1, // number of components + INDEX = 2, // index of a component + ID = 3, // id of a component + STATUS = 4, // status of a component + TYPE = 5, // the type of the component + ALARMS_COUNT = 6, // alarm counter for the component + SKIP = 7 // helper value to skip unnecessary information when parsing the status string + }; + // Constructor + inline SigInfo(const char* name, const TokenDict* dict) + : Cache(name), m_dictionary(dict) + { } + // Destructor + inline ~SigInfo() + { m_table.clear(); } + // update the alarm counter for the component with the given name + void updateAlarmCounter(const String& name); +protected: + // load data into this object from a engine.status message + virtual bool load(); + virtual void discard(); + // dictionary for + const TokenDict* m_dictionary; +}; + +/** + * Class InterfaceInfo + */ +class InterfaceInfo : public SigInfo +{ +public: + // Constructor + inline InterfaceInfo() + : SigInfo("Monitor::ifaceInfo",s_ifacesInfo) + { } + // Destructor + inline ~InterfaceInfo() + { } + // Dictionary for mapping Monitor queries about signalling interfaces + static TokenDict s_ifacesInfo[]; +protected: + // load data into this object from a engine.status message + bool load(); +}; + +/** + * Class LinkInfo + */ +class LinkInfo : public SigInfo +{ +public: + // Constructor + inline LinkInfo() + : SigInfo("Monitor::linkInfo",s_linkInfo) + { } + // Destructor + inline ~LinkInfo() + { } + // dictionary for mapping Monitor queries + static TokenDict s_linkInfo[]; +protected: + // load data into this object from a engine.status message + bool load(); +}; + +/** + * Class LinksetInfo + * Hold status data about signalling linksets + */ +class LinksetInfo : public SigInfo +{ +public: + inline LinksetInfo() + : SigInfo("Monitor::linksetInfo",s_linksetInfo) + { } + inline ~LinksetInfo() + { } + // dictionary for mapping Monitor queries + static TokenDict s_linksetInfo[]; +protected: + // load data into this object from a engine.status message + bool load(); + // parse individual link entries + NamedList* parseLinksetInfo(String& info, const String& link, NamedList* infoFill = 0); + // dictonary for mapping status parameters + static TokenDict s_linksetStatus[]; +}; + +/** + * Class TrunkInfo + * Hold status data about signalling trunks + */ + class TrunkInfo : public SigInfo + { + public: + enum TrunkExtraInfo { + CIRCUITS = 7, + CALLS = 8, + }; + // Constructor + inline TrunkInfo() + : SigInfo("Monitor::trunkInfo",s_trunkInfo) + { } + // Destructor + inline ~TrunkInfo() + { } + // dictionary for mapping Monitor queries + static TokenDict s_trunkInfo[]; +protected: + // load data into this object from a engine.status message + bool load(); + virtual void discard(); + // parse individual trunk entries + NamedList* parseTrunkInfo(String& info,const String& trunkName, NamedList* infoFill = 0); + // dictonary for mapping status parameters + static TokenDict s_trunkStatus[]; + }; + +/** + * Accounts Info + * Cache for account status information + */ +class AccountsInfo : public Cache +{ +public: + // account information type + enum AccountInfoType { + COUNT = 1, + INDEX = 2, + ID = 3, + STATUS = 4, + PROTO = 5 + }; + // Constructor + inline AccountsInfo() + : Cache("Monitor::accountsInfo") + { } + // Destructor + inline ~AccountsInfo() + { } +private: + // load data into this object from a engine.status message + bool load(); +}; + +/** + * EngineInfo - engine status information cache + */ +class EngineInfo : public Cache +{ +public: + enum EngineInfoType { + ENGINE_TYPE = 1, + ENGINE_PLUGINS = 2, + ENGINE_HANDLERS = 3, + ENGINE_MESSAGES = 4, + ENGINE_THREADS = 5, + ENGINE_WORKERS = 6, + ENGINE_MUTEXES = 7, + ENGINE_LOCKS = 8, + ENGINE_SEMAPHORES = 9, + ENGINE_WAITING = 10, + ENGINE_RUNATTEMPT = 11, + ENGINE_NODENAME = 12, + ENGINE_STATE = 13, + }; + // Constructor + inline EngineInfo() + : Cache("Monitor::engineInfo") + { } + // Destructor + inline ~EngineInfo() + { } + // get information from the cached data. Reimplemented from Cache + String getInfo(const String query, unsigned int index, TokenDict* dict); +private: + // load data into this object from a engine.status message + bool load(); + // dictionary for mapping engine status parameters + static TokenDict s_engineInfo[]; +}; + +/** + * ModuleInfo - module information cache + */ +class ModuleInfo : public Cache +{ +public: + enum ModuleInfoType { + COUNT = 1, + INDEX = 2, + MODULE_NAME = 3, + MODULE_TYPE = 4, + MODULE_INFO = 5, + MODULE_FORMAT = 6, + }; + // Constructor + inline ModuleInfo() + : Cache("Monitor::moduleInfo") + { } + // Destructor + inline ~ModuleInfo() + { } +private: + // load data into this object from a engine.status message + bool load(); + // dictionary for mapping engine status parameters + static TokenDict s_moduleInfo[]; +}; + +/** + * DatabaseAccount + * A container which holds status information about a single database account + */ +class DatabaseAccount : public GenObject +{ +public: + enum DbIndex { + TOTAL_IDX = 0, // index for total number of queries + FAILED_IDX = 1, // index for number of failed queries + ERROR_IDX = 2, // index for number of queries returning with an error status + TIME_IDX = 3, // index for time spent executing queries + CONN_IDX = 4, // index for number of active connections + }; + enum DbAlarms { + TOTAL_ALARM = 0x1, + FAILED_ALARM = 0x2, + ERROR_ALARM = 0x4, + EXEC_ALARM = 0x8, + CONNS_ALARM = 0x10, + }; + // enum for information type + enum DbData { + QueriesCount = 1, + FailedCount = 2, + ErrorsCount = 3, + ExecTime = 4, + TooManyAlrm = 5, + TooManyFailedAlrm = 6, + TooManyErrorAlrm = 7, + ExecTooLongAlrm = 8, + NoConnAlrm = 9, + TooManyAlrmCount = 10, + TooManyFailedAlrmCount = 11, + TooManyErrorAlrmCount = 12, + ExecTooLongAlrmCount = 13, + NoConnAlrmCount = 14, + MaxQueries = 15, + MaxFailedQueries = 16, + MaxErrorQueries = 17, + MaxExecTime = 18, + AccountName = 19, + AccountIndex = 20, + }; + // Constructor + DatabaseAccount(const NamedList* cfg); + // Destructor + inline ~DatabaseAccount() + { } + // reimplemented toString() method to make object searcheble in lists + inline const String& toString() const + { return m_name; } + // set the database entry index in the database account table + inline void setIndex(unsigned int index) + { m_index = index; } + // get this account's index + inline unsigned int index() + { return m_index; } + // update the internal data from the list received + void update(const NamedList& info); + // obtain data + const String getInfo(unsigned int query); + // reset internal data + void reset(); +private: + // account name + String m_name; + // index + unsigned int m_index; + // counters for number of queries + unsigned int m_dbCounters[ExecTime]; + // counters for previous interval counter values + unsigned int m_prevDbCounters[ExecTime]; + // alarms set + u_int16_t m_alarms; + // alarm counters + unsigned int m_alarmCounters[CONN_IDX + 1]; + // thresholds for triggering alarms + unsigned int m_thresholds[CONN_IDX]; + // time at which internal data should be reset + unsigned int m_resetTime; + // time to hold on on current data + unsigned int m_resetInterval; +}; + +/** + * DatabaseInfo - database information + * A list of DatabaseAccounts + */ +class DatabaseInfo : public Cache +{ +public: + enum DbInfoType { + Connections = 1, + FailedConns = 2, + Accounts = 3, + }; + // Constructor + inline DatabaseInfo(bool monitored = false) + : Cache("Monitor::dbInfo"), m_monitor(monitored) + { } + // Destructor + inline ~DatabaseInfo() + { m_table.clear(); } + // create and add a new DatabaseAccount created from the received configuration + void addDatabase(NamedList* cfg); + // update the internal data from the received message + void update(const Message& msg); + // get the requested information + String getInfo(const String& query, unsigned int& index, TokenDict* dict); + // try to reset internal data of the table entries + void reset(); +private: + static TokenDict s_databaseInfo[]; + bool load(); + // number of successful and failed connections to databases + unsigned int m_connData[FailedConns]; + bool m_monitor; + + static String s_dbParam; + static String s_totalParam; + static String s_failedParam; + static String s_errorParam; + static String s_hasConnParam; + static String s_timeParam; +}; + +/** + * RTPEntry. Container holding data about a single monitored RTP direction + */ +class RTPEntry : public GenObject +{ +public: + enum RTPInfoType { + Count = 1, + Index = 2, + Direction = 3, + NoAudio = 4, + LostAudio = 5, + PktsLost = 6, + SyncLost = 7, + SeqLost = 8, + WrongSRC = 9, + WrongSSRC = 10, + }; + RTPEntry(String rtpDirection); + ~RTPEntry(); + inline const String& toString() const + { return m_rtpDir; } + // update the entry from the received information + void update(const NamedList& nl); + // reset internal data + void reset(); + // set the index for this entry + inline void setIndex(unsigned int index) + { m_index = index; } + // get info from thins entry + String getInfo(unsigned int query); + // mapping dictionary for Monitor queries + static TokenDict s_rtpInfo[]; +private: + // the RTP direction + String m_rtpDir; + // counters + unsigned int m_counters[WrongSSRC - Direction]; + unsigned int m_index; +}; + +/** + * RTPTable. A list of RTPEntry + */ +class RTPTable : public GenObject +{ +public: + // Constructor + inline RTPTable(String directions, u_int64_t resetTime, bool monitor = false); + // Destructor + inline ~RTPTable() + { m_rtpEntries.clear(); } + // update internal data + void update(Message& msg); + // get the answer to a query + String getInfo(const String& query, const unsigned int& index); + // reset internal data + void reset(); + // check if the internal data should be reset + inline bool shouldReset() + { return Time::secNow() >= m_resetTime; } +private: + // list of RTPEntry + ObjList m_rtpEntries; + Mutex m_rtpMtx; + // interval for how long the data should be kept + u_int64_t m_resetInterval; + // time at which the data should be reset + u_int64_t m_resetTime; + // RTP monitored? + bool m_monitor; +}; + +// A route entry which is monitored for quality of service values +class CallRouteQoS : public GenObject +{ +public: + enum CallStatus { + ANSWERED = 1, + DELIVERED = 2 + }; + enum Indexes { + CURRENT_IDX = 0, + PREVIOUS_IDX = 1, + TOTAL_IDX = 2, + }; + enum ALARMS { + LOW_ASR = 1, + HIGH_ASR = 2, + LOW_NER = 4, + }; + enum QoSNotifs { + ASR_LOW = 1, + ASR_HIGH = 2, + ASR_LOW_ALL = 3, + ASR_HIGH_ALL = 4, + NER_LOW = 5, + NER_LOW_ALL = 6, + ASR = 7, + NER = 8, + ASR_ALL = 9, + NER_ALL = 10, + MIN_ASR = 11, + MAX_ASR = 12, + MIN_NER = 13, + LOW_ASR_COUNT = 14, + HIGH_ASR_COUNT = 15, + LOW_ASR_ALL_COUNT = 16, + HIGH_ASR_ALL_COUNT = 17, + LOW_NER_COUNT = 18, + LOW_NER_ALL_COUNT = 19, + HANGUP = 20, + REJECT = 21, + BUSY = 22, + CANCELLED = 23, + NO_ANSWER = 24, + NO_ROUTE = 25, + NO_CONN = 26, + NO_AUTH = 27, + CONGESTION = 28, + NO_CAUSE = 29, + HANGUP_ALL = 30, + REJECT_ALL = 31, + BUSY_ALL = 32, + CANCELLED_ALL = 33, + NO_ANSWER_ALL = 34, + NO_ROUTE_ALL = 35, + NO_CONN_ALL = 36, + NO_AUTH_ALL = 37, + CONGESTION_ALL = 38, + NAME = 39, + INDEX = 40, + }; + // Constructor + CallRouteQoS(const String direction, const NamedList* cfg = 0); + // Destructor + ~CallRouteQoS(); + // update the call counters and call end reason counters + void update(int type = -1, int endReason = -1); + // update the ASR and NER values + void updateQoS(); + // reset the internal data + void reset(); + // check if the given value has surpassed the given threshold and set the appropriate alarm + void checkForAlarm(int& value, u_int8_t& alarm, const int min, const int max, u_int8_t minAlarm, u_int8_t maxAlarm = 0xff); + // is this route in a state of alarm + bool alarm(); + // get the alarm + const String alarmText(); + // send periodic notifications + void sendNotifs(unsigned int index, bool reset = false); + // get the response to the given query + bool get(int query, String& result); + // reimplemented toString() method to make the object searcheable in lists + inline const String& toString() const + { return m_routeName; } + // set the index of this object + inline void setIndex(unsigned int index) + { m_index = index; } +private: + String m_routeName; + // call hangup reasons counters + unsigned int m_callCounters[NO_CAUSE - HANGUP]; + unsigned int m_callCountersAll[NO_CAUSE - HANGUP]; + + unsigned int m_totalCalls[TOTAL_IDX + 1]; // total calls + unsigned int m_answeredCalls[TOTAL_IDX + 1]; // total answered calls + unsigned int m_delivCalls[TOTAL_IDX + 1]; // total delivered calls + + // alarm flags for avoiding sending multiple times the same alarm + u_int8_t m_alarms; + u_int8_t m_overallAlarms; + + // flags for keeping track if an alarm has been sent or not + u_int8_t m_alarmsSent; + u_int8_t m_overallAlarmsSent; + + // alarm thresholds + int m_minASR; + int m_maxASR; + int m_minNER; + + // alarm counters + unsigned int m_alarmCounters[NER_LOW_ALL + 1]; + // minimum number of calls before starting + unsigned int m_minCalls; + // index in the table + unsigned int m_index; +}; + +/** + * Class CallMonitor + * Monitors number of calls, termination causes, computes statistic data + */ +class CallMonitor : public MessageHandler, public Thread +{ +public: + enum Indexes { + IN_ASR_Idx = 0, + OUT_ASR_Idx = 1, + IN_NER_Idx = 2, + OUT_NER_Idx = 3 + }; + + enum Queries { + INCOMING_CALLS = 9, + OUTGOING_CALLS = 10, + ROUTES_COUNT = 11 + }; + + // constructor + CallMonitor(const NamedList* sect, unsigned int priority = 100); + virtual ~CallMonitor() + { } + // inherited methods + virtual bool received(Message& msg); + virtual bool init(); + virtual void run(); + + // obtain the value from the monitored data + void get(const String& query, const int& index, String& result); + + // get the value of a call counter + bool getCounter(int type, unsigned int& value); + + // send an alarm from a route + void sendAlarmFrom(CallRouteQoS* route); + + // add a route to be monitored + void addRoute(NamedList* sect); + +private: + // interval at which notifications are sent + unsigned int m_checkTime; + // time at which notifications are sent + unsigned int m_notifTime; + // call counters + unsigned int m_inCalls; + unsigned int m_outCalls; + // list of routes + ObjList m_routes; + Mutex m_routesMtx; + bool m_first; + // parameter on which to select routes from call.cdr message + String m_routeParam; + // Directions monitored? + bool m_monitor; +}; + +/** + * Class Monitor + * Monitoring module + */ +class Monitor : public Module +{ +public: + // enum for notification categories + enum Categories { + CALL_MONITOR = 1, + DATABASE = 2, + ALARM_COUNTERS = 3, + ACTIVE_CALLS = 4, + PSTN = 5, + ENGINE = 6, + MODULE = 7, + AUTH_REQUESTS = 8, + REGISTER_REQUESTS = 9, + INTERFACE = 10, + SIP = 11, + RTP = 12, + TRUNKS = 13, + LINKSETS = 14, + LINKS = 15, + IFACES = 16, + ACCOUNTS = 17, + MGCP = 18 + }; + + enum SigTypes { + SS7_MTP3 = 1, + TRUNK = 2, + ISDN = 3, + }; + + enum Cards { + InterfaceDown = 1, + InterfaceUp, + }; + + enum SigNotifs { + TrunkDown = 1, + TrunkUp, + LinksetDown, + LinksetUp, + LinkDown, + LinkUp, + IsdnQ921Down, + IsdnQ921Up + }; + + enum SipNotifs { + TransactTimedOut = 1, + FailedAuths, + ByesTimedOut, + GWTimeout, + GWUp, + DeletesTimedOut + }; + Monitor(); + virtual ~Monitor(); + //inherited methods + virtual void initialize(); + virtual bool received(Message& msg, int id); + bool unload(); + + // handle module.update messages + void update(Message& msg); + // read configuration file + void readConfig(const Configuration& cfg); + // build and send SS7 notifications + void sendSigNotifs(Message& msg); + // build and send physical interface notifications + void sendCardNotifs(Message& msg); + // handle MGCP & SIP status notifications + void checkNotifs(Message& msg, unsigned int type); + // build a notification message + void sendTrap(const String& trap, const String& value, unsigned int index = 0); + // send multiple notifications at once + void sendTraps(const NamedList& traps); + // handle a monitor.query message + bool solveQuery(Message& msg); + // update monitored SIP gateway information + void handleChanHangup(const String& address, int& cause); + bool verifyGateway(const String& address); + // obtain SIP/MGCP transactions info + String getTransactionsInfo(const String& query, const int who); +private: + // message handlers + MsgUpdateHandler* m_msgUpdateHandler; + SnmpMsgHandler* m_snmpMsgHandler; + HangupHandler* m_hangupHandler; + EngineStartHandler* m_startHandler; + CallMonitor* m_callMonitor; + AuthHandler* m_authHandler; + RegisterHandler* m_registerHandler; + bool m_init; + // list of monitored SIP gateways and timed out gateways + ObjList* m_sipMonitoredGws; + ObjList m_timedOutGws; + + // flags if certain monitored information should be passed along in form of notifications + bool m_trunkMon; + bool m_linksetMon; + bool m_linkMon; + bool m_interfaceMon; + bool m_isdnMon; + // caches + ActiveCallsInfo* m_activeCallsCache; + TrunkInfo* m_trunkInfo; + EngineInfo* m_engineInfo; + ModuleInfo* m_moduleInfo; + DatabaseInfo* m_dbInfo; + RTPTable* m_rtpInfo; + + LinksetInfo* m_linksetInfo; + LinkInfo* m_linkInfo; + InterfaceInfo* m_ifaceInfo; + AccountsInfo* m_accountsInfo; +}; + +static int s_yateRun = 0; +static int s_yateRunAlarm = 0; +static String s_nodeState = ""; + +MGCPInfo s_mgcpInfo = { {0, 0, false}, {0, 0, false}, 0, 0, false}; +static SIPInfo s_sipInfo = { {0, 0, false}, {0, 0, false}, {0, 0, false}, 0, 0}; + +static TokenDict s_modules[] = { + {"mysqldb", Monitor::DATABASE}, + {"pgsqldb", Monitor::DATABASE}, + {"sig", Monitor::PSTN}, + {"wanpipe", Monitor::INTERFACE}, + {"zaptel", Monitor::INTERFACE}, + {"Tdm", Monitor::INTERFACE}, + {"sip", Monitor::SIP}, + {"yrtp", Monitor::RTP}, + {"mgcpca", Monitor::MGCP}, + {0,0} +}; + +static TokenDict s_categories[] = { + // database info + {"databaseCount", Monitor::DATABASE}, + {"databaseIndex", Monitor::DATABASE}, + {"databaseAccount", Monitor::DATABASE}, + {"queriesCount", Monitor::DATABASE}, + {"failedQueries", Monitor::DATABASE}, + {"errorQueries", Monitor::DATABASE}, + {"queryExecTime", Monitor::DATABASE}, + {"successfulConnections", Monitor::DATABASE}, + {"failedConnections", Monitor::DATABASE}, + // database alarm counters + {"tooManyQueriesAlarms", Monitor::DATABASE}, + {"tooManyFailedQueriesAlarms", Monitor::DATABASE}, + {"tooManyErrorQueriesAlarms", Monitor::DATABASE}, + {"queryExecTooLongAlarms", Monitor::DATABASE}, + {"noConnectionAlarms", Monitor::DATABASE}, + // database thresholds + {"queriesCountThreshold", Monitor::DATABASE}, + {"failedQueriesThreshold", Monitor::DATABASE}, + {"errorQueriesThreshold", Monitor::DATABASE}, + {"queryExecTimeThreshold", Monitor::DATABASE}, + // QOS + {"qosDirectionsCount", Monitor::CALL_MONITOR}, + {"qosEntryIndex", Monitor::CALL_MONITOR}, + {"qosEntryDirection", Monitor::CALL_MONITOR}, + {"lowASRThreshold", Monitor::CALL_MONITOR}, + {"highASRThreshold", Monitor::CALL_MONITOR}, + {"currentASR", Monitor::CALL_MONITOR}, + {"overallASR", Monitor::CALL_MONITOR}, + {"lowNERThreshold", Monitor::CALL_MONITOR}, + {"currentNER", Monitor::CALL_MONITOR}, + {"overallNER", Monitor::CALL_MONITOR}, + // QOS alarm counters + {"currentLowASRAlarmCount", Monitor::CALL_MONITOR}, + {"overallLowASRAlarmCount", Monitor::CALL_MONITOR}, + {"currentHighASRAlarmCount", Monitor::CALL_MONITOR}, + {"overallHighASRAlarmCount", Monitor::CALL_MONITOR}, + {"currentLowNERAlarmCount", Monitor::CALL_MONITOR}, + {"overallLowNERAlarmCount", Monitor::CALL_MONITOR}, + // call counters + {"incomingCalls", Monitor::CALL_MONITOR}, + {"outgoingCalls", Monitor::CALL_MONITOR}, + + {"currentHangupEndCause", Monitor::CALL_MONITOR}, + {"currentBusyEndCause", Monitor::CALL_MONITOR}, + {"currentRejectedEndCause", Monitor::CALL_MONITOR}, + {"currentCancelledEndCause", Monitor::CALL_MONITOR}, + {"currentNoAnswerEndCause", Monitor::CALL_MONITOR}, + {"currentNoRouteEndCause", Monitor::CALL_MONITOR}, + {"currentNoConnectionEndCause", Monitor::CALL_MONITOR}, + {"currentNoAuthEndCause", Monitor::CALL_MONITOR}, + {"currentCongestionEndCause", Monitor::CALL_MONITOR}, + + {"overallHangupEndCause", Monitor::CALL_MONITOR}, + {"overallBusyEndCause", Monitor::CALL_MONITOR}, + {"overallRejectedEndCause", Monitor::CALL_MONITOR}, + {"overallCancelledEndCause", Monitor::CALL_MONITOR}, + {"overallNoAnswerEndCause", Monitor::CALL_MONITOR}, + {"overallNoRouteEndCause", Monitor::CALL_MONITOR}, + {"overallNoConnectionEndCause", Monitor::CALL_MONITOR}, + {"overallNoAuthEndCause", Monitor::CALL_MONITOR}, + {"overallCongestionEndCause", Monitor::CALL_MONITOR}, + + // connections info + // linksets + {"linksetCount", Monitor::LINKSETS}, + {"linksetIndex", Monitor::LINKSETS}, + {"linksetID", Monitor::LINKSETS}, + {"linksetType", Monitor::LINKSETS}, + {"linksetStatus", Monitor::LINKSETS}, + {"linksetDownAlarms", Monitor::LINKSETS}, + // links + {"linkCount", Monitor::LINKS}, + {"linkIndex", Monitor::LINKS}, + {"linkID", Monitor::LINKS}, + {"linkType", Monitor::LINKS}, + {"linkStatus", Monitor::LINKS}, + {"linkDownAlarms", Monitor::LINKS}, + // interfaces + {"interfacesCount", Monitor::IFACES}, + {"interfaceIndex", Monitor::IFACES}, + {"interfaceID", Monitor::IFACES}, + {"interfaceStatus", Monitor::IFACES}, + {"interfaceDownAlarms", Monitor::IFACES}, + // accounts + {"accountsCount", Monitor::ACCOUNTS}, + {"accountIndex", Monitor::ACCOUNTS}, + {"accountID", Monitor::ACCOUNTS}, + {"accountStatus", Monitor::ACCOUNTS}, + {"accountProtocol", Monitor::ACCOUNTS}, + // active calls info + {"activeCallsCount", Monitor::ACTIVE_CALLS}, + {"callEntryIndex", Monitor::ACTIVE_CALLS}, + {"callEntryID", Monitor::ACTIVE_CALLS}, + {"callEntryStatus", Monitor::ACTIVE_CALLS}, + {"callEntryCaller", Monitor::ACTIVE_CALLS}, + {"callEntryCalled", Monitor::ACTIVE_CALLS}, + {"callEntryPeerChan", Monitor::ACTIVE_CALLS}, + {"callEntryDuration", Monitor::ACTIVE_CALLS}, + // trunk info + {"trunksCount", Monitor::TRUNKS}, + {"trunkIndex", Monitor::TRUNKS}, + {"trunkID", Monitor::TRUNKS}, + {"trunkType", Monitor::TRUNKS}, + {"trunkCircuitCount", Monitor::TRUNKS}, + {"trunkCurrentCallsCount", Monitor::TRUNKS}, + {"trunkDownAlarms", Monitor::TRUNKS}, + // engine info + {"plugins", Monitor::ENGINE}, + {"handlers", Monitor::ENGINE}, + {"messages", Monitor::ENGINE}, + {"threads", Monitor::ENGINE}, + {"workers", Monitor::ENGINE}, + {"mutexes", Monitor::ENGINE}, + {"locks", Monitor::ENGINE}, + {"semaphores", Monitor::ENGINE}, + {"waitingSemaphores", Monitor::ENGINE}, + // node info + {"runAttempt", Monitor::ENGINE}, + {"name", Monitor::ENGINE}, + {"state", Monitor::ENGINE}, + // module info + {"moduleCount", Monitor::MODULE}, + {"moduleIndex", Monitor::MODULE}, + {"moduleName", Monitor::MODULE}, + {"moduleType", Monitor::MODULE}, + {"moduleInfo", Monitor::MODULE}, + // request stats + {"authenticationRequests", Monitor::AUTH_REQUESTS}, + {"registerRequests", Monitor::REGISTER_REQUESTS}, + // rtp stats + {"rtpDirectionsCount", Monitor::RTP}, + {"rtpEntryIndex", Monitor::RTP}, + {"rtpDirection", Monitor::RTP}, + {"noAudioCounter", Monitor::RTP}, + {"lostAudioCounter", Monitor::RTP}, + {"packetsLost", Monitor::RTP}, + {"syncLost", Monitor::RTP}, + {"sequenceNumberLost", Monitor::RTP}, + {"wrongSRC", Monitor::RTP}, + {"wrongSSRC", Monitor::RTP}, + // sip stats + {"transactionsTimedOut", Monitor::SIP}, + {"failedAuths", Monitor::SIP}, + {"byesTimedOut", Monitor::SIP}, + // mgcp stats + {"mgcpTransactionsTimedOut", Monitor::MGCP}, + {"deleteTransactionsTimedOut", Monitor::MGCP}, + {0,0} +}; + +static TokenDict s_callQualityQueries[] = { + // alarms + {"currentLowASR", CallRouteQoS::ASR_LOW}, + {"overallLowASR", CallRouteQoS::ASR_LOW_ALL}, + {"currentHighASR", CallRouteQoS::ASR_HIGH}, + {"overallHighASR", CallRouteQoS::ASR_HIGH_ALL}, + {"currentLowNER", CallRouteQoS::NER_LOW}, + {"overallLowNER", CallRouteQoS::NER_LOW_ALL}, + {"qosEntryDirection", CallRouteQoS::NAME}, + {"qosEntryIndex", CallRouteQoS::INDEX}, + // notifications + {"currentASR", CallRouteQoS::ASR}, + {"overallASR", CallRouteQoS::ASR_ALL}, + {"currentNER", CallRouteQoS::NER}, + {"overallNER", CallRouteQoS::NER_ALL}, + // end cause counters + {"currentHangupEndCause", CallRouteQoS::HANGUP}, + {"currentBusyEndCause", CallRouteQoS::BUSY}, + {"currentRejectedEndCause", CallRouteQoS::REJECT}, + {"currentCancelledEndCause", CallRouteQoS::CANCELLED}, + {"currentNoAnswerEndCause", CallRouteQoS::NO_ANSWER}, + {"currentNoRouteEndCause", CallRouteQoS::NO_ROUTE}, + {"currentNoConnectionEndCause", CallRouteQoS::NO_CONN}, + {"currentNoAuthEndCause", CallRouteQoS::NO_AUTH}, + {"currentCongestionEndCause", CallRouteQoS::CONGESTION}, + + {"overallHangupEndCause", CallRouteQoS::HANGUP_ALL}, + {"overallBusyEndCause", CallRouteQoS::BUSY_ALL}, + {"overallRejectedEndCause", CallRouteQoS::REJECT_ALL}, + {"overallCancelledEndCause", CallRouteQoS::CANCELLED_ALL}, + {"overallNoAnswerEndCause", CallRouteQoS::NO_ANSWER_ALL}, + {"overallNoRouteEndCause", CallRouteQoS::NO_ROUTE_ALL}, + {"overallNoConnectionEndCause", CallRouteQoS::NO_CONN_ALL}, + {"overallNoAuthEndCause", CallRouteQoS::NO_AUTH_ALL}, + {"overallCongestionEndCause", CallRouteQoS::CONGESTION_ALL}, + // thresholds + {"lowASRThreshold", CallRouteQoS::MIN_ASR}, + {"highASRThreshold", CallRouteQoS::MAX_ASR}, + {"lowNERThreshold", CallRouteQoS::MIN_NER}, + // alarm counters + {"currentLowASRAlarmCount", CallRouteQoS::LOW_ASR_COUNT}, + {"currentHighASRAlarmCount", CallRouteQoS::HIGH_ASR_COUNT}, + {"overallLowASRAlarmCount", CallRouteQoS::LOW_ASR_ALL_COUNT}, + {"overallHighASRAlarmCount", CallRouteQoS::HIGH_ASR_ALL_COUNT}, + {"currentLowNERAlarmCount", CallRouteQoS::LOW_NER_COUNT}, + {"overallLowNERAlarmCount", CallRouteQoS::LOW_NER_ALL_COUNT}, + {0,0} +}; +// call end reasons +static TokenDict s_endReasons[] = { + {"User hangup", CallRouteQoS::HANGUP}, + {"Rejected", CallRouteQoS::REJECT}, + {"User busy", CallRouteQoS::BUSY}, + {"Request Terminated", CallRouteQoS::NO_ANSWER}, + {"No route to call target", CallRouteQoS::NO_ROUTE}, + {"Service Unavailable", CallRouteQoS::NO_CONN}, + {"Unauthorized", CallRouteQoS::NO_AUTH}, + {"Cancelled", CallRouteQoS::CANCELLED}, + {"Congestion", CallRouteQoS::CONGESTION}, + {0,0} +}; + +static TokenDict s_callCounterQueries[] = { + {"incomingCalls", CallMonitor::INCOMING_CALLS}, + {"outgoingCalls", CallMonitor::OUTGOING_CALLS}, + {"qosDirectionsCount", CallMonitor::ROUTES_COUNT}, + {0,0} +}; + +static TokenDict s_activeCallInfo[] = { + {"activeCallsCount", ActiveCallsInfo::COUNT}, + {"callEntryID", ActiveCallsInfo::ID}, + {"callEntryIndex", ActiveCallsInfo::INDEX}, + {"callEntryID", ActiveCallsInfo::ID}, + {"callEntryStatus", ActiveCallsInfo::STATUS}, + {"callEntryCaller", ActiveCallsInfo::CALLER}, + {"callEntryCalled", ActiveCallsInfo::CALLED}, + {"callEntryPeerChan", ActiveCallsInfo::PEER}, + {"callEntryDuration", ActiveCallsInfo::DURATION}, + {0,0} +}; + +TokenDict TrunkInfo::s_trunkInfo[] = { + {"trunksCount", TrunkInfo::COUNT}, + {"trunkIndex", TrunkInfo::INDEX}, + {"trunkID", TrunkInfo::ID}, + {"trunkType", TrunkInfo::TYPE}, + {"trunkCircuitCount", TrunkInfo::CIRCUITS}, + {"trunkCurrentCallsCount", TrunkInfo::CALLS}, + {"trunkDownAlarms", TrunkInfo::ALARMS_COUNT}, + {0,0} +}; + +TokenDict TrunkInfo::s_trunkStatus[] = { + {"module", TrunkInfo::SKIP}, + {"trunk", TrunkInfo::ID}, + {"type", TrunkInfo::TYPE}, + {"circuits", TrunkInfo::CIRCUITS}, + {"calls", TrunkInfo::CALLS}, + {0,0} +}; + +static TokenDict s_accountInfo[] = { + {"accountsCount", AccountsInfo::COUNT}, + {"accountIndex", AccountsInfo::INDEX}, + {"accountID", AccountsInfo::ID}, + {"accountStatus", AccountsInfo::STATUS}, + {"accountProtocol", AccountsInfo::PROTO}, + {0,0} +}; + +static TokenDict s_engineQuery[] = { + + {"plugins", EngineInfo::ENGINE_PLUGINS}, + {"handlers", EngineInfo::ENGINE_HANDLERS}, + {"messages", EngineInfo::ENGINE_MESSAGES}, + {"threads", EngineInfo::ENGINE_THREADS}, + {"workers", EngineInfo::ENGINE_WORKERS}, + {"mutexes", EngineInfo::ENGINE_MUTEXES}, + {"locks", EngineInfo::ENGINE_LOCKS}, + {"semaphores", EngineInfo::ENGINE_SEMAPHORES}, + {"waitingSemaphores", EngineInfo::ENGINE_WAITING}, + // node info + {"runAttempt", EngineInfo::ENGINE_RUNATTEMPT}, + {"name", EngineInfo::ENGINE_NODENAME}, + {"state", EngineInfo::ENGINE_STATE}, + {0,0} +}; + +TokenDict EngineInfo::s_engineInfo[] = { + {"type", EngineInfo::ENGINE_TYPE}, + {"plugins", EngineInfo::ENGINE_PLUGINS}, + {"handlers", EngineInfo::ENGINE_HANDLERS}, + {"messages", EngineInfo::ENGINE_MESSAGES}, + {"threads", EngineInfo::ENGINE_THREADS}, + {"workers", EngineInfo::ENGINE_WORKERS}, + {"mutexes", EngineInfo::ENGINE_MUTEXES}, + {"locks", EngineInfo::ENGINE_LOCKS}, + {"semaphores", EngineInfo::ENGINE_SEMAPHORES}, + {"waiting", EngineInfo::ENGINE_WAITING}, + {"runattempt", EngineInfo::ENGINE_RUNATTEMPT}, + {"nodename", EngineInfo::ENGINE_NODENAME}, + {0,0} +}; + +TokenDict ModuleInfo::s_moduleInfo[] = { + {"name", ModuleInfo::MODULE_NAME}, + {"type", ModuleInfo::MODULE_TYPE}, + {"format", ModuleInfo::MODULE_FORMAT}, + {0,0} +}; + +static TokenDict s_moduleQuery[] = { + {"moduleCount", ModuleInfo::COUNT}, + {"moduleIndex", ModuleInfo::INDEX}, + {"moduleName", ModuleInfo::MODULE_NAME}, + {"moduleType", ModuleInfo::MODULE_TYPE}, + {"moduleInfo", ModuleInfo::MODULE_INFO}, + {0,0} +}; + +TokenDict DatabaseInfo::s_databaseInfo[] = { + {"conns", DatabaseInfo::Connections}, + {"failed", DatabaseInfo::FailedConns}, + {0,0} +}; + +static TokenDict s_databaseQuery[] = { + {"successfulConnections", DatabaseInfo::Connections}, + {"failedConnections", DatabaseInfo::FailedConns}, + {"databaseCount", DatabaseInfo::Accounts}, + {0,0} +}; + +static TokenDict s_dbAccountQueries[] = { + {"databaseIndex", DatabaseAccount::AccountIndex}, + {"databaseAccount", DatabaseAccount::AccountName}, + {"queriesCount", DatabaseAccount::QueriesCount}, + {"failedQueries", DatabaseAccount::FailedCount}, + {"errorQueries", DatabaseAccount::ErrorsCount}, + {"queryExecTime", DatabaseAccount::ExecTime}, + // alarms counters + {"tooManyQueriesAlarms", DatabaseAccount::TooManyAlrmCount}, + {"tooManyFailedQueriesAlarms", DatabaseAccount::TooManyFailedAlrmCount}, + {"tooManyErrorQueriesAlarms", DatabaseAccount::TooManyErrorAlrmCount}, + {"queryExecTooLongAlarms", DatabaseAccount::ExecTooLongAlrmCount}, + {"noConnectionAlarms", DatabaseAccount::NoConnAlrmCount}, + // database thresholds + {"queriesCountThreshold", DatabaseAccount::MaxQueries}, + {"failedQueriesThreshold", DatabaseAccount::MaxFailedQueries}, + {"errorQueriesThreshold", DatabaseAccount::MaxErrorQueries}, + {"queryExecTimeThreshold", DatabaseAccount::MaxExecTime}, + // alarm + {"tooManyQueries", DatabaseAccount::TooManyAlrm}, + {"tooManyFailedQueries", DatabaseAccount::TooManyFailedAlrm}, + {"tooManyErrorQueries", DatabaseAccount::TooManyErrorAlrm}, + {"queryExecTimeTooLong", DatabaseAccount::ExecTooLongAlrm}, + {"noConnection", DatabaseAccount::NoConnAlrm}, + {0,0} +}; + +static TokenDict s_dbAccountInfo[] = { + {"maxqueries", DatabaseAccount::MaxQueries}, + {"maxfailed", DatabaseAccount::MaxFailedQueries}, + {"maxerrors", DatabaseAccount::MaxErrorQueries}, + {"maxtimeperquery", DatabaseAccount::MaxExecTime}, + {"total", DatabaseAccount::TOTAL_IDX}, + {"failed", DatabaseAccount::FAILED_IDX}, + {"errorred", DatabaseAccount::ERROR_IDX}, + {"querytime", DatabaseAccount::TIME_IDX}, + {"hasconn", DatabaseAccount::CONN_IDX}, + {0,-1} +}; + +TokenDict RTPEntry::s_rtpInfo[] = { + {"remoteip", RTPEntry::Direction}, + {"noaudio", RTPEntry::NoAudio}, + {"lostaudio", RTPEntry::LostAudio}, + {"lostpkts", RTPEntry::PktsLost}, + {"synclost", RTPEntry::SyncLost}, + {"seqslost", RTPEntry::SeqLost}, + {"wrongsrc", RTPEntry::WrongSRC}, + {"wrongssrc", RTPEntry::WrongSSRC}, + {0,0} +}; + +static TokenDict s_rtpQuery[] = { + {"rtpDirectionsCount", RTPEntry::Count}, + {"rtpEntryIndex", RTPEntry::Index}, + {"rtpDirection", RTPEntry::Direction}, + {"noAudioCounter", RTPEntry::NoAudio}, + {"lostAudioCounter", RTPEntry::LostAudio}, + {"packetsLost", RTPEntry::PktsLost}, + {"syncLost", RTPEntry::SyncLost}, + {"sequenceNumberLost", RTPEntry::SeqLost}, + {"wrongSRC", RTPEntry::WrongSRC}, + {"wrongSSRC", RTPEntry::WrongSSRC}, + {0,0} +}; + +static TokenDict s_sigTypes[] = { + {"ss7-mtp3", Monitor::SS7_MTP3}, + {"trunk", Monitor::TRUNK}, + {"isdn-q921", Monitor::ISDN}, + {0,0} +}; + +static TokenDict s_sipNotifs[] = { + {"transactionsTimedOut", Monitor::TransactTimedOut}, + {"failedAuths", Monitor::FailedAuths}, + {"byesTimedOut", Monitor::ByesTimedOut}, + {"gatewayTimeout", Monitor::GWTimeout}, + {"gatewayUp", Monitor::GWUp}, + {0,0} +}; + +static TokenDict s_mgcpNotifs[] = { + {"mgcpTransactionsTimedOut", Monitor::TransactTimedOut}, + {"deleteTransactionsTimedOut", Monitor::DeletesTimedOut}, + {"mgcpGatewayTimedOut", Monitor::GWTimeout}, + {"mgcpGatewayUp", Monitor::GWUp}, + {0,0} +}; + +static TokenDict s_sigNotifs[] = { + {"trunkDown", Monitor::TrunkDown}, + {"trunkUp", Monitor::TrunkUp}, + {"linksetDown", Monitor::LinksetDown}, + {"linksetUp", Monitor::LinksetUp}, + {"linkUp", Monitor::LinkUp}, + {"linkDown", Monitor::LinkDown}, + {"linkUp", Monitor::LinkUp}, + {"isdnQ921Down", Monitor::IsdnQ921Down}, + {"isdnQ921Up", Monitor::IsdnQ921Up}, + {0,0} +}; + +static TokenDict s_cardInfo[] = { + {"interfaceDown", Monitor::InterfaceDown}, + {"interfaceUp", Monitor::InterfaceUp}, + {0,0} +}; + +static TokenDict s_cardNotifs[] = { + {"interfaceDown", Monitor::InterfaceDown}, + {"interfaceUp", Monitor::InterfaceUp}, + {0,0} +}; + +TokenDict LinksetInfo::s_linksetInfo[] = { + {"linksetCount", LinksetInfo::COUNT}, + {"linksetIndex", LinksetInfo::INDEX}, + {"linksetID", LinksetInfo::ID}, + {"linksetType", LinksetInfo::TYPE}, + {"linksetStatus", LinksetInfo::STATUS}, + {"linksetDownAlarms", LinksetInfo::ALARMS_COUNT}, + {0,0} +}; + +TokenDict LinksetInfo::s_linksetStatus[] = { + {"module", LinksetInfo::SKIP}, + {"component", LinksetInfo::ID}, + {"type", LinksetInfo::TYPE}, + {"status", LinksetInfo::STATUS}, + {0,0} +}; + +TokenDict LinkInfo::s_linkInfo[] = { + {"linkCount", LinkInfo::COUNT}, + {"linkIndex", LinkInfo::INDEX}, + {"linkID", LinkInfo::ID}, + {"linkType", LinkInfo::TYPE}, + {"linkStatus", LinkInfo::STATUS}, + {"linkDownAlarms", LinkInfo::ALARMS_COUNT}, + {0,0} +}; + +TokenDict InterfaceInfo::s_ifacesInfo[] = { + {"interfacesCount", InterfaceInfo::COUNT}, + {"interfaceIndex", InterfaceInfo::INDEX}, + {"interfaceID", InterfaceInfo::ID}, + {"interfaceStatus", InterfaceInfo::STATUS}, + {"interfaceDownAlarms", InterfaceInfo::ALARMS_COUNT}, + {0,0} +}; + +String DatabaseInfo::s_dbParam = "database."; +String DatabaseInfo::s_totalParam = "total."; +String DatabaseInfo::s_failedParam = "failed."; +String DatabaseInfo::s_errorParam = "errorred."; +String DatabaseInfo::s_hasConnParam = "hasconn."; +String DatabaseInfo::s_timeParam = "querytime."; + +INIT_PLUGIN(Monitor); + +UNLOAD_PLUGIN(unloadNow) +{ + if (unloadNow && !__plugin.unload()) + return false; + return true; +} + +// helper function to get rid of new line characters +static void cutNewLine(String& line) { + if (line.endsWith("\n")) + line = line.substr(0,line.length() - 1); + if (line.endsWith("\r")) + line = line.substr(0,line.length() - 1); +} + +/** + * MsgUpdateHandler + */ +bool MsgUpdateHandler::received(Message& msg) +{ + DDebug(__plugin.name(),DebugAll,"MsgUpdateHandler::received()"); + __plugin.update(msg); + return true; +} + +/** + * SnmpMsgHandler + */ +bool SnmpMsgHandler::received(Message& msg) +{ + DDebug(__plugin.name(),DebugAll,"SnmpMsgHandler::received()"); + __plugin.solveQuery(msg); + return true; +} + +/** + * HangupHandler + */ +bool HangupHandler::received(Message& msg) +{ + DDebug(__plugin.name(),DebugAll,"HangupHandler::received()"); + String status = msg.getValue("status",""); + String address = msg.getValue("address",""); + int cause = msg.getIntValue("cause_sip",0); + if (status == "outgoing" && cause && !address.null()) + __plugin.handleChanHangup(address,cause); + if (status == "ringing" && !address.null()) + __plugin.verifyGateway(address); + return false; +} + +/** + * EngineStartHandler + */ +bool EngineStartHandler::received(Message& msg) +{ + DDebug(__plugin.name(),DebugAll,"EngineStartHandler::received()"); + s_yateRun = Engine::runParams().getIntValue("runattempt",0); + if (s_yateRun >= s_yateRunAlarm && s_yateRunAlarm >= 1) { + String notif = lookup(EngineInfo::ENGINE_RUNATTEMPT,s_engineQuery,""); + if (!notif.null()) + __plugin.sendTrap(notif,String(s_yateRun)); + } + return false; +}; + +/** + * Cache + */ +Cache::~Cache() +{ + discard(); +} + +// discard cached data +void Cache::discard() +{ + DDebug(&__plugin,DebugInfo,"Cache::discard() [%p] - dropping cached data",this); + Lock l(this); + m_reload = true; + m_table.clear(); +} + +String Cache::getInfo(const String& query, unsigned int& index, TokenDict* dict) +{ + DDebug(&__plugin,DebugAll,"Cache::getInfo(query='%s',index='%d') [%p]",query.c_str(),index,this); + // if we have data, check if it is still valid + if (isExpired()) + discard(); + else + // if the data has not yet expired, update the expire time + updateExpire(); + + String retStr; + // if the is no data available, obtain it from an engine.status message + if (m_reload && !load()) + return retStr; + + Lock l(this); + // lookup the type of the query, and if it's of type COUNT, return the number of entries + int type = lookup(query,dict,0); + if (type == COUNT) { + retStr += m_table.count(); + return retStr; + } + // if it's not of type COUNT, check if the requested index is within the range of the table + if (index < 1 || index > m_table.count()) + return retStr; + // get the entry of the given index + NamedList* nl = static_cast(m_table[index - 1]); + if (!nl) + return retStr; + // get the result + if (type == INDEX) { + retStr += index; + return retStr; + } + retStr = nl->getValue(query,""); + if (retStr.null()) + retStr = "no info"; + return retStr; +} + +/** + * ActiveCallInfo + */ +// match bill ids to find a call's peer +String ActiveCallsInfo::checkPeers(const String& billID, const String& id) +{ + DDebug(&__plugin,DebugAll,"ActiveCallsInfo::checkPeers('%s','%s')",billID.c_str(),id.c_str()); + if (billID.null()) + return id; + String retPeers; + for(ObjList* o = m_table.skipNull(); o; o = o->skipNext()) { + NamedList* nl = static_cast(o->get()); + if (!nl) + continue; + String otherBillID = nl->getValue("billId",""); + String peers = nl->getValue(lookup(PEER,s_activeCallInfo,0),""); + if (billID == otherBillID) { + String otherID = nl->getValue(lookup(ID,s_activeCallInfo,0),""); + peers.append(id,";"); + retPeers.append(otherID,";"); + } + nl->setParam(lookup(PEER,s_activeCallInfo,0),peers); + } + return retPeers; +} + +// load data into the cache +bool ActiveCallsInfo::load() +{ + DDebug(&__plugin,DebugInfo,"ActiveCallsInfo::load() [%p] - loading data",this); + // emit an engine.status message + Message m("engine.status"); + m.addParam("module","cdrbuild"); + Engine::dispatch(m); + String& status = m.retValue(); + if (TelEngine::null(status)) + return false; + + Lock l(this); + m_table.clear(); + + int pos = status.rfind(';'); + if (pos < 0) + return false; + + status = status.substr(pos + 1); + ObjList* calls = status.split(','); + for (ObjList* o = calls->skipNull(); o; o = o->skipNext()) { + String* callInfo = static_cast(o->get()); + if ( *callInfo == "\r\n") + continue; + if (pos > -1) { + int pos = callInfo->find("="); + NamedList* nl = new NamedList(""); + + String id = callInfo->substr(0,pos); + callInfo->startSkip(String(id + "=")); + nl->setParam(lookup(ID,s_activeCallInfo,0),id); + int i = 0; + String peers; + while (i < 5) { + pos = callInfo->find("|"); + if (pos < -1) + break; + String val = callInfo->substr(0,pos); + callInfo->startSkip(String(val + "|"),false); + int p = -1; + switch (i) { + case 0: + p = val.find("="); + if (p > -1) + val = val.substr(p+1); + nl->setParam(lookup(STATUS,s_activeCallInfo,0),val); + break; + case 1: + val = ( val.null() ? "no info" : val); + nl->setParam(lookup(CALLER,s_activeCallInfo,0),val); + break; + case 2: + val = ( val.null() ? "no info" : val); + nl->setParam(lookup(CALLED,s_activeCallInfo,0),val); + break; + case 3: + peers = checkPeers(val,nl->getValue(lookup(ID,s_activeCallInfo,0),"")); + nl->setParam("billId",val); + nl->setParam(lookup(PEER,s_activeCallInfo,0),peers); + break; + case 4: + cutNewLine(val); + val = ( val.null() ? "no info" : val); + nl->setParam(lookup(DURATION,s_activeCallInfo,0),val); + break; + default: + break; + } + i++; + } + m_table.append(nl); + } + } + TelEngine::destruct(calls); + updateExpire(); + return true; +} + +/** + * InterfaceInfo + */ +// reimplementation of the Cache::discard() function, only resets the status information +void SigInfo::discard() +{ + if (!m_dictionary) + return; + DDebug(&__plugin,DebugInfo,"SigInfo::discard() [%p] - dropping cached data",this); + for (ObjList* o = m_table.skipNull(); o; o = o->skipNext()) { + NamedList* nl = static_cast(o->get()); + nl->setParam(lookup(STATUS,m_dictionary,""),"unknown"); + } + m_reload = true; +} + +// STUB +bool SigInfo::load() +{ + DDebug(&__plugin,DebugWarn,"SigInfo::load() [%p] - STUB",this); + return true; +} + +// increase the counter for number of alarms sent +void SigInfo::updateAlarmCounter(const String& name) +{ + if (!m_dictionary) + return; + DDebug(&__plugin,DebugAll,"SigInfo::updateAlarmCounter('%s') [%p]",name.c_str(),this); + NamedList* nl = static_cast(m_table[name]); + if (!nl) { + load(); + nl = static_cast(m_table[name]); + } + if (nl) { + String param = lookup(ALARMS_COUNT,m_dictionary,""); + if (param.null()) + return; + int val = nl->getIntValue(param,0); + val++; + nl->setParam(param,String(val)); + } +} + +/** + * InterfaceInfo + */ +// parse interface information and store it in the cache +bool InterfaceInfo::load() +{ + DDebug(&__plugin,DebugAll,"InterfaceInfo::load() [%p] - updating internal data",this); + Message m("engine.status"); + m.addParam("module","sig ifaces"); + Engine::dispatch(m); + String& status = m.retValue(); + if (!TelEngine::null(status)) { + cutNewLine(status); + int pos = status.rfind(';'); + if (pos < 0) + return true; + String ifaces = status.substr(pos + 1); + Lock l(this); + ObjList* list = ifaces.split(','); + for (ObjList* o = list->skipNull(); o; o = o->skipNext()) { + String* iface = static_cast(o->get()); + pos = iface->find("="); + if (pos < 0) + continue; + String name = iface->substr(0,pos); + String status = iface->substr(pos+1); + NamedList* nl = static_cast(m_table[name]); + if (!nl) { + nl = new NamedList(name); + nl->setParam(lookup(ID,s_ifacesInfo,""),name); + nl->setParam(lookup(STATUS,s_ifacesInfo,""),status); + m_table.append(nl); + } + else + nl->setParam(lookup(STATUS,s_ifacesInfo,""),status); + if (!nl->getParam(lookup(ALARMS_COUNT,s_ifacesInfo,""))) + nl->setParam(lookup(ALARMS_COUNT,s_ifacesInfo,""),"0"); + } + TelEngine::destruct(list); + } + updateExpire(); + return true; +} + +/** + * LinkInfo + */ +// parse link information +bool LinkInfo::load() +{ + DDebug(&__plugin,DebugAll,"LinkInfo::load() [%p] - loading data",this); + Message m("engine.status"); + m.addParam("module","sig links"); + Engine::dispatch(m); + String& status = m.retValue(); + if (!TelEngine::null(status)) { + cutNewLine(status); + int pos1 = status.rfind(';'); + if (pos1 < 0) + return true; + status = status.substr(pos1 + 1); + Lock l(this); + ObjList* list = status.split(','); + for (ObjList* o = list->skipNull(); o; o = o->skipNext()) { + String* link = static_cast(o->get()); + pos1 = link->find("="); + if (pos1 < 0) + continue; + int pos2 = link->find("|"); + if (pos2 < 0) + continue; + String name = link->substr(0,pos1); + String type = link->substr(pos1 + 1,pos2 - pos1 -1); + String status = link->substr(pos2 + 1); + NamedList* nl = static_cast(m_table[name]); + if (!nl) { + nl = new NamedList(name); + nl->setParam(lookup(ID,s_linkInfo,""),name); + nl->setParam(lookup(TYPE,s_linkInfo,""),type); + nl->setParam(lookup(STATUS,s_linkInfo,""),status); + m_table.append(nl); + } + else + nl->setParam(lookup(STATUS,s_linkInfo,""),status); + if (!nl->getParam(lookup(ALARMS_COUNT,s_linkInfo,""))) + nl->setParam(lookup(ALARMS_COUNT,s_linkInfo,""),"0"); + } + TelEngine::destruct(list); + } + updateExpire(); + return true; +} + +/** + * LinksetInfo + */ +// parse linkset information +bool LinksetInfo::load() +{ + DDebug(&__plugin,DebugAll,"LinksetInfo::load() [%p] - loading data",this); + Message m("engine.command"); + m.addParam("partial","status sig "); + m.addParam("partline","status sig"); + if (!Engine::dispatch(m)) + return false; + String& status = m.retValue(); + if (TelEngine::null(status)) + return false; + + Lock l(this); + ObjList* links = status.split('\t'); + for (ObjList* o = links->skipNull(); o; o = o->skipNext()) { + String* link = static_cast(o->get()); + if (*link == "links" || *link == "ifaces") + continue; + Message msg("engine.status"); + msg.addParam("module",String("sig " + *link)); + Engine::dispatch(msg); + String& linkInfo = msg.retValue(); + if (linkInfo.null()) + continue; + NamedList* nl = static_cast(m_table[*link]); + if (nl) + parseLinksetInfo(linkInfo,*link,nl); + else { + nl = parseLinksetInfo(linkInfo,*link); + if (nl) + m_table.append(nl); + } + } + TelEngine::destruct(links); + updateExpire(); + return true; +} + +// parse the information about a single linkset +NamedList* LinksetInfo::parseLinksetInfo(String& info,const String& link, NamedList* infoFill) +{ + cutNewLine(info); + DDebug(&__plugin,DebugAll,"LinksetInfo::parseLinkInfo(info='%s',link='%s', infoFill='%p') [%p]",info.c_str(),link.c_str(),infoFill,this); + NamedList* nl = (infoFill ? infoFill : new NamedList(link)); + ObjList* params = info.split(',',false); + for (ObjList* o = params->skipNull(); o; o = o->skipNext()) { + String* param = static_cast(o->get()); + int pos = param->find("="); + if (pos < 0) + continue; + String nameParam = param->substr(0,pos); + String valParam = param->substr(pos + 1); + int type = lookup(nameParam,s_linksetStatus,0); + if (type == 0) { + TelEngine::destruct(params); + return 0; + } + nl->setParam(lookup(type,s_linksetInfo,""),valParam); + } + TelEngine::destruct(params); + if (!nl->getParam(lookup(ALARMS_COUNT,s_linksetInfo,""))) + nl->setParam(lookup(ALARMS_COUNT,s_linksetInfo,""),"0"); + return nl; +} + +/** + * TrunkInfo + */ +// reset trunk information +void TrunkInfo::discard() +{ + DDebug(&__plugin,DebugAll,"TrunkInfo::discard() [%p] - dropping cached data",this); + for (ObjList* o = m_table.skipNull(); o; o = o->skipNext()) { + NamedList* nl = static_cast(o->get()); + nl->setParam(lookup(TYPE,s_trunkInfo,""),""); + nl->setParam(lookup(CIRCUITS,s_trunkInfo,""),"0"); + nl->setParam(lookup(CALLS,s_trunkInfo,""),"0"); + } + m_reload = true; +} + +// parse and load trunk information +bool TrunkInfo::load() +{ + DDebug(&__plugin,DebugAll,"TrunkInfo::load() [%p] - loading data",this); + Message m("engine.command"); + m.addParam("partial","status sig "); + m.addParam("partline","status sig"); + if (!Engine::dispatch(m)) + return false; + String& status = m.retValue(); + if (TelEngine::null(status)) + return false; + + Lock l(this); + ObjList* trunks = status.split('\t'); + for (ObjList* o = trunks->skipNull(); o; o = o->skipNext()) { + String* trunk = static_cast(o->get()); + if ((*trunk) == "links" || (*trunk) == "ifaces") + continue; + Message msg("engine.status"); + msg.addParam("module",String("sig " + *trunk)); + Engine::dispatch(msg); + String& trunkInfo = msg.retValue(); + if (trunkInfo.null()) + continue; + NamedList* nl = static_cast(m_table[*trunk]); + if (nl) + parseTrunkInfo(trunkInfo,*trunk,nl); + else { + nl = parseTrunkInfo(trunkInfo,*trunk); + if (nl) + m_table.append(nl); + } + } + TelEngine::destruct(trunks); + // update the expire time + updateExpire(); + return true; +} + +// parse the information for a single trunk +NamedList* TrunkInfo::parseTrunkInfo(String& info, const String& trunk, NamedList* infoFill) +{ + cutNewLine(info); + DDebug(&__plugin,DebugAll,"TrunkInfo::parseTrunkInfo(info='%s',trunk='%s', infoFill='%p') [%p]",info.c_str(),trunk.c_str(),infoFill,this); + NamedList* nl = (infoFill ? infoFill : new NamedList(trunk)); + ObjList* params = info.split(',',false); + for (ObjList* o = params->skipNull(); o; o = o->skipNext()) { + String* param = static_cast(o->get()); + int pos = param->find("="); + if (pos < 0) + continue; + String nameParam = param->substr(0,pos); + String valParam = param->substr(pos + 1); + + int type = lookup(nameParam,s_trunkStatus,0); + if (type == 0) { + TelEngine::destruct(params); + return 0; + } + nl->setParam(lookup(type,s_trunkInfo,""),valParam); + } + TelEngine::destruct(params); + if (!nl->getParam(lookup(ALARMS_COUNT,s_trunkInfo,""))) + nl->setParam(lookup(ALARMS_COUNT,s_trunkInfo,""),"0"); + return nl; +} + +/** + * AccountsInfo + */ +// parse and store accounts information +bool AccountsInfo::load() +{ + DDebug(&__plugin,DebugAll,"AccountsInfo::load() [%p] - loading data",this); + String modules[] = {"sip","h323","iax","jabberclient"}; + + int i = 0; + while (i < 4) { + Message m("engine.status"); + m.setParam("module",modules[i] + " accounts"); + Engine::dispatch(m); + String& status = m.retValue(); + i++; + if (TelEngine::null(status)) + continue; + + cutNewLine(status); + int pos = status.rfind(';'); + if (pos < 0) + continue; + status = status.substr(pos + 1); + Lock l(this); + ObjList* accounts = status.split(',',false); + for (ObjList* o = accounts->skipNull(); o; o = o->skipNext()) { + String* account = static_cast(o->get()); + int pos1 = account->find("="); + int pos2 = account->find("|"); + if (pos1 < 0 || pos2 < 0) + continue; + String name = account->substr(0,pos1); + String proto = account->substr(pos1 + 1,pos2 - pos1 -1); + String status = account->substr(pos2 + 1); + + if (name.null()) + continue; + NamedList* nl = new NamedList(""); + nl->setParam(lookup(ID,s_accountInfo,""),name); + nl->setParam(lookup(STATUS,s_accountInfo,""),status); + nl->setParam(lookup(PROTO,s_accountInfo,""),proto); + m_table.append(nl); + } + + TelEngine::destruct(accounts); + l.drop(); + } + updateExpire(); + return true; +} + +/** + * EngineInfo - engine status information cache + */ +// reimplemented from Cache; obtain the result for a engine query +String EngineInfo::getInfo(const String query, unsigned int index, TokenDict* dict) +{ + DDebug(&__plugin,DebugAll,"EngineInfo::getInfo(%s %d) [%p]",query.c_str(),index,this); + + // if we have data, check if it is still valid + if (isExpired()) + discard(); + else + // if the data has not yet expired, update the expire time + updateExpire(); + + String retStr; + // if the is no data available, obtain it from an engine.status message + if (m_reload && !load()) + return retStr; + + Lock l(this); + int type = lookup(query,s_engineQuery,0); + if (!type) + return retStr; + + if (index > 1) + return retStr; + NamedList* nl = static_cast(m_table[index]); + if (!nl) + return retStr; + if (type == ENGINE_STATE) + return s_nodeState; + retStr = nl->getValue(query,""); + if (retStr.null()) + retStr = "no info"; + return retStr; +} + +// load data into the cache +bool EngineInfo::load() +{ + DDebug(&__plugin,DebugInfo,"EngineInfo::load() [%p] - loading data",this); + // emit an engine.status message + Message m("engine.status"); + m.setParam("module","engine"); + Engine::dispatch(m); + String& status = m.retValue(); + if (TelEngine::null(status)) + return false; + + Lock l(this); + m_table.clear(); + NamedList* nl = new NamedList(""); + ObjList* params = status.split(';'); + for(ObjList* o = params->skipNull(); o; o = o->skipNext()) { + String* strVal = static_cast(o->get()); + ObjList* l = strVal->split(','); + for (ObjList* j = l->skipNull(); j; j = j->skipNext()) { + String* str = static_cast(j->get()); + int pos = str->find("="); + if (pos < 0) + continue; + String param = str->substr(0,pos); + String value = str->substr(pos + 1); + int type = lookup(param,s_engineInfo,0); + if (!type) + continue; + nl->setParam(lookup(type,s_engineQuery,""),value); + } + TelEngine::destruct(l); + } + m_table.append(nl); + TelEngine::destruct(params); + updateExpire(); + return true; +} + +/** + * ModuleInfo + */ +// load data into the cache +bool ModuleInfo::load() +{ + DDebug(&__plugin,DebugInfo,"ModuleInfo::load() [%p] - loading data",this); + // emit an engine.status message + Message m("engine.status"); + m.setParam("details",String::boolText(false)); + Engine::dispatch(m); + String& status = m.retValue(); + if (TelEngine::null(status)) + return false; + + Lock l(this); + m_table.clear(); + + // split the info into lines + ObjList* lines = status.split('\n',false); + for (ObjList* o = lines->skipNull(); o; o = o->skipNext()) { + String* line = static_cast(o->get()); + if (!line) + continue; + cutNewLine(*line); + ObjList* parts = line->split(';'); + NamedList* nl = new NamedList(""); + for (ObjList* p = parts->skipNull(); p; p = p->skipNext()) { + String* str = static_cast(p->get()); + ObjList* paramVal = str->split(','); + String info = ""; + for (ObjList* l = paramVal->skipNull(); l; l = l->skipNext()) { + String* pair = static_cast(l->get()); + int pos = pair->find("="); + if (pos < 0) + continue; + String param = pair->substr(0,pos); + String value = pair->substr(pos + 1); + int type = lookup(param,s_moduleInfo,0); + if (!type) { + info += (info.null() ? pair : String("," + *pair)); + continue; + } + nl->setParam(lookup(type,s_moduleQuery,""),value); + } + nl->setParam(lookup(MODULE_INFO,s_moduleQuery,""),info); + TelEngine::destruct(paramVal); + } + TelEngine::destruct(parts); + if ( String("engine") == nl->getValue(lookup(MODULE_NAME,s_moduleQuery,""),"")) + continue; + m_table.append(nl); + + } + TelEngine::destruct(lines); + updateExpire(); + return true; +} + +/** + * DatabaseAccount - an object holding information about a single monitored database account + */ +// configure a database account for monitoring and initialize internal data +DatabaseAccount::DatabaseAccount(const NamedList* cfg) +{ + if (cfg) { + Debug(&__plugin,DebugInfo,"DatabaseAccount('%s') created for monitoring [%p]",cfg->c_str(),this); + m_name = cfg->c_str(); + m_alarms = 0; + for (int i = 0; i < ExecTime; i++) { + m_dbCounters[i] = 0; + m_prevDbCounters[i] = 0; + } + for (int i = 0; i <= NoConnAlrmCount - TooManyAlrmCount; i++) + m_alarmCounters[i] = 0; + for (int i = 0; i <= MaxExecTime - MaxQueries; i++) + m_thresholds[i] = cfg->getIntValue(lookup(MaxQueries + i,s_dbAccountInfo,""),0); + m_resetInterval = cfg->getIntValue("notiftime",3600); + m_resetTime = Time::secNow() + m_resetInterval; + } +} + +// update internal data from a message received from the sql modules +void DatabaseAccount::update(const NamedList& info) +{ + XDebug(&__plugin,DebugAll,"DatabaseAccount::update() [%p]",this); + for (unsigned int i = 0; i < info.count(); i++) { + NamedString* ns = info.getParam(i); + if (!(ns && *ns)) + continue; + int type = lookup(ns->name(),s_dbAccountInfo,-1); + if (type < 0) + continue; + + u_int16_t alarm = TOTAL_ALARM << (type); + if (type <= TIME_IDX) { + m_dbCounters[type] = ns->toInteger(); + if ((type != TIME_IDX) && (m_dbCounters[type] - m_prevDbCounters[type] >= m_thresholds[type]) && ((m_alarms & alarm) == 0)) { + m_alarms |= alarm; + m_alarmCounters[type]++; + __plugin.sendTrap(lookup(TooManyAlrm + type,s_dbAccountQueries,""),toString(),index()); + } + } + if (type == CONN_IDX) { + if (!ns->toBoolean()) { + if ((m_alarms & alarm) == 0) { + m_alarmCounters[CONN_IDX]++; + m_alarms |= alarm; + __plugin.sendTrap(lookup(NoConnAlrm,s_dbAccountQueries,""),toString(),index()); + } + } + else + m_alarms &= ~alarm; + } + } + // wait to gather all necessary data to compute average time + double execTime = m_dbCounters[TIME_IDX] - m_prevDbCounters[TIME_IDX]; + double queriesNo = (m_dbCounters[TOTAL_IDX] - m_prevDbCounters[TOTAL_IDX]) - (m_dbCounters[FAILED_IDX] - m_prevDbCounters[FAILED_IDX]); + if (queriesNo > 0 && (execTime / queriesNo / 1000) >= m_thresholds[TIME_IDX]) { + if ((m_alarms & EXEC_ALARM) == 0) { + m_alarms |= EXEC_ALARM; + m_alarmCounters[TIME_IDX]++; + __plugin.sendTrap(lookup(ExecTooLongAlrm,s_dbAccountQueries,""),toString(),index()); + } + } + else + m_alarms &= ~EXEC_ALARM; +} + +// obtain information from this entry +const String DatabaseAccount::getInfo(unsigned int query) +{ + DDebug(&__plugin,DebugAll,"DatabaseAccount::getInfo('%s') [%p]",lookup(query,s_dbAccountQueries,""),this); + String ret = ""; + double execTime = 0; + double queriesNo = 0; + switch (query) { + case QueriesCount: + case FailedCount: + case ErrorsCount: + ret << m_dbCounters[query - 1] - m_prevDbCounters[query - 1]; + break; + case ExecTime: + execTime = m_dbCounters[TIME_IDX] - m_prevDbCounters[TIME_IDX]; + queriesNo = (m_dbCounters[TOTAL_IDX] - m_prevDbCounters[TOTAL_IDX]) - (m_dbCounters[FAILED_IDX] - m_prevDbCounters[FAILED_IDX]); + if (queriesNo > 0) + ret << (unsigned int) (execTime / queriesNo / 1000); + else + ret << 0; + break; + case TooManyAlrmCount: + case TooManyFailedAlrmCount: + case TooManyErrorAlrmCount: + case ExecTooLongAlrmCount: + case NoConnAlrmCount: + ret << m_alarmCounters[query - TooManyAlrmCount]; + break; + case MaxQueries: + case MaxFailedQueries: + case MaxErrorQueries: + case MaxExecTime: + ret << m_thresholds[query - MaxQueries]; + break; + case AccountName: + ret = m_name; + break; + case AccountIndex: + ret = index(); + break; + default: + break; + } + return ret; +} + +void DatabaseAccount::reset() +{ + if (Time::secNow() < m_resetTime) + return; + + __plugin.sendTrap(lookup(QueriesCount,s_dbAccountQueries,""),String(m_dbCounters[TOTAL_IDX] - m_prevDbCounters[TOTAL_IDX]),index()); + __plugin.sendTrap(lookup(FailedCount,s_dbAccountQueries,""),String(m_dbCounters[FAILED_IDX] - m_prevDbCounters[FAILED_IDX]),index()); + __plugin.sendTrap(lookup(ErrorsCount,s_dbAccountQueries,""),String(m_dbCounters[ERROR_IDX] - m_prevDbCounters[ERROR_IDX]),index()); + + double execTime = m_dbCounters[TIME_IDX] - m_prevDbCounters[TIME_IDX]; + double queriesNo = (m_dbCounters[TOTAL_IDX] - m_prevDbCounters[TOTAL_IDX]) - (m_dbCounters[FAILED_IDX] - m_prevDbCounters[FAILED_IDX]); + unsigned int time = 0; + if (queriesNo > 0) + time = (unsigned int) (execTime / queriesNo / 1000); + __plugin.sendTrap(lookup(ExecTime,s_dbAccountQueries,""),String(time),index()); + + m_alarms = 0; + for (unsigned int i = 0; i < CONN_IDX; i++) + m_prevDbCounters[i] = m_dbCounters[i]; + + m_resetTime = Time::secNow() + m_resetInterval; +} + +/** + * DatabaseInfo + */ +// parse database status information and store it for all sql modules +bool DatabaseInfo::load() +{ + DDebug(&__plugin,DebugInfo,"DatabaseInfo::load() [%p] - loading data",this); + String modules[] = {"pgsqldb", "mysqldb"}; + unsigned int i = 0; + + for (int i = 0; i < FailedConns; i++) + m_connData[i] = 0; + + while (i < 2) { + Message msg("engine.status"); + msg.addParam("module",modules[i]); + msg.addParam("details","false"); + Engine::dispatch(msg); + String& status = msg.retValue(); + if (!TelEngine::null(status)) { + cutNewLine(status); + /* status example: name=mysqldb,type=database,format=Total|Failed|Errors|AvgExecTime;conns=1,failed=1 */ + int pos = status.rfind(';'); + if (pos < 0) + continue; + String connInfo = status.substr(pos + 1); + if (connInfo.null()) + continue; + ObjList* l = connInfo.split(','); + for (ObjList* j = l->skipNull(); j; j = j->skipNext()) { + String* str = static_cast(j->get()); + pos = str->find("="); + if (pos < 0) + continue; + String param = str->substr(0,pos); + String value = str->substr(pos + 1); + int type = lookup(param,s_databaseInfo,0); + if (!type) + continue; + m_connData[type - 1] += value.toInteger(); + } + TelEngine::destruct(l); + } + i++; + } + updateExpire(); + return true; +} + +// get the answer to a query for the entry with the given index +String DatabaseInfo::getInfo(const String& query, unsigned int& index, TokenDict* dict) +{ + DDebug(&__plugin,DebugAll,"DatabaseInfo::getInfo(query='%s',index='%d',dict='%p') [%p]",query.c_str(),index,dict,this); + // handle a query about an entry in the table + Lock l(this); + int type = lookup(query,s_dbAccountQueries,0); + if (type) { + if (index == 0 || index > m_table.count()) + return ""; + DatabaseAccount* acc = static_cast(m_table[index - 1]); + if (!acc) + return ""; + return acc->getInfo(type); + } + if (!isExpired()) + // if the data has not yet expired, update the expire time + updateExpire(); + // if the is no data available, obtain it from an engine.status message + if (m_reload && !load()) + return ""; + // handle queries about connections + type = lookup(query,s_databaseQuery,0); + switch (type) { + case Accounts: + return String(m_table.count()); + case Connections: + case FailedConns: + return String(m_connData[type - 1]); + default: + break; + } + return ""; +} + +void DatabaseInfo::reset() +{ + Lock l(this); + for (ObjList* o = m_table.skipNull(); o; o = o->skipNext()) { + DatabaseAccount* acc = static_cast(o->get()); + acc->reset(); + } +} + +// create a new DatabaseAccount object for monitoring a database +void DatabaseInfo::addDatabase(NamedList* cfg) +{ + if (!cfg || !m_monitor) + return; + DDebug(&__plugin,DebugInfo,"DatabaseInfo::addDatabase('%s') [%p]",cfg->c_str(),this); + DatabaseAccount* acc = new DatabaseAccount(cfg); + lock(); + m_table.append(acc); + acc->setIndex(m_table.count()); + unlock(); +} + +//update the information for a given account +void DatabaseInfo::update(const Message& msg) +{ + XDebug(&__plugin,DebugInfo,"DatabaseInfo::update()"); + int count = msg.getIntValue("count",0); + for (int i = 0; i < count; i++) { + String str = s_dbParam; + str << i; + String acc = msg.getValue(str); + DatabaseAccount* dbAccount = static_cast(m_table[acc]); + if (!dbAccount) + continue; + NamedList nl(acc); + str = s_totalParam; + str << i; + nl.setParam("total",msg.getValue(str)); + str = s_failedParam; + str << i; + nl.setParam("failed",msg.getValue(str)); + str = s_errorParam; + str << i; + nl.setParam("errorred",msg.getValue(str)); + str = s_hasConnParam; + str << i; + nl.setParam("hasconn",msg.getValue(str)); + str = s_timeParam; + str << i; + nl.setParam("querytime",msg.getValue(str)); + dbAccount->update(nl); + } +} + +/** + * RTPEntry + */ +RTPEntry::RTPEntry(String rtpDirection) + : m_rtpDir(rtpDirection), m_index(0) +{ + Debug(&__plugin,DebugAll,"RTPEntry '%s' created [%p]",rtpDirection.c_str(),this); + reset(); +} + +RTPEntry::~RTPEntry() +{ + Debug(&__plugin,DebugAll,"RTPEntry '%s' destroyed [%p]",m_rtpDir.c_str(),this); +} + +// update the RTP info from the given list +void RTPEntry::update(const NamedList& nl) +{ + DDebug(&__plugin,DebugAll,"RTPEntry::update() name='%s' [%p]",m_rtpDir.c_str(),this); + for (unsigned int i = 0; i < nl.count(); i++) { + NamedString* n = nl.getParam(i); + if (!n) + continue; + int type = lookup(n->name(),s_rtpInfo,0); + if (!type || type < NoAudio) + continue; + m_counters[type - NoAudio] += (*n).toInteger(); + } +} + +// reset counters +void RTPEntry::reset() +{ + DDebug(&__plugin,DebugAll,"RTPEntry::reset() '%s' [%p]",m_rtpDir.c_str(),this); + for (int i = 0; i < WrongSSRC - Direction; i++) + m_counters[i] = 0; +} + +// the the answer to a query about this RTP direction +String RTPEntry::getInfo(unsigned int query) +{ + DDebug(&__plugin,DebugAll,"RTPEntry::getInfo('%s') '%s' [%p]",lookup(query,s_rtpQuery,""),m_rtpDir.c_str(),this); + String retStr = ""; + switch (query) { + case Direction: + retStr << m_rtpDir; + break; + case Index: + retStr << m_index; + break; + case NoAudio: + case LostAudio: + case PktsLost: + case SyncLost: + case SeqLost: + case WrongSRC: + case WrongSSRC: + retStr << m_counters[query - NoAudio]; + break; + default: + break; + } + return retStr; +} + +/** + * RTPTable + */ +RTPTable::RTPTable(String directions, u_int64_t resetTime, bool monitor) + : m_rtpMtx(false,"Monitor::rtpInfo"), m_resetInterval(resetTime), m_monitor(monitor) +{ + Debug(&__plugin,DebugAll,"RTPTable created [%p] direction='%s',resetTime=" FMT64,this,directions.c_str(),m_resetInterval); + // build RTPEntry objects for monitoring RTP directions if monitoring is enabled + if (m_monitor) { + ObjList* l = directions.split(','); + for (ObjList* o = l->skipNull(); o; o = o->skipNext()) { + String* str = static_cast(o->get()); + RTPEntry* entry = new RTPEntry(*str); + m_rtpEntries.append(entry); + entry->setIndex(m_rtpEntries.count()); + } + TelEngine::destruct(l); + } + m_resetTime = Time::secNow() + m_resetInterval; +} + +// update an entry +void RTPTable::update(Message& msg) +{ + XDebug(&__plugin,DebugAll,"RTPTable::update() [%p]",this); + String dir = lookup(RTPEntry::Direction,RTPEntry::s_rtpInfo,""); + if (dir.null()) + dir = "remoteip"; + String rtpDir = msg.getValue(dir,""); + if (rtpDir.null()) + return; + m_rtpMtx.lock(); + RTPEntry* entry = static_cast(m_rtpEntries[rtpDir]); + if (entry) + entry->update(msg); + m_rtpMtx.unlock(); +} + +String RTPTable::getInfo(const String& query, const unsigned int& index) +{ + DDebug(&__plugin,DebugAll,"RTPTable::getInfo(query='%s',index='%u') [%p]",query.c_str(),index,this); + String retStr = ""; + int type = lookup(query,s_rtpQuery,0); + if (!type) + return retStr; + if (type == RTPEntry::Count) + retStr << m_rtpEntries.count(); + else if (index > 0 && index <= m_rtpEntries.count()) { + m_rtpMtx.lock(); + RTPEntry* entry = static_cast(m_rtpEntries[index - 1]); + if (entry) + retStr << entry->getInfo(type); + m_rtpMtx.unlock(); + } + return retStr; +} + +// reset information +void RTPTable::reset() +{ + XDebug(&__plugin,DebugAll,"RTPTable::reset() [%p]",this); + m_rtpMtx.lock(); + for (ObjList* o = m_rtpEntries.skipNull(); o; o = o->skipNext()) { + RTPEntry* e = static_cast(o->get()); + e->reset(); + } + m_rtpMtx.unlock(); + m_resetTime = Time::secNow() + m_resetInterval; +} + +/** + * CallRouteQoS + */ +CallRouteQoS::CallRouteQoS(const String direction, const NamedList* cfg) + : m_routeName(direction) +{ + Debug(&__plugin,DebugAll,"CallRouteQoS [%p] created for route '%s',cfg='%p'",this,direction.c_str(),cfg); + for (int i = 0; i <= NO_CAUSE - HANGUP; i++) { + m_callCounters[i] = 0; + m_callCountersAll[i] = 0; + } + + for (int i = 0; i <= TOTAL_IDX; i++) { + m_totalCalls[i] = 0; + m_answeredCalls[i] = 0; + m_delivCalls[i] = 0; + } + + for (int i = 0; i <= NER_LOW_ALL; i++) + m_alarmCounters[i] = 0; + + m_alarms = 0; + m_overallAlarms = 0; + + m_alarmsSent = 0; + m_overallAlarmsSent = 0; + + m_minCalls = 1; + m_minASR = m_minNER = 0; + m_maxASR = 101; + if (cfg) { + m_minCalls = cfg->getIntValue("mincalls",m_minCalls); + m_minASR = cfg->getIntValue("minASR",m_minASR); + m_maxASR = cfg->getIntValue("maxASR",m_maxASR); + m_minNER = cfg->getIntValue("minNER",m_minNER); + } + m_index = 0; +} + +CallRouteQoS::~CallRouteQoS() +{ + Debug(&__plugin,DebugAll,"CallRouteQoS [%p] destroyed",this); +} + +// update the counters taking into account the type of the call and reason with which the call was ended +void CallRouteQoS::update(int type, int endReason) +{ + DDebug(&__plugin,DebugAll,"CallRouteQoS::update(callType='%d',endReason='%d') [%p] ",type,endReason,this); + m_totalCalls[CURRENT_IDX]++; + m_totalCalls[TOTAL_IDX]++; + switch (type) { + case ANSWERED: + m_answeredCalls[CURRENT_IDX]++; + m_answeredCalls[TOTAL_IDX]++; + break; + case DELIVERED: + m_delivCalls[CURRENT_IDX]++; + m_delivCalls[TOTAL_IDX]++; + break; + default: + break; + } + if (endReason != -1 && endReason >= HANGUP && endReason < NO_CAUSE) { + m_callCounters[endReason - HANGUP]++; + m_callCountersAll[endReason - HANGUP]++; + } +} + +// update the internal ASR/NER values and check for alarms +void CallRouteQoS::updateQoS() +{ + //XDebug(&__plugin,DebugAll,"CallRouteQoS::updateQoS() [%p]",this); + int realASR, totalASR; + if ((m_totalCalls[CURRENT_IDX] != m_totalCalls[PREVIOUS_IDX]) && (m_totalCalls[CURRENT_IDX] >= m_minCalls)) { + + realASR = (double) m_answeredCalls[CURRENT_IDX] / m_totalCalls[CURRENT_IDX] * 100; + checkForAlarm(realASR,m_alarms,m_minASR,m_maxASR,LOW_ASR,HIGH_ASR); + m_totalCalls[PREVIOUS_IDX] = m_totalCalls[CURRENT_IDX]; + + totalASR = (double) m_answeredCalls[TOTAL_IDX] / m_totalCalls[TOTAL_IDX] * 100; + checkForAlarm(totalASR,m_overallAlarms,m_minASR,m_maxASR,LOW_ASR,HIGH_ASR); + + int ner = (double) (m_answeredCalls[CURRENT_IDX] + m_delivCalls[CURRENT_IDX]) / m_totalCalls[CURRENT_IDX] * 100; + checkForAlarm(ner,m_alarms,m_minNER,-1,LOW_NER); + + ner = (double) (m_answeredCalls[TOTAL_IDX] + m_delivCalls[TOTAL_IDX]) / m_totalCalls[TOTAL_IDX] * 100; + checkForAlarm(ner,m_overallAlarms,m_minNER,-1,LOW_NER); + } +} + +// reset counters +void CallRouteQoS::reset() +{ + DDebug(&__plugin,DebugInfo,"CallRoute::reset() [%p]",this); + m_totalCalls[CURRENT_IDX] = m_totalCalls[PREVIOUS_IDX] = 0; + m_answeredCalls[CURRENT_IDX] = m_answeredCalls[PREVIOUS_IDX] = 0; + m_delivCalls[CURRENT_IDX] = m_delivCalls[PREVIOUS_IDX] = 0; + m_alarms = 0; + m_alarmsSent = m_overallAlarmsSent = 0; + for (int i = 0; i < NO_CAUSE - HANGUP; i++) + m_callCounters[i] = 0; +} + +// check a value against a threshold and if necessary set an alarm +void CallRouteQoS::checkForAlarm(int& value, u_int8_t& alarm, const int min, const int max, u_int8_t minAlarm, u_int8_t maxAlarm) +{ + if ( value < 1.05 * min) + alarm |= minAlarm; + else + alarm &= ~minAlarm; + if (max > 0) { + if (value > 0.95 * max) + alarm |= maxAlarm; + else + alarm &= ~maxAlarm; + } +} + +// is this entry in an alarm state? +bool CallRouteQoS::alarm() +{ + if (m_alarms || m_overallAlarms) + return true; + return false; +} + +// get the string version of the alarm and remember that we sent this alarm (avoid sending the same alarm multiple times) +const String CallRouteQoS::alarmText() +{ + String text = ""; + if (m_alarms & LOW_ASR) { + if (!(m_alarmsSent & LOW_ASR)) { + m_alarmsSent |= LOW_ASR; + m_alarmCounters[ASR_LOW]++; + return text = lookup(ASR_LOW,s_callQualityQueries,""); + } + } + else + m_alarmsSent &= ~LOW_ASR; + + if (m_alarms & HIGH_ASR) { + if (!(m_alarmsSent & HIGH_ASR)) { + m_alarmsSent |= HIGH_ASR; + m_alarmCounters[ASR_HIGH]++; + return text = lookup(ASR_HIGH,s_callQualityQueries,""); + } + } + else + m_alarmsSent &= ~HIGH_ASR; + + if (m_alarms & LOW_NER) { + if (!(m_alarmsSent & LOW_NER)) { + m_alarmsSent |= LOW_NER; + m_alarmCounters[NER_LOW]++; + return text = lookup(NER_LOW,s_callQualityQueries,""); + } + } + else + m_alarmsSent &= ~LOW_NER; + + if (m_overallAlarms & LOW_ASR) { + if (!(m_overallAlarmsSent & LOW_ASR)) { + m_overallAlarmsSent |= LOW_ASR; + m_alarmCounters[ASR_LOW_ALL]++; + return text = lookup(ASR_LOW_ALL,s_callQualityQueries,""); + } + } + else + m_overallAlarmsSent &= ~LOW_ASR; + + if (m_overallAlarms & HIGH_ASR) { + if (!(m_overallAlarmsSent & HIGH_ASR)) { + m_overallAlarmsSent |= HIGH_ASR; + m_alarmCounters[ASR_HIGH_ALL]++; + return text = lookup(ASR_HIGH_ALL,s_callQualityQueries,""); + } + } + else + m_overallAlarmsSent &= ~HIGH_ASR; + + if (m_overallAlarms & LOW_NER) { + if (!(m_overallAlarmsSent & LOW_NER)) { + m_overallAlarmsSent |= LOW_NER; + m_alarmCounters[NER_LOW_ALL]++; + return text = lookup(NER_LOW_ALL,s_callQualityQueries,""); + } + } + else + m_overallAlarmsSent &= ~LOW_NER; + return text; +} + +// send periodical notification containing current ASR and NER values +void CallRouteQoS::sendNotifs(unsigned int index, bool rst) +{ + DDebug(&__plugin,DebugInfo,"CallRouteQoS::sendNotifs() - route='%s' reset=%s [%p]",toString().c_str(),String::boolText(rst),this); + // we dont want notifcations if we didn't have the minimum number of calls + if (m_totalCalls[CURRENT_IDX] < m_minCalls) + return; + NamedList nl(""); + String value; + nl.addParam("index",String(index)); + nl.addParam("count","4"); + + for (int i = 0; i < 4; i++) { + String param = "notify."; + param << i; + String paramValue = "value."; + paramValue << i; + nl.addParam(param,lookup(ASR + i,s_callQualityQueries,"")); + get(ASR + i,value); + nl.addParam(paramValue,value); + } + __plugin.sendTraps(nl); + if (rst) + reset(); +} + +// get the value for a query +bool CallRouteQoS::get(int query, String& result) +{ + DDebug(&__plugin,DebugInfo,"CallRouteQoS::get(query='%s') [%p]",lookup(query,s_callQualityQueries,""),this); + int val = 0; + if (query) { + switch (query) { + case ASR: + if (m_totalCalls[CURRENT_IDX]) { + val = (double) m_answeredCalls[CURRENT_IDX] / m_totalCalls[CURRENT_IDX] * 100; + result = String( val); + } + else + result = "0"; + return true; + case NER: + if (m_totalCalls[CURRENT_IDX]) { + val = (double) (m_answeredCalls[CURRENT_IDX] + m_delivCalls[CURRENT_IDX]) / m_totalCalls[CURRENT_IDX] * 100; + result = String(val); + } + else + result = "0"; + return true; + case ASR_ALL: + if (m_totalCalls[TOTAL_IDX]) { + val = (double) m_answeredCalls[TOTAL_IDX] / m_totalCalls[TOTAL_IDX] * 100; + result = String(val); + } + else + result = "0"; + return true; + case NER_ALL: + if (m_totalCalls[TOTAL_IDX]) { + val = (double) (m_answeredCalls[TOTAL_IDX] + m_delivCalls[TOTAL_IDX]) / m_totalCalls[TOTAL_IDX] * 100; + result = String(val); + } + else + result = "0"; + return true; + case MIN_ASR: + result << m_minASR; + return true; + case MAX_ASR: + result << m_maxASR; + return true; + case MIN_NER: + result << m_minNER; + return true; + case LOW_ASR_COUNT: + case HIGH_ASR_COUNT: + case LOW_ASR_ALL_COUNT: + case HIGH_ASR_ALL_COUNT: + case LOW_NER_COUNT: + case LOW_NER_ALL_COUNT: + result << m_alarmCounters[query - LOW_ASR_COUNT + 1]; + return true; + case HANGUP: + case REJECT: + case BUSY: + case CANCELLED: + case NO_ANSWER: + case NO_ROUTE: + case NO_CONN: + case NO_AUTH: + case CONGESTION: + result << m_callCounters[query - HANGUP]; + return true; + case HANGUP_ALL: + case REJECT_ALL: + case BUSY_ALL: + case CANCELLED_ALL: + case NO_ANSWER_ALL: + case NO_ROUTE_ALL: + case NO_CONN_ALL: + case NO_AUTH_ALL: + case CONGESTION_ALL: + result << m_callCountersAll[query - HANGUP_ALL]; + return true; + case NAME: + result << toString(); + return true; + case INDEX: + result << m_index; + return true; + default: + return false; + } + } + return false; +} + +/** + * CallMonitor + */ +CallMonitor::CallMonitor(const NamedList* sect, unsigned int priority) + : MessageHandler("call.cdr",priority), + Thread("Call Monitor") +{ + setFilter("operation","finalize"); + // configs, interval at which the monitored values should be sent as notifications - in seconds + m_checkTime = sect ? sect->getIntValue("time_interval",3600) : 3600; + m_routeParam = sect ? sect->getValue("route","address") : "address"; + m_monitor = sect ? sect->getBoolValue("monitor",false) : false; + + m_notifTime = Time::secNow() + m_checkTime; + m_inCalls = m_outCalls = 0; + // flags + m_first = true; + init(); +} + +bool CallMonitor::init() +{ + return startup(); +} + +// main loop. Update the monitor data, if neccessary, send alarms and/or notifications +void CallMonitor::run() +{ + for (;;) { + check(); + idle(); + bool sendNotif = false; + + if (!m_first && Time::secNow() >= m_notifTime) { + m_notifTime = Time::secNow() + m_checkTime; + sendNotif = true; + } + + m_routesMtx.lock(); + unsigned int index = 0; + for (ObjList* o = m_routes.skipNull(); o; o = o->skipNext()) { + index++; + CallRouteQoS* route = static_cast(o->get()); + route->updateQoS(); + if (route->alarm()) + sendAlarmFrom(route); + if (sendNotif) + route->sendNotifs(index,true); + } + if (sendNotif) + sendNotif = false; + + if (m_first) + m_first = false; + m_routesMtx.unlock(); + } +} + +// add a route to be monitored +void CallMonitor::addRoute(NamedList* cfg) +{ + if (!m_monitor || !cfg) + return; + CallRouteQoS* route = new CallRouteQoS(*cfg,cfg); + m_routesMtx.lock(); + m_routes.append(route); + route->setIndex(m_routes.count()); + m_routesMtx.unlock(); +} + +// send an alarm received from a route +void CallMonitor::sendAlarmFrom(CallRouteQoS* route) +{ + if (!route) + return; + String alarm = route->alarmText(); + if (!alarm.null()) + __plugin.sendTrap(alarm,route->toString()); +} + +// extract from a call.cdr message call information and update the monitor data +bool CallMonitor::received(Message& msg) +{ + DDebug(__plugin.name(),DebugAll,"CdrHandler::received()"); + String operation = msg.getValue("operation",""); + if (operation != "finalize") + return false; + + if (m_routeParam.null() || !msg.getParam(m_routeParam)) + return false; + + String status = msg.getValue("status",""); + int code = -1; + if (status == "answered") + code = CallRouteQoS::ANSWERED; + if (status == "ringing" || status == "accepted") + code = CallRouteQoS::DELIVERED; + + String direction = msg.getValue("direction",""); + if (direction == "incoming") + m_inCalls++; + else if (direction == "outgoing") + m_outCalls++; + + String reason = msg.getValue("reason",""); + int type = lookup(reason,s_endReasons,0); + int reasonEnd = -1; + if (type <= CallRouteQoS::NO_ANSWER) { + if (direction == "outgoing") + reasonEnd = type; + } + else + reasonEnd = type; + + String routeStr = msg.getValue(m_routeParam,""); + if (routeStr.null()) + return false; + if ( m_routeParam == "address") { + int pos = routeStr.find(":"); + if (pos > -1) + routeStr = routeStr.substr(0,pos); + } + m_routesMtx.lock(); + CallRouteQoS* route = static_cast(m_routes[routeStr]); + if (!route) { + m_routesMtx.unlock(); + return false; + } + + route->update(code,reasonEnd); + m_routesMtx.unlock(); + return false; +} + +// get a value from the call counters +bool CallMonitor::getCounter(int type, unsigned int& value) +{ + DDebug(__plugin.name(),DebugAll,"CallMonitor::getCounter(%s)",lookup(type,s_callCounterQueries,"")); + if (type == 0 || type > ROUTES_COUNT) + return false; + switch (type) { + case INCOMING_CALLS: + value = m_inCalls; + break; + case OUTGOING_CALLS: + value = m_outCalls; + break; + case ROUTES_COUNT: + value = m_routes.count(); + break; + default: + return false; + } + return true; +} + +// obtain call monitor specific data +void CallMonitor::get(const String& query, const int& index, String& result) +{ + DDebug(__plugin.name(),DebugAll,"CallMonitor::get(%s,%d)",query.c_str(),index); + if (index > 0) { + CallRouteQoS* route = static_cast(m_routes[index - 1]); + if (!route) + return; + + int type = lookup(query,s_callQualityQueries,0); + if (type && route->get(type,result)) + return; + } + int type = lookup(query,s_callCounterQueries,0); + unsigned int value = 0; + if (getCounter(type,value)) { + result += value; + return; + } +} + +/** + * Monitor + */ +Monitor::Monitor() + : Module("monitoring","misc"), + m_msgUpdateHandler(0), + m_snmpMsgHandler(0), + m_startHandler(0), + m_callMonitor(0), + m_authHandler(0), + m_registerHandler(0), + m_init(false), + m_sipMonitoredGws(0), + m_trunkMon(false), + m_linksetMon(false), + m_linkMon(false), + m_interfaceMon(false), + m_isdnMon(false), + m_activeCallsCache(0), + m_trunkInfo(0), + m_engineInfo(0), + m_moduleInfo(0), + m_dbInfo(0), + m_rtpInfo(0), + m_linksetInfo(0), + m_linkInfo(0), + m_ifaceInfo(0), + m_accountsInfo(0) +{ + Output("Loaded module Monitoring"); +} + +Monitor::~Monitor() +{ + Output("Unloaded module Monitoring"); +} + +bool Monitor::unload() +{ + DDebug(this,DebugAll,"::unload()"); + if (!lock(500000)) + return false; + TelEngine::destruct(m_moduleInfo); + TelEngine::destruct(m_engineInfo); + TelEngine::destruct(m_activeCallsCache); + TelEngine::destruct(m_linkInfo); + TelEngine::destruct(m_linksetInfo); + TelEngine::destruct(m_trunkInfo); + Engine::uninstall(m_msgUpdateHandler); + Engine::uninstall(m_snmpMsgHandler); + Engine::uninstall(m_startHandler); + Engine::uninstall(m_authHandler); + Engine::uninstall(m_registerHandler); + Engine::uninstall(m_hangupHandler); + if (m_callMonitor) + Engine::uninstall(m_callMonitor); + unlock(); + return true; +} + +void Monitor::initialize() +{ + Output("Initializing module Monitoring"); + + // read configuration + Configuration cfg(Engine::configFile("monitoring")); + + if (!m_init) { + m_init = true; + setup(); + installRelay(Halt); + installRelay(Timer); + + s_nodeState = "active"; + + if (!m_msgUpdateHandler) { + m_msgUpdateHandler = new MsgUpdateHandler(); + Engine::install(m_msgUpdateHandler); + } + if (!m_snmpMsgHandler) { + m_snmpMsgHandler = new SnmpMsgHandler(); + Engine::install(m_snmpMsgHandler); + } + if (!m_hangupHandler) { + m_hangupHandler = new HangupHandler(); + Engine::install(m_hangupHandler); + } + if (!m_startHandler) { + m_startHandler = new EngineStartHandler(); + Engine::install(m_startHandler); + } + if (!m_authHandler) { + m_authHandler = new AuthHandler(); + Engine::install(m_authHandler); + } + if (!m_registerHandler) { + m_registerHandler = new RegisterHandler(); + Engine::install(m_registerHandler); + } + // build a call monitor + if (!m_callMonitor) { + NamedList* asrCfg = cfg.getSection("call_qos"); + m_callMonitor = new CallMonitor(asrCfg); + Engine::install(m_callMonitor); + } + + int cacheFor = cfg.getIntValue("general","cache",1); + if (!m_activeCallsCache) { + m_activeCallsCache = new ActiveCallsInfo(); + m_activeCallsCache->setRetainInfoTime(cacheFor);//seconds + } + if (!m_trunkInfo) { + m_trunkInfo = new TrunkInfo(); + m_trunkInfo->setRetainInfoTime(cacheFor);//seconds + } + if (!m_linksetInfo) { + m_linksetInfo = new LinksetInfo(); + m_linksetInfo->setRetainInfoTime(cacheFor);//seconds + } + if (!m_linkInfo) { + m_linkInfo = new LinkInfo(); + m_linkInfo->setRetainInfoTime(cacheFor);//seconds + } + if (!m_ifaceInfo) { + m_ifaceInfo = new InterfaceInfo(); + m_ifaceInfo->setRetainInfoTime(cacheFor);//seconds + } + if (!m_accountsInfo) { + m_accountsInfo = new AccountsInfo(); + m_accountsInfo->setRetainInfoTime(cacheFor);//seconds + } + if (!m_engineInfo) { + m_engineInfo = new EngineInfo(); + m_engineInfo->setRetainInfoTime(cacheFor);//seconds + } + if (!m_moduleInfo) { + m_moduleInfo = new ModuleInfo(); + m_moduleInfo->setRetainInfoTime(cacheFor);//seconds + } + if (!m_dbInfo) { + bool enable = cfg.getBoolValue("database","monitor",false); + m_dbInfo = new DatabaseInfo(enable); + m_dbInfo->setRetainInfoTime(cacheFor); + } + readConfig(cfg); + } +} + +void Monitor::readConfig(const Configuration& cfg) +{ + // get the threshold for yate restart alarm + s_yateRunAlarm = cfg.getIntValue("general","restart_alarm",1); + + // read configs for database monitoring (they type=database, the name of the section is the database account) + for (unsigned int i = 0; i < cfg.sections(); i++) { + NamedList* sec = cfg.getSection(i); + if (!sec || (*sec == "general")) + continue; + String type = sec->getValue("type",""); + if (type.null()) + continue; + if (type == "database" && m_dbInfo) + m_dbInfo->addDatabase(sec); + if (type == "call_qos" && m_callMonitor) + m_callMonitor->addRoute(sec); + } + // read config for SIP monitoring + String gw = cfg.getValue("sip","gateways",""); + if (!gw.null()) { + m_sipMonitoredGws = gw.split(';',false); + for (ObjList* o = m_sipMonitoredGws->skipNull(); o; o = o->skipNext()) { + String* addr = static_cast(o->get()); + int pos = addr->find(":"); + if (pos == -1) { + addr->append(":" + String(SIP_PORT)); + m_sipMonitoredGws->remove(o); + m_sipMonitoredGws->set(addr); + } + else { + String tmp = addr->substr(pos+1); + if (tmp.null()) + addr->append(":" + String(SIP_PORT)); + } + } + } + s_sipInfo.auths.threshold = cfg.getIntValue("sip","max_failed_auths",0); + s_sipInfo.transactions.threshold = cfg.getIntValue("sip","max_transaction_timeouts",0); + s_sipInfo.byes.threshold = cfg.getIntValue("sip","max_byes_timeouts",0); + s_sipInfo.reset = cfg.getIntValue("sip","reset_time",0); + if (s_sipInfo.reset) + s_sipInfo.resetTime = Time::secNow() + s_sipInfo.reset; + + // read SS7 monitoring + bool sigEnable = cfg.getBoolValue("sig","monitor",false); + m_trunkMon = cfg.getBoolValue("sig","trunk",sigEnable); + m_interfaceMon = cfg.getBoolValue("sig","interface",sigEnable); + m_linksetMon = cfg.getBoolValue("sig","linkset",sigEnable); + m_linkMon = cfg.getBoolValue("sig","link",sigEnable); + m_isdnMon = cfg.getBoolValue("sig","isdn",sigEnable); + + // read RTP monitoring + bool enable = cfg.getBoolValue("rtp","monitor",false); + int resetTime = cfg.getIntValue("rtp","reset_interval",3600); + String directions = cfg.getValue("rtp","rtp_directions",""); + m_rtpInfo = new RTPTable(directions,resetTime,enable); + + // read config for MGCP monitoring + s_mgcpInfo.transactions.threshold = cfg.getIntValue("mgcp","max_transaction_timeouts",0); + s_mgcpInfo.deletes.threshold = cfg.getIntValue("mgcp","max_deletes_timeouts",0); + s_mgcpInfo.reset = cfg.getIntValue("mgcp","reset_time",0); + s_mgcpInfo.gw_monitor = cfg.getBoolValue("mgcp","gw_monitor",false); + if (s_mgcpInfo.reset) + s_mgcpInfo.resetTime = Time::secNow() + s_mgcpInfo.reset; + +} + +// handle messages received by the module +bool Monitor::received(Message& msg, int id) +{ + if (id == Halt) { + DDebug(this,DebugInfo,"::received() - Halt Message"); + s_nodeState = "exiting"; + unload(); + } + if (id == Timer) { + if (m_rtpInfo && m_rtpInfo->shouldReset()) + m_rtpInfo->reset(); + if (s_sipInfo.resetTime && s_sipInfo.resetTime > Time::secNow()) { + s_sipInfo.auths.counter = s_sipInfo.transactions.counter = s_sipInfo.byes.counter = 0; + s_sipInfo.auths.alarm = s_sipInfo.transactions.alarm = s_sipInfo.byes.alarm = false; + s_sipInfo.resetTime = Time::secNow() + s_sipInfo.reset; + } + if (s_mgcpInfo.resetTime && s_mgcpInfo.resetTime > Time::secNow()) { + s_mgcpInfo.transactions.counter = s_mgcpInfo.deletes.counter = 0; + s_mgcpInfo.transactions.alarm = s_mgcpInfo.deletes.alarm = false; + s_mgcpInfo.resetTime = Time::secNow() + s_mgcpInfo.reset; + } + if (m_dbInfo) + m_dbInfo->reset(); + } + return Module::received(msg,id); +} + +// handle module.update messages +void Monitor::update(Message& msg) +{ + String module = msg.getValue("module",""); + XDebug(this,DebugAll,"Monitor::update() from module=%s",module.c_str()); + int type = lookup(module,s_modules,0); + switch (type) { + case DATABASE: + if (m_dbInfo) + m_dbInfo->update(msg); + break; + case PSTN: + sendSigNotifs(msg); + break; + case INTERFACE: + sendCardNotifs(msg); + break; + case RTP: + if (m_rtpInfo) + m_rtpInfo->update(msg); + break; + case SIP: + case MGCP: + checkNotifs(msg,type); + break; + default: + break; + } +} + +// build SS7 notifications +void Monitor::sendSigNotifs(Message& msg) +{ + String type = msg.getValue("type",""); + if (type.null()) + return; + // get the type of the notification + int t = lookup(type,s_sigTypes,0); + String name = msg.getValue("from"); + DDebug(this,DebugInfo,"Monitor::sendSigNotifs() - send notification from '%s'",name.c_str()); + bool up = false; + String notif; + // build trap information + switch (t) { + case ISDN: + up = msg.getBoolValue("operational"); + if (m_isdnMon) + sendTrap(lookup((up ? IsdnQ921Up : IsdnQ921Down),s_sigNotifs),name); + if (!up && m_linkInfo) + m_linkInfo->updateAlarmCounter(name); + break; + case SS7_MTP3: + up = msg.getBoolValue("operational",false); + if (m_linksetMon) { + sendTrap(lookup((up ? LinksetUp : LinksetDown),s_sigNotifs),name); + if (!up && m_linksetInfo) + m_linksetInfo->updateAlarmCounter(name); + } + notif = msg.getValue("link",""); + if (m_linkMon && !notif.null()) { + up = msg.getBoolValue("linkup",false); + sendTrap(lookup(( up ? LinkUp : LinkDown),s_sigNotifs),notif); + if (!up && m_linkInfo) + m_linkInfo->updateAlarmCounter(name); + } + break; + case TRUNK: + up = msg.getBoolValue("operational",true); + if (m_trunkMon) + sendTrap(lookup(( up ? TrunkUp : TrunkDown),s_sigNotifs),name); + if (!up && m_trunkInfo) + m_trunkInfo->updateAlarmCounter(name); + break; + default: + break; + } +} + +// build and send trap from interface notifications +void Monitor::sendCardNotifs(Message& msg) +{ + String device = msg.getValue("interface",""); + DDebug(this,DebugInfo,"::sendCardNotifs() - a notification from interface '%s' has been received",device.c_str()); + if (device.null()) + return; + String notif = msg.getValue("notify",""); + int type = lookup(notif,s_cardInfo,0); + if (type && m_interfaceMon) { + String trap = lookup(type,s_cardNotifs,""); + if (!trap.null()) + sendTrap(notif,device); + if (m_ifaceInfo) + m_ifaceInfo->updateAlarmCounter(device); + } +} + +// helper function to check for a value against a threshold from a BaseInfo struct and send a notification if necessary +static void checkInfo(unsigned int count, BaseInfo& info, unsigned int alrm, TokenDict* dict) +{ + DDebug(&__plugin,DebugAll,"checkInfo(count=%d, info={threshold=%d,alarm=%s,counter=%d})", + count,info.threshold,String::boolText(info.alarm),info.counter); + info.counter += count; + if (info.threshold && !info.alarm && info.counter >= info.threshold) { + info.alarm = true; + String notif = lookup(alrm,dict,""); + if (!notif.null()) + __plugin.sendTrap(notif,String(info.counter)); + } +} + +// handle module.update messages from SIP and MGCP +void Monitor::checkNotifs(Message& msg, unsigned int type) +{ + DDebug(&__plugin,DebugAll,"::checkNotifs() from module='%s'",lookup(type,s_modules,"")); + if (type == SIP) { + unsigned int count = msg.getIntValue("failed_auths",0); + checkInfo(count,s_sipInfo.auths,FailedAuths,s_sipNotifs); + + count = msg.getIntValue("transaction_timeouts",0); + checkInfo(count,s_sipInfo.transactions,TransactTimedOut,s_sipNotifs); + + count = msg.getIntValue("bye_timeouts",0); + checkInfo(count,s_sipInfo.byes,ByesTimedOut,s_sipNotifs); + } + if (type == MGCP) { + unsigned int transTO = msg.getIntValue("tr_timedout",0); + checkInfo(transTO,s_mgcpInfo.transactions,TransactTimedOut,s_mgcpNotifs); + + transTO = msg.getIntValue("del_timedout",0); + checkInfo(transTO,s_mgcpInfo.deletes,DeletesTimedOut,s_mgcpNotifs); + + if (s_mgcpInfo.gw_monitor) { + if (msg.getValue("mgcp_gw_down")) + sendTrap(lookup(GWTimeout,s_mgcpNotifs,"mgcpGatewayTimedOut"),msg.getValue("mgcp_gw_down")); + if (msg.getValue("mgcp_gw_up")) + sendTrap(lookup(GWUp,s_mgcpNotifs,"mgcpGatewayUp"),msg.getValue("mgcp_gw_up")); + } + } +} + +// get SIP/MGCP transaction info +String Monitor::getTransactionsInfo(const String& query, const int who) +{ + String result = ""; + if (who == SIP) { + int type = lookup(query,s_sipNotifs,0); + switch (type) { + case TransactTimedOut: + result << s_sipInfo.transactions.counter; + return result; + case FailedAuths: + result << s_sipInfo.auths.counter; + return result; + case ByesTimedOut: + result << s_sipInfo.byes.counter; + return result; + default: + break; + } + } + else if (who == MGCP) { + int type = lookup(query,s_mgcpNotifs,0); + switch (type) { + case TransactTimedOut: + result << s_mgcpInfo.transactions.counter; + return result; + case DeletesTimedOut: + result << s_mgcpInfo.deletes.counter; + return result; + default: + break; + } + } + return ""; +} + +// build a notification message. Increase the alarm counters if the notification was an alarm +void Monitor::sendTrap(const String& trap, const String& value, unsigned int index) +{ + DDebug(&__plugin,DebugAll,"Monitor::sendtrap(trap='%s',value='%s',index='%d') [%p]",trap.c_str(),value.c_str(),index,this); + Message* msg = new Message("monitor.notify"); + msg->addParam("notify.0",trap); + msg->addParam("value.0",value); + msg->addParam("index",String(index)); + msg->addParam("count","1"); + Engine::enqueue(msg); +} + +// build a notification message. Increase the alarm counters if the notification was an alarm +void Monitor::sendTraps(const NamedList& traps) +{ + Message* msg = new Message("monitor.notify"); + msg->copyParams(traps); + Engine::enqueue(msg); +} + +// handle a query for a specific monitored value +bool Monitor::solveQuery(Message& msg) +{ + XDebug(__plugin.name(),DebugAll,"::solveQuery()"); + String query = msg.getValue("name",""); + if (query.null()) + return false; + int queryWho = lookup(query,s_categories,0); + String result = ""; + unsigned int index = msg.getIntValue("index",0); + DDebug(__plugin.name(),DebugAll,"::solveQuery(query=%s, index=%u)",query.c_str(),index); + switch (queryWho) { + case DATABASE: + if (m_dbInfo) + result = m_dbInfo->getInfo(query,index,s_databaseQuery); + break; + case CALL_MONITOR: + if (m_callMonitor) + m_callMonitor->get(query,index,result); + break; + case ACTIVE_CALLS: + if (m_activeCallsCache) + result = m_activeCallsCache->getInfo(query,index,s_activeCallInfo); + break; + case TRUNKS: + if (m_trunkInfo) + result = m_trunkInfo->getInfo(query,index,m_trunkInfo->s_trunkInfo); + break; + case LINKSETS: + if (m_linksetInfo) + result = m_linksetInfo->getInfo(query,index,m_linksetInfo->s_linksetInfo); + break; + case LINKS: + if (m_linkInfo) + result = m_linkInfo->getInfo(query,index,m_linkInfo->s_linkInfo); + break; + case IFACES: + if (m_ifaceInfo) + result = m_ifaceInfo->getInfo(query,index,m_ifaceInfo->s_ifacesInfo); + break; + case ACCOUNTS: + if (m_accountsInfo) + result = m_accountsInfo->getInfo(query,index,s_accountInfo); + break; + case ENGINE: + if (m_engineInfo) + result = m_engineInfo->getInfo(query,index,s_engineQuery); + break; + case MODULE: + if (m_moduleInfo) + result = m_moduleInfo->getInfo(query,index,s_moduleQuery); + break; + case AUTH_REQUESTS: + if (m_authHandler) + result = m_authHandler->getCount(); + break; + case REGISTER_REQUESTS: + if (m_registerHandler) + result = m_registerHandler->getCount(); + break; + case RTP: + if (m_rtpInfo) + result = m_rtpInfo->getInfo(query,index); + break; + case SIP: + case MGCP: + result = getTransactionsInfo(query,queryWho); + break; + default: + return false; + } + msg.setParam("value",result); + return true; +} + +// verify if a call hasn't hangup because of a gateway timeout. In that case, if the gateway was +// monitored send a notification +void Monitor::handleChanHangup(const String& address, int& code) +{ + DDebug(this,DebugInfo,"::handleChanHangup('%s', '%d')",address.c_str(),code); + if (address.null()) + return; + if (m_sipMonitoredGws && m_sipMonitoredGws->find(address)) { + if (code == 408 && !m_timedOutGws.find(address)) { + sendTrap(lookup(GWTimeout,s_sipNotifs,"gatewayTimeout"),address); + m_timedOutGws.append(new String(address)); + } + } +} + +// if a call has passed through, get the gateway and verify if it was previously down +// if it was send a notification that the gateway is up again +bool Monitor::verifyGateway(const String& address) +{ + if (address.null()) + return false; + if (m_timedOutGws.find(address)) { + m_timedOutGws.remove(address); + sendTrap(lookup(GWUp,s_sipNotifs,"gatewayUp"),address); + } + return true; +} + +}; +/* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/modules/server/mysqldb.cpp b/modules/server/mysqldb.cpp index da53c321..333ae3e8 100644 --- a/modules/server/mysqldb.cpp +++ b/modules/server/mysqldb.cpp @@ -53,6 +53,7 @@ class MySqlConn; class MyAcct; static ObjList s_conns; +static unsigned int s_failedConns; Mutex s_acctMutex(false,"MySQL::accts"); /** @@ -110,6 +111,23 @@ public: void appendQuery(DbQuery* query); + void incTotal(); + void incFailed(); + void incErrorred(); + void incQueryTime(u_int64_t with); + void lostConn(); + void resetConn(); + inline unsigned int total() + { return m_totalQueries; } + inline unsigned int failed() + { return m_failedQueries; } + inline unsigned int errorred() + { return m_errorQueries; } + inline bool hasConn() + { return ((int)(m_poolSize - m_failedConns) > 0 ? true : false); } + inline unsigned int queryTime() + { return (unsigned int) m_queryTime; } //microseconds + private: unsigned int m_timeout; @@ -128,6 +146,14 @@ private: Semaphore m_queueSem; Mutex m_queueMutex; + + // stats counters + unsigned int m_totalQueries; + unsigned int m_failedQueries; + unsigned int m_errorQueries; + u_int64_t m_queryTime; + unsigned int m_failedConns; + Mutex m_incMutex; }; /** @@ -168,9 +194,12 @@ class MyModule : public Module public: MyModule(); ~MyModule(); + void statusModule(String& str); protected: virtual void initialize(); virtual void statusParams(String& str); + virtual void statusDetail(String& str); + virtual void genUpdate(Message& msg); private: bool m_init; }; @@ -229,7 +258,7 @@ void MyConn::closeConn() MYSQL* tmp = m_conn; m_conn = 0; mysql_close(tmp); - if(m_owner) + if (m_owner) m_owner->m_connections.remove(this); Debug(&module,DebugInfo,"Database connection '%s' closed",c_str()); } @@ -244,6 +273,7 @@ void MyConn::runQueries() DbQuery* query = static_cast(m_owner->m_queryQueue.remove(false)); if (!query) continue; + m_owner->incTotal(); mylock.drop(); DDebug(&module,DebugAll,"Connection '%s' will try to execute '%s'", @@ -268,11 +298,19 @@ bool MyConn::testDb() // return number of rows, -1 for error int MyConn::queryDbInternal(DbQuery* query) { - if (!testDb()) + if (!testDb()) { + m_owner->lostConn(); + m_owner->incFailed(); return -1; + } + m_owner->resetConn(); + u_int64_t start = Time::now(); if (mysql_real_query(m_conn,query->safe(),query->length())) { Debug(&module,DebugWarn,"Query for '%s' failed: %s",c_str(),mysql_error(m_conn)); + u_int64_t duration = Time::now() - start; + m_owner->incQueryTime(duration); + m_owner->incErrorred(); return -1; } @@ -332,6 +370,9 @@ int MyConn::queryDbInternal(DbQuery* query) } } while (!mysql_next_result(m_conn)); + u_int64_t finish = Time::now(); + m_owner->incQueryTime(finish - start); + if (query->m_msg) { query->m_msg->setParam("affected",String(affected)); if (warns) @@ -347,7 +388,10 @@ MyAcct::MyAcct(const NamedList* sect) : String(*sect), Mutex(true,"MySQL::acct"), m_queueSem(MAX_CONNECTIONS,"MySQL::queue"), - m_queueMutex(false,"MySQL::queue") + m_queueMutex(false,"MySQL::queue"), + m_totalQueries(0), m_failedQueries(0), m_errorQueries(0), + m_queryTime(0), m_failedConns(0), + m_incMutex(false,"MySQL::inc") { int tout = sect->getIntValue("timeout",10000); // round to seconds @@ -487,6 +531,60 @@ void MyAcct::dropDb() s_libMutex.unlock(); } +void MyAcct::incTotal() +{ + XDebug(&module,DebugAll,"MyAcct::incTotal() [%p] - currently there have been %d queries",this,m_totalQueries); + m_incMutex.lock(); + m_totalQueries++; + m_incMutex.unlock(); + module.changed(); +} + +void MyAcct::incFailed() +{ + XDebug(&module,DebugAll,"MyAcct::incfailed() [%p] - currently there have been %d failed queries",this,m_failedQueries); + m_incMutex.lock(); + m_failedQueries++; + m_incMutex.unlock(); + module.changed(); +} + +void MyAcct::incErrorred() +{ + XDebug(&module,DebugAll,"MyAcct::incErrorred() [%p] - currently there have been %d errorred queries",this,m_errorQueries); + m_incMutex.lock(); + m_errorQueries++; + m_incMutex.unlock(); + module.changed(); +} + +void MyAcct::incQueryTime(u_int64_t with) +{ + XDebug(&module,DebugAll,"MyAcct::incQueryTime(with=" FMT64 ") [%p]",with,this); + m_incMutex.lock(); + m_queryTime += with; + m_incMutex.unlock(); + module.changed(); +} + +void MyAcct::lostConn() +{ + DDebug(&module,DebugAll,"MyAcct::lostConn() [%p]",this); + m_incMutex.lock(); + if (m_failedConns < (unsigned int) m_poolSize) + m_failedConns++; + m_incMutex.unlock(); + module.changed(); +} + +void MyAcct::resetConn() +{ + DDebug(&module,DebugAll,"MyAcct::hasConn() [%p]",this); + m_incMutex.lock(); + m_failedConns = 0; + m_incMutex.unlock(); +} + void MyAcct::appendQuery(DbQuery* query) { DDebug(&module, DebugAll, "Account '%s' received a new query %p",c_str(),query); @@ -574,11 +672,31 @@ MyModule::~MyModule() { Output("Unloading module MySQL"); s_conns.clear(); + s_failedConns = 0; +} + +void MyModule::statusModule(String& str) +{ + Module::statusModule(str); + str.append("format=Total|Failed|Errors|AvgExecTime",","); } void MyModule::statusParams(String& str) { str.append("conns=",",") << s_conns.count(); + str.append("failed=",",") << s_failedConns; +} + +void MyModule::statusDetail(String& str) +{ + for (unsigned int i = 0; i < s_conns.count(); i++) { + MyAcct* acc = static_cast(s_conns[i]); + str.append(acc->c_str(),",") << "=" << acc->total() << "|" << acc->failed() << "|" << acc->errorred() << "|"; + if (acc->total() - acc->failed() > 0) + str << (acc->queryTime() / (acc->total() - acc->failed()) / 1000); //miliseconds + else + str << "0"; + } } void MyModule::initialize() @@ -589,6 +707,7 @@ void MyModule::initialize() if (m_init) Engine::install(new MyHandler(cfg.getIntValue("general","priority",100))); m_init = false; + s_failedConns = 0; for (unsigned int i = 0; i < cfg.sections(); i++) { NamedList* sec = cfg.getSection(i); if (!sec || (*sec == "general")) @@ -604,11 +723,36 @@ void MyModule::initialize() conn = new MyAcct(sec); s_conns.insert(conn); - if (!conn->initDb()) + if (!conn->initDb()) { s_conns.remove(conn); + s_failedConns++; + } } } +void MyModule::genUpdate(Message& msg) +{ + Lock lock(this); + unsigned int index = 0; + String db = "database."; + String total = "total."; + String failed = "failed."; + String error = "errorred."; + String conn = "hasconn."; + String time = "querytime."; + for (ObjList* o = s_conns.skipNull(); o; o = o->next()) { + MyAcct* acc = static_cast(o->get()); + msg.setParam(db << index,acc->toString()); + msg.setParam(total << index,String(acc->total())); + msg.setParam(failed << index,String(acc->failed())); + msg.setParam(error << index,String(acc->errorred())); + msg.setParam(conn << index,String::boolText(acc->hasConn())); + msg.setParam(time << index,String(acc->queryTime())); + index++; + } + msg.setParam("count",String(index)); +} + }; // anonymous namespace /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/modules/server/pgsqldb.cpp b/modules/server/pgsqldb.cpp index df956894..5d062527 100644 --- a/modules/server/pgsqldb.cpp +++ b/modules/server/pgsqldb.cpp @@ -32,6 +32,7 @@ namespace { // anonymous static ObjList s_conns; Mutex s_conmutex(false,"PgSQL::conn"); +static unsigned int s_failedConns; class PgConn : public RefObject, public Mutex { @@ -46,6 +47,19 @@ public: int queryDb(const char* query, Message* dest = 0); bool initDb(int retry = 0); + inline unsigned int total() + { return m_totalQueries; } + inline unsigned int failed() + { return m_failedQueries; } + inline unsigned int errorred() + { return m_errorQueries; } + inline unsigned int queryTime() + { return (unsigned int) m_queryTime; } + inline void setConn(bool conn = true) + { m_hasConn = conn; } + inline bool hasConn() + { return m_hasConn; } + private: void dropDb(); bool testDb(); @@ -56,6 +70,13 @@ private: int m_retry; u_int64_t m_timeout; PGconn *m_conn; + + // stat counters + unsigned int m_totalQueries; + unsigned int m_failedQueries; + unsigned int m_errorQueries; + u_int64_t m_queryTime; + bool m_hasConn; }; class PgHandler : public MessageHandler @@ -74,7 +95,10 @@ public: ~PgModule(); protected: virtual void initialize(); + virtual void statusModule(String& str); virtual void statusParams(String& str); + virtual void statusDetail(String& str); + virtual void genUpdate(Message& msg); private: bool m_init; }; @@ -83,7 +107,9 @@ static PgModule module; PgConn::PgConn(const NamedList* sect) : Mutex(true,"PgConn"), - m_name(*sect), m_conn(0) + m_name(*sect), m_conn(0), + m_totalQueries(0), m_failedQueries(0), + m_errorQueries(0), m_queryTime(0), m_hasConn(false) { m_connection = sect->getValue("connection"); if (m_connection.null()) { @@ -204,6 +230,7 @@ bool PgConn::ok() // try to get up the connection, retry if we have to bool PgConn::startDb() { + setConn(true); if (testDb()) return true; for (int i = 0; i < m_retry; i++) { @@ -213,6 +240,7 @@ bool PgConn::startDb() if (testDb()) return true; } + setConn(false); return false; } @@ -313,6 +341,8 @@ int PgConn::queryDbInternal(const char* query, Message* dest) default: Debug(&module,DebugWarn,"Query error: %s",PQresultErrorMessage(res)); dest->setParam("error",PQresultErrorMessage(res)); + m_errorQueries++; + module.changed(); } PQclear(res); } @@ -335,12 +365,21 @@ int PgConn::queryDb(const char* query, Message* dest) return -1; Debug(&module,DebugAll,"Performing query \"%s\" for '%s'", query,m_name.c_str()); + m_totalQueries++; + module.changed(); + u_int64_t start = Time::now(); for (int i = 0; i < m_retry; i++) { int res = queryDbInternal(query,dest); if (res > -2) { - if (res < 0) + if (res < 0) { failure(dest); + m_failedQueries++; + module.changed(); + } // ok or non-retryable error, get out of here + u_int64_t finish = Time::now() - start; + m_queryTime += finish; + module.changed(); return res; } } @@ -348,7 +387,6 @@ int PgConn::queryDb(const char* query, Message* dest) return -2; } - static PgConn* findDb(const String& account) { if (account.null()) @@ -385,10 +423,32 @@ PgModule::~PgModule() s_conns.clear(); } +void PgModule::statusModule(String& str) +{ + Module::statusModule(str); + str.append("format=Total|Failed|Errors|AvgExecTime",","); +} + void PgModule::statusParams(String& str) { s_conmutex.lock(); str.append("conns=",",") << s_conns.count(); + str.append("failed=",",") << s_failedConns; + s_conmutex.unlock(); +} + +void PgModule::statusDetail(String& str) +{ + s_conmutex.lock(); + for (unsigned int i = 0; i < s_conns.count(); i++) { + PgConn* conn = static_cast(s_conns[i]); + str.append(conn->toString().c_str(),",") << "=" << conn->total() << "|" << conn->failed() + << "|" << conn->errorred() << "|"; + if (conn->total() - conn->failed() > 0) + str << (conn->queryTime() / (conn->total() - conn->failed()) / 1000); //miliseconds + else + str << "0"; + } s_conmutex.unlock(); } @@ -410,12 +470,36 @@ void PgModule::initialize() if (sec->getBoolValue("autostart",true)) conn->initDb(); s_conmutex.lock(); - s_conns.insert(conn); + if (conn->ok()) + s_conns.insert(conn); + else + s_failedConns++; s_conmutex.unlock(); } } +void PgModule::genUpdate(Message& msg) +{ + unsigned int index = 0; + String db = "database."; + String total = "total."; + String failed = "failed."; + String error = "errorred."; + String hasconn = "hasconn."; + String time = "querytime."; + for (ObjList* o = s_conns.skipNull(); o; o = o->next()) { + PgConn* conn = static_cast(o->get()); + msg.setParam(db << index,conn->toString()); + msg.setParam(total << index,String(conn->total())); + msg.setParam(failed << index,String(conn->failed())); + msg.setParam(error << index,String(conn->errorred())); + msg.setParam(hasconn << index,String::boolText(conn->hasConn())); + msg.setParam(time << index,String(conn->queryTime())); + index++; + } + msg.setParam("count",String(index)); +} }; // anonymous namespace /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/modules/server/tdmcard.cpp b/modules/server/tdmcard.cpp index 39bc3813..9d758717 100644 --- a/modules/server/tdmcard.cpp +++ b/modules/server/tdmcard.cpp @@ -200,6 +200,7 @@ private: u_int64_t m_sent; u_int64_t m_received; struct timeval m_tv; + bool m_down; }; class TdmInterface : public SignallingInterface, public TdmWorker @@ -456,6 +457,25 @@ static inline bool getBoolValue(const char* param, const NamedList& config, } +static void sendModuleUpdate(const String& notif, const String& device, bool& notifStat, int status = 0) +{ + Message* msg = new Message("module.update"); + msg->addParam("module",plugin.name()); + msg->addParam("interface",device); + msg->addParam("notify",notif); + if(notifStat && status == SignallingInterface::LinkUp) { + notifStat = false; + Engine::enqueue(msg); + return; + } + if (!notifStat && status == SignallingInterface::LinkDown) { + notifStat = true; + Engine::enqueue(msg); + return; + } + TelEngine::destruct(msg); +} + bool TdmWorker::running() const { return m_thread && m_thread->running(); @@ -556,6 +576,7 @@ TdmDevice::TdmDevice(Type t, SignallingComponent* dbg, unsigned int chan, return; } m_sent = m_received = 0; + m_down = false; plugin.append(this); } @@ -1009,9 +1030,11 @@ bool TdmDevice::checkEvents() case WP_TDMAPI_EVENT_ALARM: if (!rx_event->wp_tdm_api_event_alarm) { DDebug(m_owner,DebugWarn,"%s: Link is disconnected",tdmName().c_str()); + sendModuleUpdate("interfaceDown",tdmName(),m_down,SignallingInterface::LinkDown); } else { DDebug(m_owner,DebugInfo,"%s: Link is connected",tdmName().c_str()); + sendModuleUpdate("interfaceUp",tdmName(),m_down,SignallingInterface::LinkUp); } decode_alarms(rx_event->wp_tdm_api_event_alarm); break; @@ -1800,6 +1823,7 @@ bool TdmInterface::process() return false; if (!m_device.canRead()) return false; + m_device.checkEvents(); int r = m_device.receiveData(m_buffer,m_bufsize); if (r <= 0) return false; diff --git a/modules/server/wpcard.cpp b/modules/server/wpcard.cpp index 7739f5d6..9cda93c7 100644 --- a/modules/server/wpcard.cpp +++ b/modules/server/wpcard.cpp @@ -263,6 +263,7 @@ private: bool m_repeatCapable; // HW repeat available Mutex m_repeatMutex; // Lock repeat buffer DataBlock m_repeatPacket; // Packet to repeat + bool m_down; }; // Read signalling data for WpInterface @@ -445,6 +446,26 @@ static bool s_repeatCapable = true; // Global repeat packet capability static WpModule driver; +static void sendModuleUpdate(bool& notifStat, int status, const String& device) +{ + Message* msg = new Message("module.update"); + msg->addParam("module",driver.name()); + msg->addParam("interface",device); + if(notifStat && status == SignallingInterface::LinkUp) { + msg->addParam("notify","interfaceUp"); + notifStat = false; + Engine::enqueue(msg); + return; + } + if (!notifStat && status == SignallingInterface::LinkDown) { + msg->addParam("notify","interfaceDown"); + notifStat = true; + Engine::enqueue(msg); + return; + } + TelEngine::destruct(msg); +} + /** * Fifo */ @@ -849,6 +870,7 @@ bool WpInterface::init(const NamedList& config, NamedList& params) s << " hwrepeatcapable=" << String::boolText(m_repeatCapable); Debug(this,DebugInfo,"D-channel: %s [%p]",s.c_str(),this); } + m_down = false; return true; } @@ -1038,10 +1060,14 @@ bool WpInterface::updateStatus() return false; Debug(this,DebugNote,"Link status changed to %s [%p]", lookup(m_socket.status(),s_linkStatus),this); - if (m_socket.status() == WpSocket::Connected) + if (m_socket.status() == WpSocket::Connected) { notify(LinkUp); - else + sendModuleUpdate(m_down,LinkUp,m_socket.card()); + } + else { notify(LinkDown); + sendModuleUpdate(m_down,LinkDown,m_socket.card()); + } return true; } diff --git a/modules/server/ysigchan.cpp b/modules/server/ysigchan.cpp index 21b1a34a..72f98497 100644 --- a/modules/server/ysigchan.cpp +++ b/modules/server/ysigchan.cpp @@ -44,7 +44,7 @@ class SigIsdnCallRecord; // Record an ISDN call monitor class SigTrunkThread; // Get events and check timeout for trunks that have a call controller class IsupDecodeHandler; // Handler for "isup.decode" message class IsupEncodeHandler; // Handler for "isup.encode" message - +class SigNotifier; // Class for handling received notifications // The signalling channel class SigChannel : public Channel, public MessageNotifier @@ -247,6 +247,15 @@ class SigTopmost : public TopMost { public: SigTopmost(const char* name); + // Return the status of this component + virtual inline void status(String& retVal) + { } + // Return the status of a signalling interface + virtual inline void ifStatus(String& status) + { } + // Return the status of a link + virtual inline void linkStatus(String& status) + { } protected: virtual void destroyed(); }; @@ -261,6 +270,10 @@ public: // Initialize (create or reload) the linkset // Return false on failure virtual bool initialize(NamedList& params); + // Return the status of this component + virtual void status(String& retVal); + virtual void ifStatus(String& status); + virtual void linkStatus(String& status); protected: virtual void destroyed(); private: @@ -338,6 +351,10 @@ public: void cleanup(); // Type names static const TokenDict s_type[]; + virtual inline void ifStatus(String& status) + { } + virtual inline void linkStatus(String& status) + { } protected: // Cancel thread. Cleanup. Remove from plugin list virtual void destroyed(); @@ -390,6 +407,8 @@ class SigIsdn : public SigTrunk public: SigIsdn(const char* name, Type type); virtual ~SigIsdn(); + virtual void ifStatus(String& status); + virtual void linkStatus(String& status); protected: virtual bool create(NamedList& params, String& error); virtual bool reload(NamedList& params); @@ -618,8 +637,18 @@ public: virtual bool received(Message& msg); }; +class SigNotifier : public SignallingNotifier +{ +public: + inline ~SigNotifier() + { } + virtual void notify(NamedList& params); + virtual void cleanup(); +}; + static SigDriver plugin; static SigFactory factory; +static SigNotifier s_notifier; static Configuration s_cfg; static Configuration s_cfgData; static const String s_noPrefixParams = "format,earlymedia"; @@ -714,8 +743,11 @@ SignallingComponent* SigFactory::create(const String& type, const NamedList& nam case SigISDNLayer2: if (ty && *ty == "isdn-iua") return new ISDNIUA(*config); - if (name.getBoolValue("primary",true)) - return new ISDNQ921(*config,name); + if (name.getBoolValue("primary",true)) { + NamedList cfg(*config); + cfg.setParam("type",lookup(compType,s_compNames)); + return new ISDNQ921(cfg,name); + } return new ISDNQ921Management(*config,name,name.getBoolValue("network",true)); case SigISDNLayer3: return new ISDNQ931(*config,name); @@ -1686,6 +1718,46 @@ bool SigDriver::received(Message& msg, int id) if (!target.startSkip(name())) return false; + if (target.startSkip("links")) { + msg.retValue() << "module=" << name(); + msg.retValue() << ",format=Type|Status"; + String ret = ""; + m_trunksMutex.lock(); + for (ObjList* o = m_trunks.skipNull(); o; o = o->skipNext()) { + SigTrunk* trunk = static_cast(o->get()); + trunk->linkStatus(ret); + } + m_trunksMutex.unlock(); + m_topmostMutex.lock(); + for (ObjList* o = m_topmost.skipNull(); o; o = o->skipNext()) { + SigTopmost* top = static_cast(o->get()); + top->linkStatus(ret); + } + m_topmostMutex.unlock(); + if (!ret.null()) + msg.retValue() << ";" << ret; + msg.retValue() << "\r\n"; + } + if (target.startSkip("ifaces")) { + msg.retValue() << "module=" << name(); + msg.retValue() << ",format=Status"; + String ret = ""; + m_trunksMutex.lock(); + for (ObjList* o = m_trunks.skipNull(); o; o = o->skipNext()) { + SigTrunk* trunk = static_cast(o->get()); + trunk->ifStatus(ret); + } + m_trunksMutex.unlock(); + m_topmostMutex.lock(); + for (ObjList* o = m_topmost.skipNull(); o; o = o->skipNext()) { + SigTopmost* top = static_cast(o->get()); + top->ifStatus(ret); + } + m_topmostMutex.unlock(); + if (!ret.null()) + msg.retValue() << ";" << ret; + msg.retValue() << "\r\n"; + } // Status target=trunk[/cic|/range] int pos = target.find("/"); @@ -1762,6 +1834,10 @@ void SigDriver::status(SigTopmost* topmost, String& retVal) retVal.clear(); retVal << "module=" << name(); retVal << ",component=" << topmost->name(); + String details = ""; + topmost->status(details); + if (!details.null()) + retVal << "," << details; retVal << "\r\n"; } @@ -1984,6 +2060,8 @@ bool SigDriver::commandComplete(Message& msg, const String& partLine, Lock lock(this); // line='status sig': add trunks and topmost components if (partLine == m_statusCmd) { + itemComplete(msg.retValue(),"links",partWord); + itemComplete(msg.retValue(),"ifaces",partWord); ObjList* o; m_trunksMutex.lock(); for (o = m_trunks.skipNull(); o; o = o->skipNext()) @@ -2338,6 +2416,7 @@ void SigDriver::initialize() m_engine = SignallingEngine::self(true); m_engine->debugChain(this); m_engine->start(); + m_engine->setNotifier(&s_notifier); } // Apply debug levels to driver and engine int level = s_cfg.getIntValue("general","debuglevel",-1); @@ -2413,6 +2492,54 @@ bool SigLinkSet::initialize(NamedList& params) return m_linkset && m_linkset->initialize(¶ms); } +void SigLinkSet::status(String& retVal) +{ + retVal << "type=" << (m_linkset ? m_linkset->componentType() : ""); + retVal << ",status=" << (m_linkset && m_linkset->operational() ? "" : "non-") << "operational"; +} + +void SigLinkSet::ifStatus(String& status) +{ + SS7MTP3* mtp3 = static_cast(m_linkset); + if (mtp3) { + const ObjList* list = mtp3->links(); + for (ObjList* o = list->skipNull(); o; o = o->skipNext()) { + GenPointer* p = static_cast*>(o->get()); + if (!*p) + continue; + SS7Layer2* link = *p; + SS7MTP2* mtp2 = static_cast(link->getObject("SS7MTP2")); + if (mtp2) { + SignallingInterface* sigIface = mtp2->iface(); + if (sigIface) { + status.append(sigIface->toString(),","); + status << "=" << (sigIface->control(SignallingInterface::Query) ? "" : "non-"); + status << "operational"; + } + } + } + } +} + +void SigLinkSet::linkStatus(String& status) +{ + SS7MTP3* mtp3 = static_cast(m_linkset); + if (mtp3) { + const ObjList* list = mtp3->links(); + for (ObjList* o = list->skipNull(); o; o = o->skipNext()) { + GenPointer* p = static_cast*>(o->get()); + if (!*p) + continue; + SS7Layer2* link = *p; + if (link) { + status.append(link->toString(),",") << "="; + status << link->componentType() ; + status << "|" << link->statusName(); + + } + } + } +} /** * SigTesting @@ -2871,6 +2998,31 @@ void SigIsdn::release() XDebug(&plugin,DebugAll,"SigIsdn('%s'). Released [%p]",name().c_str(),this); } +void SigIsdn::ifStatus(String& status) +{ + if (m_controller) { + const ISDNQ921* l2 = static_cast(q931()->layer2()); + if (l2) { + SignallingInterface* sigIface = l2->iface(); + if (sigIface) { + status.append(sigIface->toString(),","); + status << "=" << (sigIface->control(SignallingInterface::Query) ? "" : "non-") << "operational"; + } + } + } +} + +void SigIsdn::linkStatus(String& status) +{ + if (m_controller) { + const ISDNLayer2* l2 = static_cast(q931()->layer2()); + if (l2) { + status.append(l2->toString(),",") << "="; + status << l2->componentType(); + status << "|" << l2->stateName(l2->state()); + } + } +} /** * SigIsdnMonitor @@ -3689,6 +3841,26 @@ bool IsupEncodeHandler::received(Message& msg) return false; } +/** + * SigNotifier + */ +void SigNotifier::notify(NamedList& notifs) +{ + Debug(&plugin,DebugInfo,"SigNotifier [%p] received a notify ",this); + Message* msg = new Message("module.update"); + msg->addParam("module",plugin.name()); + msg->copyParams(notifs); + Engine::enqueue(msg); +} + +void SigNotifier::cleanup() +{ + DDebug(&plugin,DebugInfo,"SigNotifier [%p] cleanup()",this); + SignallingEngine* engine = plugin.engine(); + if (engine) + engine->removeNotifier(this); +} + }; // anonymous namespace /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/modules/server/ysnmpagent.cpp b/modules/server/ysnmpagent.cpp new file mode 100644 index 00000000..ba0e3825 --- /dev/null +++ b/modules/server/ysnmpagent.cpp @@ -0,0 +1,2712 @@ +/** + * ysnmpagent.cpp + * This file is part of the YATE Project http://YATE.null.ro + * + * Module for SNMP protocol agent + * + * Yet Another Telephony Engine - a fully featured software PBX and IVR + * Copyright (C) 2004-2010 Null Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include + +// values for the different versions of the protocol +#define SNMP_VERSION_1 0 +#define SNMP_VERSION_2C 1 +#define SNMP_VERSION_2S 2 // not implemented +#define SNMP_VERSION_3 3 + +// user security model +#define USM_SEC_MODEL 3 + +// privacy flags +#define REPORT_FLAG 0x04 +#define PRIVACY_FLAG 0x02 +#define AUTH_FLAG 0x01 + +// maximum value for the agent encryption salt +#define SALT_MAX_VAL 0xffffffffffffffffULL + +// maximum time frame window (in seconds) in which a message should be handled +#define TIMEFRAME_VAL 150 +// maximum value engine boots, after which it should be reset +#define ENGINE_BOOTS_MAX 2147483647 +// maximum value for engine time, after which it should be reset +#define ENGINE_TIME_MAX 2147483647 + +#define MSG_MAX_SIZE 65507 + +using namespace TelEngine; + +namespace { + +class TransportType; +class SnmpSocketListener; +class SnmpMsgQueue; +class SnmpMessage; +class SnmpAgent; +class SnmpUser; + +class SnmpUdpListener; +class TrapHandler; + +/** + * TransportType + */ +class TransportType +{ +public: + enum Type { + UDP = 0, + TCP = 1, // not implemented +// OSI = 2, // not implemented + }; + inline TransportType(int type = UDP) + : m_type(type) + {} + + static inline const char* lookupType(int stat, const char* defVal = 0) + { return lookup(stat, s_typeText, defVal); } + + static const TokenDict s_typeText[]; + + int m_type; +}; + +/** + * Abstract class SnmpSocketListener + */ +class SnmpSocketListener : public Thread +{ +public: + inline SnmpSocketListener(int port, SnmpMsgQueue* queue) + : Thread("SNMP Socket"), + m_port(port), m_msgQueue(queue) + {} + inline ~SnmpSocketListener() + {} + virtual bool init() = 0; + virtual void run() = 0; + virtual void sendMessage(DataBlock& data, SocketAddr& to) = 0; + virtual void cleanup() = 0; + +protected: + Socket m_socket; + int m_port; + SnmpMsgQueue* m_msgQueue; +}; + +/** + * SnmpMsgQueue - class for holding a queue of messages received + */ +class SnmpMsgQueue : public Thread +{ +public: + SnmpMsgQueue(SnmpAgent* agent, Thread::Priority prio = Thread::Normal, unsigned int port = 161, int type = TransportType::UDP); + inline ~SnmpMsgQueue() + { } + virtual bool init(); + virtual void run(); + virtual void cleanup(); + virtual void addMsg(unsigned char* msg, int len, SocketAddr& fromAddr); + virtual void sendMsg(SnmpMessage* msg); + +protected: + SnmpSocketListener* m_socket; + +private: + TransportType m_type; + ObjList m_msgQueue; + Mutex m_queueMutex; + SnmpAgent* m_snmpAgent; +}; + +/** + * SnmpMessage - a wrapper for SNMP messages + */ +class SnmpMessage : public GenObject +{ +public: + inline SnmpMessage() + {} + inline SnmpMessage(unsigned char* rawData, unsigned int length, SocketAddr fromAddr) + : m_from(fromAddr) + { m_data.assign(rawData,length);} + inline ~SnmpMessage() + { } + inline void setData(const DataBlock& data) + { m_data = data;} + inline DataBlock& data() + { return m_data;} + inline SocketAddr& peer() + { return m_from;} + inline void setPeer(SocketAddr peer) + { m_from = peer;} +private: + DataBlock m_data; + SocketAddr m_from; +}; + +class SnmpUser : public GenObject +{ +public: + // enum for authentication and privacy encryption + enum SecurityProtocols { + MD5_AUTH = 1, + SHA1_AUTH = 2, + AES_ENCRYPT = 3, + DES_ENCRYPT = 4 + }; + // Constructor + SnmpUser(NamedList* cfg); + + // Destructor + inline ~SnmpUser() + {} + + inline const String& toString() const + { return m_name; } + + inline bool needsAuth() + { return !m_authPassword.null(); } + inline bool needsPriv() + { return !m_privPassword.null(); } + inline int authProto() + { return m_authProto; } + inline int privProto() + { return m_privProto; } + inline int accessLevel() + { return m_accessLevel; } + inline const DataBlock& digestK1() + { return m_k1; } + inline const DataBlock& digestK2() + { return m_k2; } + inline const DataBlock& authKey() + { return m_authKey; } + inline const DataBlock& privKey() + { return m_privKey; } + +private: + String m_name; + String m_authPassword; + String m_privPassword; + int m_authProto; + int m_privProto; + int m_accessLevel; + + DataBlock m_authKey; + DataBlock m_k1; + DataBlock m_k2; + DataBlock m_privKey; + + static TokenDict s_access[]; + // generate encryption key + DataBlock generateAuthKey(String pass = ""); + // generate an authentication information + void generateAuthInfo(); +}; + +/** + * SnmpV3MsgContainer - a container for a decoded SNMPv3 message data + */ +class SnmpV3MsgContainer : public GenObject +{ +public: + // Constructor + inline SnmpV3MsgContainer() + : m_scopedPdu(0), m_user(0), m_msgEngineBoots(0), + m_msgEngineTime(0), m_msgId(0), m_securityModel(0), + m_msgMaxSize(MSG_MAX_SIZE), m_privFlag(false), m_authFlag(false), m_reportFlag(false) + {} + // Destructor + inline ~SnmpV3MsgContainer() + {} + + // Return the security parameters from the message + inline Snmp::UsmSecurityParameters& getSecurity() + { return m_security;} + // reportable flag + inline bool reportable() + { return m_reportFlag;} + + // validate a SNMPv3 message + int validate(Snmp::SNMPv3Message& msg); + // handle a request + int processRequest(Snmp::SNMPv3Message& msg); + // prepare a message for sending. Generate authentication and privacy information as needed. + int prepareForSend(Snmp::SNMPv3Message& msg); + // in case the message exceeds the size constraint for a SNMPv3 message, generate a tooBigMessage response + int generateTooBigMsg(Snmp::SNMPv3Message& msg); + + // extract information from the message header and verify it + int processHeader(Snmp::SNMPv3Message& msg); + // extract and verify authentication and privacy information + int processSecurityModel(Snmp::SNMPv3Message& msg); + // proces the pdu from the message + int processScopedPdu(); + + // check the authentication credentials for the given user + int checkUser(); + // check to see if the message was received in the acceptable timeframe window + int checkTimeWindow(); + // check digest of the message + int checkAuth(Snmp::SNMPv3Message& msg); + + // build a message digest + void msgDigest(Snmp::SNMPv3Message& msg, OctetString& digest); + + // decrypt a pdu + int decrypt(Snmp::SNMPv3Message& msg); + // encrypt a given pdu, return encryption result in ecryptedPdu + int encrypt(Snmp::ScopedPDU* pdu, DataBlock& encryptedPdu); + + // get the maximum size of a message + inline int msgMaxSize() + { return m_msgMaxSize;} + + // set the SNMPv3 user for this message + inline void setUser(SnmpUser* user) + { + m_user = user; + if (m_user) { + m_authFlag = m_user->needsAuth(); + m_privFlag = m_user->needsPriv(); + } + } + + inline void setScopedPdu(Snmp::ScopedPDU* scopedPdu) + { m_scopedPdu = scopedPdu;} + inline void setAuthFlag(bool val = true) + { m_authFlag = val; } + inline void setPrivFlag(bool val = true) + { m_privFlag = val; } + inline void setReportFlag(bool val = true) + { m_reportFlag = val; } +private: + // security parameters + Snmp::UsmSecurityParameters m_security; + // message pdu + Snmp::ScopedPDU* m_scopedPdu; + // user + SnmpUser* m_user; + // message "salt" + DataBlock m_msgSalt; + // message engine boots + u_int32_t m_msgEngineBoots; + // message engine time + u_int32_t m_msgEngineTime; + // message id + int m_msgId; + // message USM + int m_securityModel; + // message maximum size + int m_msgMaxSize; + // message flags + bool m_privFlag; + bool m_authFlag; + bool m_reportFlag; +}; + +/** + * SnmpAgent + */ +class SnmpAgent : public Module +{ +public: + // type of values + enum ValType { + INTEGER, + STRING, + OBJECT_ID, + IPADDRESS, + COUNTER, + TIMETICKS, + ARBITRARY, + BIG_COUNTER, + UNSIGNED_INTEGER + }; + // SNMPv3 process statuses + enum USMEnum { + MESSAGE_DROP = -1, + SUCCESS = 0, + WRONG_SEC_LEVEL = 1, + WRONG_WINDOW_TIME = 2, + WRONG_USER = 3, + WRONG_ENGINE_ID = 4, + WRONG_DIGEST = 5, + WRONG_ENCRYPT = 6 + }; + // formats for generating a engine ID + enum EngineFormats { + IPv4 = 1, + IPv6 = 2, + MAC = 3, + TEXT = 4, + OCTETS = 5, + ENTERPRISE = 128 + }; + + SnmpAgent(); + virtual ~SnmpAgent(); + //inherited methods + virtual void initialize(); + virtual bool received(Message& msg, int id); + bool unload(); + + inline const OctetString& getEngineID() + { return m_engineId;} + + inline u_int32_t getEngineBoots() + { return m_engineBoots;} + + inline u_int32_t getEngineTime() + { + u_int32_t time = Time::secNow() - m_startTime; + if (time >= ENGINE_TIME_MAX) { + m_engineBoots++; + m_startTime = Time::secNow(); + time = Time::secNow() - m_startTime; + } + return time; + } + + // get the salt used for security. Change it's value with each call. + inline u_int32_t getEngineSalt() + { + u_int32_t tmp = m_salt++; + m_salt = (m_salt == SALT_MAX_VAL ? 0 : m_salt); + return tmp; + } + + // process a SNMP message + int processMsg(SnmpMessage* msg); + // process a SNMPv2 message + int processSnmpV2Msg(Snmp::Message& msg); + // decode a pdu and process it accordingly + void decodePDU(int& reqType, Snmp::PDU* obj, const int& access); + // process get/getnext/set requests + int processGetReq(Snmp::VarBind* varBind, AsnValue* value, int& error, const int& access); + int processGetNextReq(Snmp::VarBind* varBind, AsnValue* value, int& error, const int& access); + int processSetReq(Snmp::VarBind* varBind, int& error, const int& access); + // handle a getbulkrequest + Snmp::PDU* decodeBulkPDU(int& reqType, Snmp::BulkPDU* pdu, const int& access); + + // handle a SNMPv3 message + int processSnmpV3Msg(Snmp::SNMPv3Message& msg); + // generate reports and responses for SNMPv3 messages + int generateReport(Snmp::SNMPv3Message& msg, const int& usmRes, SnmpV3MsgContainer& msgContainer); + int generateResponse(Snmp::SNMPv3Message& msg, SnmpV3MsgContainer& msgContainer); + + + Snmp::PDU* getPDU(Snmp::PDUs& p); + // get a encryption object + Cipher* getCipher(int criptoType = SnmpUser::DES_ENCRYPT); + + // get&set the value from/for a variable binding + DataBlock getVal(Snmp::VarBind* varBind); + void assignValue(Snmp::VarBind* varBind, AsnValue* val); + + // obtain the value for a query + AsnValue makeQuery(const String& query, unsigned int& index, AsnMib* mib = 0); + + // send in form of a SNMP trap a notification + int sendNotification(String& notif, String& value, unsigned int index = 0); + // build trap network destination + SocketAddr buildDestination(const String& ip, const String& port); + // build a variable bindings list of mandatory OIDs for a trap + Snmp::VarBindList* addTrapOIDs(String& notifOID); + // build SNMPv2 and SNMPv3 traps + Snmp::SNMPv2_Trap_PDU buildTrapPDU(const String& name, const String& value, unsigned int index = 0); + int buildTrapMsgV3(Snmp::SNMPv3Message& msg, DataBlock pduData); + + // set a value from a varbind + void setValue(const String& varName, Snmp::VarBind* val, int& error); + // generate a engineID + OctetString genEngineId(const int format, String& info); + // verify if a trap is disabled + bool trapDisabled(String& name); + + // verify if a query is in the Yate tree + bool queryIsSupported(const String& query, AsnMib* mib = 0); + // obtain a SNMPv3 user + inline SnmpUser* getUser(const String& user) + { return static_cast(m_users[user]); } + +private: + bool m_init; + SnmpMsgQueue* m_msgQueue; + String m_roCommunity; + String m_rwCommunity; + String m_rcCommunity; + AsnMibTree* m_mibTree; + // msg v3 vars + OctetString m_engineId; + u_int32_t m_engineBoots; + u_int32_t m_startTime; + + // user security model statistics + u_int32_t m_stats[7]; + + u_int32_t m_silentDrops; + u_int64_t m_salt; + + TrapHandler* m_trapHandler; + + bool m_enabledTraps; + ObjList* m_traps; + + // SNMP v3 users + SnmpUser* m_trapUser; + ObjList m_users; + + // AES and DES ciphers + Cipher* m_cipherAES; + Cipher* m_cipherDES; +}; + +/** + * SnmpUdpListener - UDP socket for receiving and sending messages + */ +class SnmpUdpListener : public SnmpSocketListener +{ +public: + SnmpUdpListener(int port, SnmpMsgQueue* queue); + ~SnmpUdpListener(); + virtual bool init(); + virtual void run(); + virtual void sendMessage(DataBlock& data, SocketAddr& to); + virtual void cleanup(); +}; + +/** + * CipherHolder - class for obtaining an appropriate encryption/decryption object from OpenSSL module + */ +class CipherHolder : public RefObject +{ +public: + inline CipherHolder() + : m_cipher(0) + { } + virtual ~CipherHolder() + { TelEngine::destruct(m_cipher); } + virtual void* getObject(const String& name) const + { return (name == "Cipher*") ? (void*)&m_cipher : RefObject::getObject(name); } + inline Cipher* cipher() + { Cipher* tmp = m_cipher; m_cipher = 0; return tmp; } +private: + Cipher* m_cipher; +}; + +/** + * TrapHandler - message handler for incoming notifications + */ +class TrapHandler : public MessageHandler +{ +public: + inline TrapHandler(unsigned int priority = 100) + : MessageHandler("monitor.notify",priority) + { } + virtual ~TrapHandler() + { } + virtual bool received(Message& msg); +}; + +const TokenDict TransportType::s_typeText[] = { + {"UDP", UDP}, + {"TCP", TCP}, + {0,0} +}; + +static const TokenDict s_proto[] = { + {"SNMPv1", SNMP_VERSION_1}, + {"SNMPv2c", SNMP_VERSION_2C}, + {"SNMPv3", SNMP_VERSION_3}, + {0,0} +}; + +static const TokenDict s_errors[] = { + {"MESSAGE_DROP", SnmpAgent::MESSAGE_DROP}, + {"SUCCESS", SnmpAgent::SUCCESS}, + {"WRONG_SEC_LEVEL", SnmpAgent::WRONG_SEC_LEVEL}, + {"WRONG_WINDOW_TIME", SnmpAgent::WRONG_WINDOW_TIME}, + {"WRONG_USER", SnmpAgent::WRONG_USER}, + {"WRONG_ENGINE_ID", SnmpAgent::WRONG_ENGINE_ID}, + {"WRONG_DIGEST", SnmpAgent::WRONG_DIGEST}, + {"WRONG_ENCRYPT", SnmpAgent::WRONG_ENCRYPT}, + {0,0} +}; + +static const TokenDict s_stats[] = { + {"usmStatsUnknownEngineIDs", SnmpAgent::WRONG_ENGINE_ID}, + {"usmStatsUnknownUserNames", SnmpAgent::WRONG_USER}, + {"usmStatsWrongDigests", SnmpAgent::WRONG_DIGEST}, + {"usmStatsUnsupportedSecLevels", SnmpAgent::WRONG_SEC_LEVEL}, + {"usmStatsDecryptionErrors", SnmpAgent::WRONG_ENCRYPT}, + {"usmStatsNotInTimeWindows", SnmpAgent::WRONG_WINDOW_TIME}, + {0,0} +}; + +static const TokenDict s_crypto[] = { + {"DES_CBC", SnmpUser::DES_ENCRYPT}, + {"AES128_CFB", SnmpUser::AES_ENCRYPT}, + {0,0} +}; + +static const TokenDict s_pdus[] = { + {"GetRequest", Snmp::PDUs::GET_REQUEST}, + {"GetNextRequest", Snmp::PDUs::GET_NEXT_REQUEST}, + {"GetBulkRequest", Snmp::PDUs::GET_BULK_REQUEST}, + {"Response", Snmp::PDUs::RESPONSE}, + {"SetRequest", Snmp::PDUs::SET_REQUEST}, + {"InformRequest", Snmp::PDUs::INFORM_REQUEST}, + {"SnmpV2Trap", Snmp::PDUs::SNMPV2_TRAP}, + {"Report", Snmp::PDUs::REPORT}, + {0,0} +}; + +static const TokenDict s_types[] = { + {"INTEGER", AsnValue::INTEGER}, + {"DisplayString", AsnValue::STRING}, + {"OBJECT_ID", AsnValue::OBJECT_ID}, + {"IpAddress", AsnValue::IPADDRESS}, + {"Counter32", AsnValue::COUNTER}, + {"TimeTicks", AsnValue::TIMETICKS}, + {"Opaque", AsnValue::ARBITRARY}, + {"Counter64", AsnValue::BIG_COUNTER}, + {"Unsigned32", AsnValue::UNSIGNED_INTEGER}, + {"OCTET_STRING", AsnValue::STRING}, + {0,0} +}; + +TokenDict SnmpUser::s_access[] = { + {"readonly", AsnMib::readOnly}, + {"readwrite", AsnMib::readWrite}, + {"readCreate", AsnMib::readCreate}, + {0,0} +}; + +static Configuration s_cfg; +static Configuration s_saveCfg; +static u_int8_t s_zero = 0; + +static u_int32_t s_pen = 34501; + +static SocketAddr s_remote; +static String s_yateRoot = ""; + +// zero digest +static const DataBlock s_zeroKey(0,12); + +INIT_PLUGIN(SnmpAgent); + + +UNLOAD_PLUGIN(unloadNow) +{ + if (unloadNow && !__plugin.unload()) + return false; + return true; +} + +static DataBlock toNetworkOrder(u_int64_t val, unsigned int size) +{ + XDebug(&__plugin,DebugAll,"toNetworkOrder("FMT64")",val); + DataBlock res; + for (unsigned int i = 0; i < size; i++) { + DataBlock aux; + u_int8_t auxInt = val >> (8 * i); + aux.append(&auxInt,1); + res.insert(aux); + } + return res; +} + +/** + * SnmpUdpListener + */ +SnmpUdpListener::SnmpUdpListener(int port, SnmpMsgQueue* queue) + : SnmpSocketListener(port,queue) +{ + DDebug(&__plugin,DebugAll,"SnmpUdpListener created with assigned port : %d",m_port); +} + +SnmpUdpListener::~SnmpUdpListener() +{ + DDebug(&__plugin,DebugAll,"SnmpUdpListener with port %d destroyed",m_port); +} + +bool SnmpUdpListener::init() +{ + SocketAddr addr; + + if (!addr.assign(AF_INET) || !addr.host("0.0.0.0") || !addr.port(m_port)) { + Debug(&__plugin,DebugWarn,"Could not assign values to socket address for SNMP UDP Listener"); + return false; + } + + if (!m_socket.create(addr.family(),SOCK_DGRAM)) { + Debug(&__plugin,DebugWarn,"Could not create socket for SNMP UDP Listener error %d", + m_socket.error()); + return false; + } + + m_socket.setReuse(); + + if (!m_socket.bind(addr)) { + Debug(&__plugin,DebugWarn,"Could not bind SNMP UDP Listener, error %d %s", + m_socket.error(),strerror(m_socket.error())); + return false; + } + if (!m_socket.setBlocking(false)) { + Debug(&__plugin,DebugWarn,"Could not set nonblocking SNMP UDP Listener, error %d %s", + m_socket.error(),strerror(m_socket.error())); + return false; + } + Debug(&__plugin,DebugInfo,"SNMP UDP Listener initialized on port %d", m_port); + return startup(); +} + +void SnmpUdpListener::run() +{ + DDebug(&__plugin,DebugInfo,"SNMP UDP Listener started to run"); + unsigned char buffer[2048]; + + for (;;) { + bool readOk = false; + bool error = false; + + check(); + + if (!m_socket.select(&readOk,0,&error,idleUsec())) + continue; + + if (!readOk || error) { + if (error) + Debug(&__plugin,DebugInfo,"SNMP UDP Reading data error: (%d)",m_socket.error()); + continue; + } + + SocketAddr from; + int readSize = m_socket.recvFrom(buffer,sizeof(buffer),from,0); + if (!readSize) { + if (m_socket.canRetry()) { + idle(true); + continue; + } + } + else if (readSize < 0) { + if (m_socket.canRetry()) { + idle(true); + continue; + } + cancel(); + Debug(&__plugin,DebugWarn,"SNMP UDP Read error in SnmpUdpListener [%p]",this); + break; + } + + buffer[readSize] = 0; + + m_msgQueue->addMsg(buffer,readSize,from); + } +} + +void SnmpUdpListener::sendMessage(DataBlock& d, SocketAddr& to) +{ + DDebug(&__plugin,DebugAll,"SnmpUdpListener::sendMessage() of length '%d' to '%s:%d'",d.length(),to.host().c_str(),to.port()); + + int len = d.length(); + while (m_socket.valid() && (len > 0)) { + + bool writeOk = false,error = false; + + if (!m_socket.select(0,&writeOk,&error,idleUsec())) + continue; + if (!writeOk || error) + continue; + int w = m_socket.sendTo(d.data(),len,to); + if (w < 0) { + if (!m_socket.canRetry()) { + Debug(&__plugin,DebugWarn,"SnmpUdpListener::sendMessage() - could not send message"); + cancel(); + return ; + } + } + else + len -= w; + } + return; +} + +void SnmpUdpListener::cleanup() +{ +} + + +/** + * SnmpMsgQueue + */ +SnmpMsgQueue::SnmpMsgQueue(SnmpAgent* agent, Thread::Priority prio, unsigned int port, int type) + : Thread("SNMP Queue",prio), + m_socket(0), + m_queueMutex(false,"SnmpAgent::queue"), + m_snmpAgent(agent) +{ + Debug(&__plugin,DebugAll,"SnmpMsgQueue created for port %d with priority '%s'",port,priority(prio)); + if (type == TransportType::UDP) { + m_socket = new SnmpUdpListener(port,this); + if (!m_socket->init()) { + delete m_socket; + m_socket = 0; + } + } +} + +bool SnmpMsgQueue::init() +{ + DDebug(&__plugin,DebugAll,"SnmpMsgQueue::init()"); + if (!m_socket) + return false; + return startup(); +} + +void SnmpMsgQueue::cleanup() +{ + DDebug(&__plugin,DebugAll,"SnmpMsgQueue::cleanup()"); + m_msgQueue.clear(); +} + +void SnmpMsgQueue::run() +{ + while (m_socket && m_snmpAgent) { + Thread::check(); + SnmpMessage* msg = 0; + if (m_msgQueue.get()) { + m_queueMutex.lock(); + msg = static_cast(m_msgQueue.remove(false)); + m_queueMutex.unlock(); + } + if (!msg) { + idle(); + continue; + } + + XDebug(&__plugin,DebugAll,"Processing message [%p]",msg); + int res = m_snmpAgent->processMsg(msg); + if (res < 0) + Debug(&__plugin,DebugAll,"Error processing message [%p]",msg); + + XDebug(&__plugin,DebugAll,"Processing of message [%p] finished",msg); + TelEngine::destruct(msg); + } +} + +void SnmpMsgQueue::addMsg(unsigned char* msg, int len, SocketAddr& fromAddr) +{ + XDebug(&__plugin,DebugAll,"SnmpMsgQueue::addMsg() - message received with length %d from address %s:%d", + len,fromAddr.host().c_str(),fromAddr.port() ); + + if(!msg) + return; + SnmpMessage* snmpMsg = new SnmpMessage(msg,len,fromAddr); + + m_queueMutex.lock(); + m_msgQueue.append(snmpMsg); + m_queueMutex.unlock(); +} + +void SnmpMsgQueue::sendMsg(SnmpMessage* msg) +{ + DDebug(&__plugin,DebugAll,"SnmpMsgQueue::sendMsg([%p])",msg); + if (!msg) + return; + DataBlock content = msg->data(); + if (m_socket && content.length() > 0) + m_socket->sendMessage(content,msg->peer()); +} + +/** + * TrapHandler + */ +bool TrapHandler::received(Message& msg) +{ + unsigned int index = msg.getIntValue("index",0); + int count = msg.getIntValue("count",0); + for (int i = 0; i < count; i++) { + String param = "notify."; + param << i; + String paramValue = "value."; + paramValue << i; + String notif = msg.getValue(param,""); + String value = msg.getValue(paramValue,""); + if (!notif.null()) + __plugin.sendNotification(notif,value,index); + } + return true; +} + +/** + * SnmpUser + */ +SnmpUser::SnmpUser(NamedList* cfg) +{ + DDebug(&__plugin,DebugAll,"SnmpUser::SnmpUser(cfg=%p) [%p]",cfg,this); + if (cfg) { + m_name = *cfg; + m_authPassword = cfg->getValue("auth_password",""); + + String proto = cfg->getValue("auth_protocol","MD5"); + m_authProto = (proto == "MD5" ? MD5_AUTH : SHA1_AUTH); + + m_privPassword = cfg->getValue("priv_password",""); + + proto = cfg->getValue("priv_protocol","DES"); + m_privProto = (proto == "DES" ? DES_ENCRYPT : AES_ENCRYPT); + + // get the user's privilege level + String access = cfg->getValue("access","readonly"); + m_accessLevel = lookup(access,s_access); + + if (needsAuth()) + generateAuthInfo(); + } +} + +DataBlock SnmpUser::generateAuthKey(String password) +{ + DataBlock b; + if (TelEngine::null(password)) + return b; + DDebug(&__plugin,DebugAll,"SnmpUser::generateAuthKey(user=%s) [%p]",m_name.c_str(),this); + DataBlock authKey(0,64); + + MD5 digestMD5; + SHA1 digestSHA; + int count = 0; + int passIndex = 0; + int len = password.length(); + // initialization + unsigned char ku[64]; + while (count < 1048576) { // 1MB + for (int i = 0; i < 64; i++) + ku[i] =password[passIndex++ % len]; + count += 64; + if (m_authProto == MD5_AUTH) { + digestMD5.update(ku,64); + continue; + } + if (m_authProto == SHA1_AUTH) + digestSHA.update(ku,64); + } + + DataBlock aux; + if (m_authProto == MD5_AUTH) { + digestMD5.finalize(); + aux.append((void*)digestMD5.rawDigest(), digestMD5.rawLength()); + digestMD5.clear(); + } + else if (m_authProto == SHA1_AUTH) { + digestSHA.finalize(); + aux.append((void*)digestSHA.rawDigest(), digestSHA.rawLength()); + digestSHA.clear(); + } + authKey.clear(); + + // key localization + authKey.append(aux); + authKey.append(__plugin.getEngineID()); + authKey.append(aux); + + // obtain final key according to encryption method + if (m_authProto == SnmpUser::MD5_AUTH) { + digestMD5.update(authKey); + digestMD5.finalize(); + authKey.clear(); + authKey.append((void*)digestMD5.rawDigest(),digestMD5.rawLength()); + authKey.truncate(16); + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::generateAuthKey() [%p] - MD5 authKey generated %s", + this,digestMD5.hexDigest().substr(0,32).c_str()); + return authKey; + } + else if (m_authProto == SnmpUser::SHA1_AUTH) { + digestSHA.update(authKey); + digestSHA.finalize(); + authKey.clear(); + authKey.append((void*)digestSHA.rawDigest(),digestSHA.rawLength()); + authKey.truncate(20); + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::generateAuthKey() [%p] - SHA authKey generated %s", + this,digestSHA.hexDigest().substr(0,40).c_str()); + return authKey; + } + Debug(&__plugin,DebugInfo,"::generateAuthKey() [%p] - invalid auth protocol",this); + m_authKey.clear(); + return authKey; +} + +// generate an authentication information +void SnmpUser::generateAuthInfo() +{ + if (TelEngine::null(m_authPassword)) + return; + + m_authKey = generateAuthKey(m_authPassword); + m_k1.clear(); + m_k2.clear(); + for (unsigned int i = 0; i < 64; i++) { + u_int8_t val = 0; + if (i < m_authKey.length()) + val = m_authKey[i]; + u_int8_t x1 = val ^ 0x36; + u_int8_t x2 = val ^ 0x5c; + m_k1.append(&x1,1); + m_k2.append(&x2,1); + } + m_privKey = generateAuthKey(m_privPassword); +} + +/** + * SnmpV3MsgContainer + */ + +// validate a message +int SnmpV3MsgContainer::validate(Snmp::SNMPv3Message& msg) +{ + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::validate() [%p]",this); + int res = processHeader(msg); + if (res != SnmpAgent::SUCCESS) + return res; + res = processSecurityModel(msg); + if (res != SnmpAgent::SUCCESS) + return res; + + // if the auth flag is set, check the digest for the message + if (m_authFlag) { + res = checkAuth(msg); + if (res != SnmpAgent::SUCCESS) + return res; + } + // check the user data + res = checkUser(); + if (res != SnmpAgent::SUCCESS) + return res; + // if the privacy flag is set, decrypt the message + if (m_privFlag) { + res = decrypt(msg); + if (res != SnmpAgent::SUCCESS); + return res; + } + Debug(&__plugin,DebugAll,"SnmpV3MsgContainer::validate() [%p] - message %p validated",this,&msg); + return res; +} +// handle the request fom the SNMPv3 message +int SnmpV3MsgContainer::processRequest(Snmp::SNMPv3Message& msg) +{ + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::processRequest() [%p]",this); + if (msg.m_msgData->m_choiceType == Snmp::ScopedPduData::PLAINTEXT) + m_scopedPdu = msg.m_msgData->m_plaintext; + processScopedPdu(); + return SnmpAgent::SUCCESS; +} + +// prepare for sending a SNMPv3 message +int SnmpV3MsgContainer::prepareForSend(Snmp::SNMPv3Message& msg) +{ + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::prepareForSend() [%p]",this); + + // set the message flags + u_int8_t msgFlags = 0; + if (m_reportFlag) + msgFlags &= ~REPORT_FLAG; + if (m_authFlag) + msgFlags |= AUTH_FLAG; + if (m_privFlag) + msgFlags |= PRIVACY_FLAG; + msg.m_msgGlobalData->m_msgFlags.assign(&msgFlags,sizeof(msgFlags)); + + // make sure auth and encrypt parameters are empty + m_security.m_msgPrivacyParameters.clear(); + m_security.m_msgAuthenticationParameters.clear(); + m_security.m_msgAuthoritativeEngineID = __plugin.getEngineID(); + m_security.m_msgAuthoritativeEngineTime = __plugin.getEngineTime(); + m_security.m_msgAuthoritativeEngineBoots = __plugin.getEngineBoots(); + + if (!m_user && m_authFlag) + return SnmpAgent::MESSAGE_DROP; + // if the privacy flag is set, encrypt the pdu + if (m_user && m_privFlag && m_user->needsPriv()) { + msg.m_msgData->m_encryptedPDU.clear(); + encrypt(m_scopedPdu,msg.m_msgData->m_encryptedPDU); + msg.m_msgData->m_choiceType = Snmp::ScopedPduData::ENCRYPTEDPDU; + m_security.m_msgPrivacyParameters.append(m_msgSalt); + } + // if the auth flag is set, compute the message digest and set it in the message + if (m_user && m_authFlag && m_user->needsAuth()) { + m_security.m_msgAuthenticationParameters = s_zeroKey; + OctetString digest; + msgDigest(msg,digest); + m_security.m_msgAuthenticationParameters = digest; + } + // encode and set the security parameters + DataBlock data; + msg.m_msgSecurityParameters.clear(); + m_security.encode(msg.m_msgSecurityParameters); + return SnmpAgent::SUCCESS; +} + +// build a tooBigMessage +int SnmpV3MsgContainer::generateTooBigMsg(Snmp::SNMPv3Message& msg) +{ + Debug(&__plugin,DebugInfo,"SnmpV3MsgContainer::generateTooBigMsg() [%p]",this); + DataBlock data = m_scopedPdu->m_data; + Snmp::PDUs pdus; + pdus.decode(data); + Snmp::PDU* pdu = __plugin.getPDU(pdus); + if (!pdu) + return SnmpAgent::MESSAGE_DROP; + pdu->m_error_status = Snmp::PDU::s_tooBig_error_status; + pdu->m_error_index = 0; + if (!pdu->m_variable_bindings) + pdu->m_variable_bindings = new Snmp::VarBindList(); + pdu->m_variable_bindings->m_list.clear(); + data.clear(); + pdus.encode(data); + if (!m_scopedPdu) + return SnmpAgent::MESSAGE_DROP; + m_scopedPdu->m_data.clear(); + m_scopedPdu->m_data.append(data); + prepareForSend(msg); + return SnmpAgent::SUCCESS; +} + +// parse the header data from the message +int SnmpV3MsgContainer::processHeader(Snmp::SNMPv3Message& msg) +{ + Snmp::HeaderData* header = msg.m_msgGlobalData; + if (!header) { + Debug(&__plugin,DebugInfo,"SnmpV3MsgContainer::processHeader() - no header [%p]",this); + return SnmpAgent::MESSAGE_DROP; + } + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::processHeader('%p')",header); + // * msgId + m_msgId = header->m_msgID; + // * msgMaxSize + m_msgMaxSize = header->m_msgMaxSize; + // * msgFlags + u_int8_t msgFlags = (u_int8_t)(header->m_msgFlags.length() == 1 ? header->m_msgFlags[0] : 0); + + // get the message flags + m_reportFlag = ((msgFlags & REPORT_FLAG) == 0x0 ? false : true); + m_privFlag = ((msgFlags & PRIVACY_FLAG) == 0x0 ? false : true); + m_authFlag = ((msgFlags & AUTH_FLAG) == 0x0 ? false : true); + // * msgSecurityModel + m_securityModel = header->m_msgSecurityModel; + if (m_securityModel != USM_SEC_MODEL) { + Debug(&__plugin,DebugInfo,"SnmpV3MsgContainer::processHeader() [%p] - invalid security model=%d",this,m_securityModel); + return SnmpAgent::MESSAGE_DROP; + } + DDebug(&__plugin,DebugInfo,"SnmpV3MsgContainer::processHeader() found msgID = %d, m_msgMaxSize = %d, " + "reportFlag = %s, privFlag = %s, authFlag = %s",m_msgId,m_msgMaxSize,String::boolText(m_reportFlag), + String::boolText(m_privFlag),String::boolText(m_authFlag)); + + return SnmpAgent::SUCCESS; +} + +// parse and handle the security data +int SnmpV3MsgContainer::processSecurityModel(Snmp::SNMPv3Message& msg) +{ + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::processSecurityModel() [%p]",this); + + int r = m_security.decode(msg.m_msgSecurityParameters); + if (r < 0) + return SnmpAgent::MESSAGE_DROP; + + // extract from the message the engineID, engineBoots/Time and the username + OctetString authEngineId = m_security.m_msgAuthoritativeEngineID; + m_msgEngineBoots = m_security.m_msgAuthoritativeEngineBoots; + m_msgEngineTime = m_security.m_msgAuthoritativeEngineTime; + + m_user = __plugin.getUser(m_security.m_msgUserName.getString()); + + DDebug(&__plugin,DebugInfo,"SnmpV3MsgContainer::processSecurityModel found authEngineId = '%s', engineBoots = '%d', " + "engineTime = '%d', username = '%s'", authEngineId.toHexString().c_str(), + m_msgEngineBoots,m_msgEngineTime,(m_user ? m_user->toString().c_str() : "")); + + // check the engine data and if it doesn't match set the correct data and return a wrong engine id status + if (authEngineId.toHexString() != __plugin.getEngineID().toHexString()) + return SnmpAgent::WRONG_ENGINE_ID; + + int res = checkTimeWindow(); + if (res != SnmpAgent::SUCCESS) + return res; + return SnmpAgent::SUCCESS; +} + +// verify the message time against the engine time and the time window +int SnmpV3MsgContainer::checkTimeWindow() +{ + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::checkTimeWindow() [%p]",this); + u_int32_t engineBoots = __plugin.getEngineBoots(); + if (engineBoots == ENGINE_BOOTS_MAX || engineBoots != m_msgEngineBoots) + return SnmpAgent::WRONG_WINDOW_TIME; + + int32_t engineTime = (int32_t)__plugin.getEngineTime(); + if (((engineTime - TIMEFRAME_VAL) > (int32_t)m_msgEngineTime) || ((engineTime + TIMEFRAME_VAL) < (int32_t)m_msgEngineTime)) + return SnmpAgent::WRONG_WINDOW_TIME; + return SnmpAgent::SUCCESS; +} + +// check the user data provided in the message against locally stored data +int SnmpV3MsgContainer::checkUser() +{ + if (!m_user) { + Debug(&__plugin,DebugInfo,"SnmpV3MsgContainer::checkUser() - Unknown user name [%p]",this); + return SnmpAgent::WRONG_USER; + } + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::checkUser('%s') [%p]",m_user->toString().c_str(),this); + + if (m_authFlag != m_user->needsAuth()) { + Debug(&__plugin,DebugInfo,"SnmpV3MsgContainer::checkUser() [%p] - Unsupported security level 'auth' for user %s", + this,m_user->toString().c_str()); + return SnmpAgent::WRONG_SEC_LEVEL; + } + + if (m_privFlag != m_user->needsPriv()) { + Debug(&__plugin,DebugInfo,"SnmpV3MsgContainer::checkUser() [%p] - Unsupported security level 'priv' for user %s", + this,m_user->toString().c_str()); + return SnmpAgent::WRONG_SEC_LEVEL; + } + return SnmpAgent::SUCCESS; +} + +// handle the pdu from the SNMPv3 message +int SnmpV3MsgContainer::processScopedPdu() +{ + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::processScopedPdu(scopedPdu=%p) [%p]",m_scopedPdu,this); + if (!(m_scopedPdu && m_user)) + return SnmpAgent::MESSAGE_DROP; + + Snmp::PDUs pdus; + pdus.decode(m_scopedPdu->m_data); + int type = pdus.m_choiceType; + Snmp::PDU* decodedPdu = __plugin.getPDU(pdus); + __plugin.decodePDU(type,decodedPdu,m_user->accessLevel()); + pdus.m_choiceType = type; + if (type == Snmp::PDUs::RESPONSE) { + pdus.m_response = new Snmp::Response_PDU(); + pdus.m_response->m_Response_PDU = (decodedPdu ? decodedPdu : new Snmp::PDU()); + } + + m_scopedPdu->m_data.clear(); + pdus.encode(m_scopedPdu->m_data); + return SnmpAgent::SUCCESS; +} + +// check the digest received in the message +int SnmpV3MsgContainer::checkAuth(Snmp::SNMPv3Message& msg) +{ + if (!m_user) + return SnmpAgent::MESSAGE_DROP; + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::checkAuth('%s') [%p]",m_user->toString().c_str(),this); + //put digest on zero + OctetString authDigest = m_security.m_msgAuthenticationParameters; + m_security.m_msgAuthenticationParameters = s_zeroKey; + OctetString digest; + msgDigest(msg,digest); + + if (digest.toHexString() != authDigest.toHexString()) { + Debug(&__plugin,DebugInfo,"SnmpV3MsgContainer::checkAuth('%s') [%p] - wrong digest received on wire",m_user->toString().c_str(),this); + return SnmpAgent::WRONG_DIGEST; + } + DDebug(&__plugin,DebugInfo,"SnmpV3MsgContainer::checkAuth('%s') [%p] - AUTH SUCCESS",m_user->toString().c_str(),this); + return SnmpAgent::SUCCESS; +} + +// compute a message digest +void SnmpV3MsgContainer::msgDigest(Snmp::SNMPv3Message& msg, OctetString& digest) +{ + digest.clear(); + if (!m_user) + return; + if (!m_user->needsAuth()) + return; + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::msgDigest(%s) [%p]",m_user->toString().c_str(),this); + + const DataBlock& k1 = m_user->digestK1(); + const DataBlock& k2 = m_user->digestK2(); + + m_security.encode(digest); + msg.m_msgSecurityParameters.clear(); + msg.m_msgSecurityParameters.append(digest); + digest.clear(); + msg.encode(digest); + + // md51 = MD5 digest on k1 + msg, then md52 = MD5 digest on k2 + md51 + // msgDigest = md52[0..11] + // sha1 = SHA1 digest on k1 + msg, then sha2 = SHA1 digest on k2 + sha1 + // msgDigest = sha2[0..11] + if (m_user->authProto() == SnmpUser::MD5_AUTH) { + MD5 md5; + md5.update(k1); + md5.update(digest); + md5.finalize(); + + digest.clear(); + digest.append((void*)md5.rawDigest(),md5.rawLength()); + + md5.clear(); + md5.update(k2); + md5.update(digest); + md5.finalize(); + + digest.clear(); + digest.append((void*)md5.rawDigest(),md5.rawLength()); + digest.truncate(12); + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::msgDigest()[%p]:MD5 digest is %s",this,md5.hexDigest().substr(0,24).c_str()); + } + else if (m_user->authProto() == SnmpUser::SHA1_AUTH) { + SHA1 sha1; + sha1.update(k1); + sha1.update(digest); + sha1.finalize(); + + digest.clear(); + digest.append((void*)sha1.rawDigest(),sha1.rawLength()); + + sha1.clear(); + sha1.update(k2); + sha1.update(digest); + sha1.finalize(); + + digest.clear(); + digest.append((void*)sha1.rawDigest(),sha1.rawLength()); + digest.truncate(12); + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::msgDigest() [%p] : SHA1 digest is %s",this,sha1.hexDigest().substr(0,24).c_str()); + } +} + +// decrypt an encrypted pdu +int SnmpV3MsgContainer::decrypt(Snmp::SNMPv3Message& msg) +{ + if(msg.m_msgData && msg.m_msgData->m_choiceType != Snmp::ScopedPduData::ENCRYPTEDPDU) + return SnmpAgent::WRONG_ENCRYPT; + if (!msg.m_msgData || !m_user) + return SnmpAgent::MESSAGE_DROP; + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::decrypt() [%p]",this); + + DataBlock encryptedBlock = msg.m_msgData->m_encryptedPDU; + // get privacy key + DataBlock privKey = m_user->privKey(); + DataBlock encryptKey = privKey; + DataBlock initVector; + + // build the initialization vector from the key according to encryption method + if (m_user->privProto() == SnmpUser::DES_ENCRYPT) { + if (encryptedBlock.length() % 8 != 0 ) + return SnmpAgent::WRONG_ENCRYPT; + encryptKey.truncate(8); + DataBlock preIV = privKey; + preIV.truncate(16); + preIV.cut(-8); + //m_security.m_msgPrivacyParameters is the salt + for (unsigned int i = 0; i < m_security.m_msgPrivacyParameters.length(); i++) { + u_int8_t aux = preIV[i] ^ m_security.m_msgPrivacyParameters[i]; + initVector.append(&aux,1); + } + } + if (m_user->privProto() == SnmpUser::AES_ENCRYPT) { + encryptKey.truncate(16); + DataBlock aux = toNetworkOrder(m_msgEngineBoots,4); + initVector.append(aux); + aux = toNetworkOrder(m_msgEngineTime,4); + initVector.append(aux); + initVector.append(m_security.m_msgPrivacyParameters); + } + + //rfc3826 + Cipher* cipher = __plugin.getCipher(m_user->privProto()); + if (!cipher){ + Debug(&__plugin,DebugInfo,"Could not obtain %s cipher",lookup(m_user->privProto(),s_crypto,"")); + return SnmpAgent::WRONG_ENCRYPT; + } + // set the decrypt key + if (!cipher->setKey(encryptKey)) + return SnmpAgent::WRONG_ENCRYPT; + // set the initialization vector + if (!cipher->initVector(initVector)) + return SnmpAgent::WRONG_ENCRYPT; + // decrypt the data + cipher->decrypt(encryptedBlock); + // decode the pdu from the data + m_scopedPdu = new Snmp::ScopedPDU(); + if(m_scopedPdu->decode(encryptedBlock) < 0) + return SnmpAgent::WRONG_ENCRYPT; + + return SnmpAgent::SUCCESS; +} + +// encrypt the given pdu +int SnmpV3MsgContainer::encrypt(Snmp::ScopedPDU* pdu, DataBlock& encryptedPdu) +{ + DDebug(&__plugin,DebugAll,"SnmpV3MsgContainer::encrypt() pdu=[%p] [%p]",pdu,this); + if (!pdu ||!m_user) + return SnmpAgent::MESSAGE_DROP; + + pdu->encode(encryptedPdu); + + // obtain the engine salt + m_msgSalt.clear(); + u_int64_t engineSalt = __plugin.getEngineSalt(); + m_msgSalt = toNetworkOrder(engineSalt,8); + + DataBlock privKey = m_user->privKey(); + DataBlock encryptKey = privKey; + // build the initialization vector + DataBlock initVector; + if (m_user->privProto() == SnmpUser::DES_ENCRYPT) { + encryptKey.truncate(8); + DataBlock preIV = privKey; + preIV.truncate(16); + preIV.cut(-8); + for (unsigned int i = 0; i < m_msgSalt.length(); i++) { + u_int8_t aux = preIV[i] ^ m_msgSalt[i]; + initVector.append(&aux,1); + } + int r = encryptedPdu.length() % 8; + if(r != 0) + for (int i = 0; i < 8 - r; i++) + encryptedPdu.append(&s_zero,1); + } + else if (m_user->privProto() == SnmpUser::AES_ENCRYPT) { + encryptKey.truncate(16); + DataBlock aux = toNetworkOrder(m_msgEngineBoots,4); + initVector.append(aux); + aux = toNetworkOrder(m_msgEngineTime,4); + initVector.append(aux); + initVector.append(m_msgSalt); + } + + Cipher* cipher = __plugin.getCipher(m_user->privProto()); + if (!cipher) { + Debug(&__plugin,DebugInfo,"Could not obtain '%s' cipher",lookup(m_user->privProto(),s_crypto,"")); + return SnmpAgent::MESSAGE_DROP; + } + + // set the encryption key + if (!cipher->setKey(encryptKey)) + return SnmpAgent::MESSAGE_DROP; + + // set the initialization vector + if (!cipher->initVector(initVector)) + return SnmpAgent::MESSAGE_DROP; + + // encrypt the data + cipher->encrypt(encryptedPdu); + return SnmpAgent::SUCCESS; +} + +/** + * SnmpAgent + */ +SnmpAgent::SnmpAgent() + : Module("snmpagent","misc"), + m_init(false), m_msgQueue(0), m_mibTree(0), + m_engineBoots(0),m_startTime(0), m_silentDrops(0), + m_salt(0), + m_trapHandler(0), + m_enabledTraps(true), m_traps(0), + m_trapUser(0), + m_cipherAES(0), + m_cipherDES(0) +{ + Output("Loaded module SNMP Agent"); +} + +SnmpAgent::~SnmpAgent() +{ + Output("Unloaded module SNMP Agent"); +} + +bool SnmpAgent::unload() +{ + Debug(this,DebugAll,"::unload()"); + if (!lock(500000)) + return false; + + uninstallRelays(); + Engine::uninstall(m_trapHandler); + unlock(); + return true; +} + +void SnmpAgent::initialize() +{ + Output("Initializing module SNMP Agent"); + + s_cfg = Engine::configFile("ysnmpagent"); + s_cfg.load(); + + // load community strings for SNMPv2 or prior + m_roCommunity = s_cfg.getValue("snmp_v2","ro_community",""); + m_rwCommunity = s_cfg.getValue("snmp_v2","rw_community",""); + m_rcCommunity = s_cfg.getValue("snmp_v2","rc_community",""); + + // load the file containing the Yate OID and initialize the tree + String treeConf = s_cfg.getValue("general","mibs"); + if (treeConf.null()) + treeConf << Engine::sharedPath() << Engine::pathSeparator() << + "data" << Engine::pathSeparator() << "snmp_mib.conf"; + m_mibTree = new AsnMibTree(treeConf); + + // get information needed for the computation of the agents' engine id (SNMPv3) + int engineFormat = s_cfg.getIntValue("snmp_v3","engine_format",TEXT); + String engineInfo = s_cfg.getValue("snmp_v3","engine_info",""); + m_engineId = genEngineId(engineFormat,engineInfo); + + // read configuration for traps + m_enabledTraps = s_cfg.getBoolValue("traps","enable_traps",true); + String remoteIP = s_cfg.getValue("traps","remote_ip","localhost"); + String remotePort = s_cfg.getValue("traps","remote_port","162"); + s_remote = buildDestination(remoteIP,remotePort); + if (!s_remote.valid()) + m_enabledTraps = false; + // initiate the user for sending SNMPv3 traps + String trapUser = s_cfg.getValue("traps","trap_user",""); + if (!TelEngine::null(trapUser) && s_cfg.getSection(trapUser)) + m_trapUser = new SnmpUser(s_cfg.getSection(trapUser)); + + for (unsigned int i = 0; i < s_cfg.sections(); i++) { + NamedList* sec = s_cfg.getSection(i); + if (!sec || (*sec == "general") || (*sec == "snmp_v2") || (*sec == "snmp_v3") + || (*sec == "traps") || (*sec == s_cfg.getValue("traps","trap_user",""))) + continue; + m_users.append(new SnmpUser(sec)); + } + + // load saved data + s_saveCfg = Engine::configFile("snmp_data"); + s_saveCfg.load(); + + // read last used snmpEngineID + String snmpEngineId = s_saveCfg.getValue("snmp_v3","engine_id",""); + if (snmpEngineId == m_engineId.toHexString()) { + // the snmpEngineID hasn't been modified so snmpEngineBoots must be increased + // if there is no engineBoots value saved, it must be set to ENGINE_BOOTS_MAX + m_engineBoots = s_saveCfg.getIntValue("snmp_v3","engine_boots",ENGINE_BOOTS_MAX); + if (m_engineBoots == ENGINE_BOOTS_MAX) + Debug(this,DebugWarn,"snmpEngineBoots reached maximum value, snmpEngineID must be reconfigured"); + else + m_engineBoots++; + s_saveCfg.setValue("snmp_v3","engine_boots",(int)m_engineBoots); + } + else { + // reset snmpEngineBoots if snmpEngineID has changed. Save the new value of snmpEngineID + Debug(this,DebugInfo,"snmpEngineID has been reconfigured, resetting snmpEngineBoots"); + s_saveCfg.setValue("snmp_v3","engine_id",m_engineId.toHexString()); + m_engineBoots = 1; + s_saveCfg.setValue("snmp_v3","engine_boots",(int)m_engineBoots); + } + s_saveCfg.save(); + + // load disabled traps + String traps = s_saveCfg.getValue("traps_conf","traps_disabled",""); + m_traps = traps.split(',',false); + + // USM inits + // initialize all counters for USM stats + for (int i = 0; i < 7; i++) + m_stats[i] = 0; + + // init engine start time + m_startTime = Time::secNow(); + // init encryption salt + m_salt = 0; + m_salt += m_engineBoots; + m_salt <<= 32; + m_salt += m_startTime; + + m_silentDrops = 0; + + AsnMib* yateMib = (m_mibTree ? m_mibTree->find("yate") : 0); + if (yateMib) + s_yateRoot = yateMib->toString(); + + // port on which to listen for SNMP requests + int snmpPort = s_cfg.getIntValue("general","port",161); + // thread priority + Thread::Priority threadPrio = Thread::priority(s_cfg.getValue("general","thread")); + + // do module init, install message handlers + if (!m_init) { + m_init = true; + setup(); + installRelay(Halt); + m_msgQueue = new SnmpMsgQueue(this,threadPrio,snmpPort); + if (!m_msgQueue->init()) + m_msgQueue = 0; + if (m_trapHandler) + return; + m_trapHandler = new TrapHandler(); + Engine::install(m_trapHandler); + } +} + +bool SnmpAgent::received(Message& msg, int id) +{ + if (id == Halt) { + // save and cleanup + DDebug(&__plugin,DebugInfo,"::received() - Halt Message"); + String traps = ""; + for (ObjList* o = m_traps->skipNull(); o; o = o->skipNext()) { + String* str = static_cast(o->get()); + traps.append(*str,","); + } + s_saveCfg.setValue("traps_conf","traps_disable",traps); + s_saveCfg.save(); + if (m_traps) + TelEngine::destruct(m_traps); + Engine::uninstall(m_trapHandler); + if (m_cipherAES) + TelEngine::destruct(m_cipherAES); + if (m_cipherDES) + TelEngine::destruct(m_cipherDES); + } + return Module::received(msg,id); +} + + +int SnmpAgent::processMsg(SnmpMessage* msg) +{ + Debug(&__plugin,DebugAll,"::processMsg([%p])",msg); + if(!msg) + return MESSAGE_DROP; + DataBlock data = msg->data(); + + // determine the version of the SNMP message + Snmp::Message msgSnmp; + int l = msgSnmp.decode(data); + if (l > 0) { + // SNMPv2 message + Debug(&__plugin,DebugAll,"::processMsg() - received %s message msg=%p",lookup(msgSnmp.m_version,s_proto,""),&msgSnmp); + // try to handle it + if (processSnmpV2Msg(msgSnmp) < 0) { + m_silentDrops++; + return MESSAGE_DROP; + } + data.clear(); + // encode response in case of successful handling into data + msgSnmp.encode(data); + } + else { + data = msg->data(); + Snmp::SNMPv3Message m; + l = m.decode(data); + if (l >= 0) { + // SNMPv3 message + Debug(&__plugin,DebugAll,"::processMsg() - received SNMPv3 message msg=%p",&m); + if(processSnmpV3Msg(m) < 0) { + m_silentDrops++; + return MESSAGE_DROP; + } + data.clear(); + // encode response in case of successful handling into data + m.encode(data); + } + else { + Debug(&__plugin,DebugNote,"::processMsg() - unknown SNMP protocol version"); + return MESSAGE_DROP; + } + } + Debug(&__plugin,DebugAll,"::processMsg([%p]) - successful",msg); + // set the data for the message wrapper + msg->setData(data); + // send it and return with success + if (m_msgQueue) + m_msgQueue->sendMsg(msg); + + return SUCCESS; +} + +// process a SNMPv2 message +int SnmpAgent::processSnmpV2Msg(Snmp::Message& msg) +{ + DDebug(&__plugin,DebugAll,"::processSnmpV2Msg() [%p]",&msg); + // verify community string + String community = msg.m_community.getString(); + int access = AsnMib::notAccessible; + if (!m_rcCommunity.null() && m_rcCommunity == community) + access = AsnMib::readCreate; + else if (!m_rwCommunity.null() && m_rwCommunity == community) + access = AsnMib::readWrite; + else if (!m_roCommunity.null() && m_roCommunity == community) + access = AsnMib::readOnly; + if (access == AsnMib::notAccessible) { + Debug(&__plugin,DebugInfo,"::processSnmpV2Msg() [%p] - message arrived with wrong community string, message dropped",&msg); + return MESSAGE_DROP; + } + // obtain pdus and do decoding + DataBlock pdu = msg.m_data; + if (pdu.length() > 0) { + Snmp::PDUs chosen; + int l = chosen.decode(pdu); + if (l < 0) + return MESSAGE_DROP; + Snmp::BulkPDU* bulkReq = 0; + Snmp::PDU* req = getPDU(chosen); + if (req) { + // handle received pdu according to type + decodePDU(chosen.m_choiceType,req,access); + if (chosen.m_choiceType == Snmp::PDUs::RESPONSE) + chosen.m_response->m_Response_PDU = (req ? req : new Snmp::PDU()); + } + else if (chosen.m_choiceType == Snmp::PDUs::GET_BULK_REQUEST) { + bulkReq = chosen.m_get_bulk_request->m_GetBulkRequest_PDU; + if (bulkReq) { + // handle bulk request + Snmp::PDU* responsePDU = decodeBulkPDU(chosen.m_choiceType,bulkReq,access); + chosen.m_response->m_Response_PDU = (responsePDU ? responsePDU : new Snmp::PDU()); + chosen.m_choiceType = Snmp::PDUs::RESPONSE; + } + } + // encode the result and set it in the message wrapper + msg.m_data.clear(); + chosen.encode(msg.m_data); + } + DDebug(&__plugin,DebugAll,"::processSnmpV2Msg() [%p] - successful",&msg); + return SUCCESS; +} + +// handle a request pdu, generate response +void SnmpAgent::decodePDU(int& reqType, Snmp::PDU* obj, const int& access) +{ + DDebug(&__plugin,DebugAll,"::decodePDU([%p]) - pdu type is %s",obj,lookup(reqType,s_pdus,"")); + if (!obj) { + Debug(&__plugin,DebugMild,"No SNMP PDU to decode"); + return; + } + + // obtain list of requested OIDs + Snmp::VarBindList* list = obj->m_variable_bindings; + if (!list) + return; + obj->m_variable_bindings = new Snmp::VarBindList(); + + for (unsigned int i = 0; i < list->m_list.count(); i++) { + Snmp::VarBind* obji = static_cast(list->m_list[i]); + if (obji) { + int res = 0; + AsnValue val; + // for each OID requested, handle the request accordingly + switch (reqType) { + case Snmp::PDUs::GET_REQUEST: + res = processGetReq(obji,&val,obj->m_error_status,access); + break; + case Snmp::PDUs::GET_NEXT_REQUEST: + res = processGetNextReq(obji,&val,obj->m_error_status,access); + break; + case Snmp::PDUs::SET_REQUEST: + res = processSetReq(obji,obj->m_error_status,access); + break; + case Snmp::PDUs::SNMPV2_TRAP: + case Snmp::PDUs::INFORM_REQUEST: + case Snmp::PDUs::REPORT: + default: + break; + } + // if the request was handled, but an error was returned, set the error in the response + if (res == 1 && obj->m_error_status) { + obj->m_error_index = i + 1; + obj->m_variable_bindings = list; + break; + } + // if the request was not handled, set a generic error + if (!res) { + obj->m_error_status = Snmp::PDU::s_genErr_error_status; + obj->m_error_index = i + 1; + break; + } + assignValue(obji,&val); + obj->m_variable_bindings->m_list.append(obji); + } + } + reqType = Snmp::PDUs::RESPONSE; +} + +// handle a GetRequest for a single variable binding +int SnmpAgent::processGetReq(Snmp::VarBind* varBind, AsnValue* value, int& error, const int& access) +{ + DDebug(&__plugin,DebugInfo,"::processGetRequest() - varBind [%p], value [%p]",varBind,value); + if (!(varBind && value && m_mibTree)) + return 0; + // obtain the OID + Snmp::ObjectName* objName = varBind->m_name; + if (!objName) + return 0; + + ASNObjId oid = objName->m_ObjectName; + + // try to find the OID in the tree, if not found set the appropiate error and return + AsnMib* mib = m_mibTree->find(oid); + if (!mib) { + varBind->m_choiceType = Snmp::VarBind::NOSUCHOBJECT; + return 1; + } + + // get the access level of the requested oid, if it doesn't match the access level of the request, set error and return + if (mib->getAccessValue() < access) { + varBind->m_choiceType = Snmp::VarBind::NOSUCHOBJECT; + return 1; + } + DDebug(&__plugin,DebugInfo,"::processGetRequest() - varBind [%p], value [%p], oid %s",varBind,value,oid.toString().c_str()); + unsigned int index = mib->index(); + objName->m_ObjectName = mib->getOID(); + mib->setIndex(0); + // obtain the string equivalent of the OID (the name of the oid) + String askFor = mib->getName(); + if (TelEngine::null(askFor)) { + varBind->m_choiceType = Snmp::VarBind::NOSUCHOBJECT; + return 1; + } + // try to get its value + *value = makeQuery(askFor,index,mib); + String typeStr = mib->getType(); + // get the type of the OID's value (integer,string,OID?) and set it + int type = lookup(typeStr,s_types,0); + if (type != 0) + value->setType(type); + // if the is no value for the requested OID, return with error set + if (!value || value->getValue().null()) { + varBind->m_choiceType = Snmp::VarBind::NOSUCHINSTANCE; + return 1; + } + return 1; +} + +// handle a GetNextRequest +int SnmpAgent::processGetNextReq(Snmp::VarBind* varBind, AsnValue* value, int& error, const int& access) +{ + DDebug(&__plugin,DebugInfo,"::processGetNextRequest() - varBind [%p], value [%p]",varBind,value); + if (!(varBind && value && m_mibTree)) + return 0; + // obtain the OID in the request + Snmp::ObjectName* objName = varBind->m_name; + if (!objName) + return 0; + + ASNObjId oid = objName->m_ObjectName; + AsnMib *next = 0, *aux = 0; + + next = m_mibTree->findNext(oid); + unsigned int index = next->index(); + + // obtain the value for the next oid + while (next) { + aux = next; + String askFor = next->getName(); + if (TelEngine::null(askFor)) { + varBind->m_choiceType = Snmp::VarBind::NOSUCHINSTANCE; + next->setIndex(0); + return 1; + } + *value = makeQuery(askFor,index,next); + int type = lookup(next->getType(),s_types,0); + if (type != 0) + value->setType(type); + if (!value || value->getValue().null()) { + if (!index) { + index++; + continue; + } + else { + oid = next->getOID(); + next = m_mibTree->findNext(oid); + index = 0; + aux->setIndex(0); + aux = next; + continue; + } + } + else { + next->setIndex(index); + objName->m_ObjectName = next->getOID(); + next->setIndex(0); + return 1; + } + } + // no OID with a value was found, set end of mib view + varBind->m_choiceType = Snmp::VarBind::ENDOFMIBVIEW; + return 1; +} + +// process a SetRequest +int SnmpAgent::processSetReq(Snmp::VarBind* varBind, int& error, const int& access) +{ + // !NOTE : Yate will not allow setting values. Besides the enableTrap and disableTrap, it will always return with error + DDebug(&__plugin,DebugInfo,"::setRequest() - varBind [%p] userAccess %d",varBind,access); + if (!(varBind && m_mibTree)) + return 0; + Snmp::ObjectName* objName = varBind->m_name; + if (!objName) + return 0; + if (access < AsnMib::readWrite) { + error = Snmp::PDU::s_noAccess_error_status; + return 1; + } + + ASNObjId oid = objName->m_ObjectName; + AsnMib* mib = m_mibTree->find(oid); + if (!mib) { + error = Snmp::PDU::s_noAccess_error_status; + return 1; + } + + // check access level + int oidAccess = mib->getAccessValue(); + switch (oidAccess) { + case AsnMib::notAccessible: + case AsnMib::accessibleForNotify: + error = Snmp::PDU::s_noAccess_error_status; + return 1; + break; + case AsnMib::readOnly: + error = Snmp::PDU::s_notWritable_error_status; + return 1; + break; + case AsnMib::readWrite: + case AsnMib::readCreate: + default: + break; + } + + // set value + String name = mib->getName(); + setValue(name,varBind,error); + return 1; +} + +// set a value for YATE +void SnmpAgent::setValue(const String& varName, Snmp::VarBind* val, int& error) +{ + DDebug(this,DebugAll,"::setValue('%s', [%p])",varName.c_str(),val); + if (!val) { + error = Snmp::PDU::s_wrongType_error_status; + return; + } + if (!m_mibTree) { + error = Snmp::PDU::s_noCreation_error_status; + return; + } + // only if the variable asked to be set are these + if (varName == "enableTrap" || varName == "disableTrap") { + DataBlock data = getVal(val); + if (!data.length()) + return; + String valStr((const char*)data.data(),data.length()); + ASNObjId oid = valStr; + AsnMib* mib = m_mibTree->find(oid); + if (!mib) { + Debug(this,DebugInfo,"::setValue('%s', [%p]), given oid value not found",varName.c_str(),val); + error = Snmp::PDU::s_noCreation_error_status; + return; + } + if (varName == "enableTrap") + m_traps->remove(mib->getName()); + else if (varName == "disableTrap") { + if (!m_traps->find(mib->getName())) + m_traps->append(new String(mib->getName())); + } + } + else + error = Snmp::PDU::s_notWritable_error_status; + +} + +// handle a GetBulkRequest +Snmp::PDU* SnmpAgent::decodeBulkPDU(int& reqType, Snmp::BulkPDU* pdu, const int& access) +{ + DDebug(&__plugin,DebugInfo,"::decodeBulkPDU() pdu [%p]", pdu); + if (!(pdu && m_mibTree)) { + Debug(&__plugin,DebugMild,"::decodeBulkPDU() : no pdu to decode"); + return 0; + } + + int nonRepeaters = pdu->m_non_repeaters; + int maxRepetitions = pdu->m_max_repetitions; + Snmp::VarBindList* list = pdu->m_variable_bindings; + DDebug(&__plugin,DebugInfo,"decodeBulkPDU : PDU [%p] list has size %d, non-Repeaters %d, max-Repetitions %d", + pdu,list->m_list.count(),nonRepeaters,maxRepetitions); + + Snmp::PDU* retPdu = new Snmp::PDU(); + int i = 0; + int error = 0; + + // handle non-repeaters + ObjList* o = list->m_list.skipNull(); + for (; o; o = o->skipNext()) { + if (i >= nonRepeaters) + break; + Snmp::VarBind* var = static_cast(o->get()); + if (var) { + AsnValue* val = 0; + int res = processGetNextReq(var,val,error,access); + if (res == 1 && error) { + retPdu->m_error_index = i + 1; + retPdu->m_error_status = error; + break; + } + if (!res) { + retPdu->m_error_status = Snmp::PDU::s_genErr_error_status; + retPdu->m_error_index = i + 1; + break; + } + assignValue(var,val); + retPdu->m_variable_bindings->m_list.append(var); + i++; + } + } + // handle repeaters + int j = 0; + while (j < maxRepetitions) { + for (ObjList* l = o->skipNull(); l; l = l->skipNext()) { + Snmp::VarBind* var = static_cast(l->get()); + if (var) { + AsnValue* val = 0; + int res = processGetNextReq(var,val,error,access); + if (res == 1 && error) { + retPdu->m_error_index = i + 1; + retPdu->m_error_status = error; + break; + } + if (!res) { + retPdu->m_error_status = Snmp::PDU::s_genErr_error_status; + retPdu->m_error_index = i + 1; + break; + } + assignValue(var,val); + retPdu->m_variable_bindings->m_list.append(var); + l->set(var,false); + } + } + if (error) + break; + j++; + } + return retPdu; +} + +// set the value for a variable binding +void SnmpAgent::assignValue(Snmp::VarBind* varBind, AsnValue* val) +{ + if (!varBind || !(val && val->getValue())) + return; + XDebug(&__plugin,DebugAll,"::assignValue([%p], [%p]) - data:%s, type:%d = %s", + varBind,val,val->getValue().c_str(),val->type(),lookup(val->type(),s_types,"")); + + // set the type of the varbind and assign a value object for it + varBind->m_choiceType = Snmp::VarBind::VALUE; + Snmp::ObjectSyntax* objSyn = new Snmp::ObjectSyntax(); + varBind->m_value = objSyn; + + Snmp::SimpleSyntax* simple = objSyn->m_simple; + Snmp::ApplicationSyntax* app = objSyn->m_application_wide; + // assign value according to type + switch (val->type()) { + case AsnValue::INTEGER: + objSyn->m_choiceType = Snmp::ObjectSyntax::SIMPLE; + objSyn->m_simple = simple; + simple->m_choiceType = Snmp::SimpleSyntax::INTEGER_VALUE; + simple->m_integer_value =(int32_t)val->getValue().toInteger(); + break; + case AsnValue::STRING: + objSyn->m_choiceType = Snmp::ObjectSyntax::SIMPLE; + objSyn->m_simple = simple; + simple->m_choiceType = Snmp::SimpleSyntax::STRING_VALUE; + simple->m_string_value = val->getValue(); + break; + case AsnValue::OBJECT_ID: + objSyn->m_choiceType = Snmp::ObjectSyntax::SIMPLE; + objSyn->m_simple = simple; + simple->m_choiceType = Snmp::SimpleSyntax::OBJECTID_VALUE; + simple->m_objectID_value = (const char*) val->getValue().c_str(); + break; + case AsnValue::IPADDRESS: + objSyn->m_choiceType = Snmp::ObjectSyntax::APPLICATION_WIDE; + objSyn->m_application_wide = app; + app->m_choiceType = Snmp::ApplicationSyntax::IPADDRESS_VALUE; + app->m_ipAddress_value->m_IpAddress = String(val->getValue()); + break; + case AsnValue::COUNTER: + objSyn->m_choiceType = Snmp::ObjectSyntax::APPLICATION_WIDE; + objSyn->m_application_wide = app; + app->m_choiceType = Snmp::ApplicationSyntax::COUNTER_VALUE; + app->m_counter_value->m_Counter32 = (u_int32_t)val->getValue().toInteger(); + break; + case AsnValue::TIMETICKS: + objSyn->m_choiceType = Snmp::ObjectSyntax::APPLICATION_WIDE; + objSyn->m_application_wide = app; + app->m_choiceType = Snmp::ApplicationSyntax::TIMETICKS_VALUE; + app->m_timeticks_value-> m_TimeTicks = (u_int32_t)val->getValue().toInteger(); + break; + case AsnValue::ARBITRARY: + objSyn->m_choiceType = Snmp::ObjectSyntax::APPLICATION_WIDE; + objSyn->m_application_wide = app; + app->m_choiceType = Snmp::ApplicationSyntax::ARBITRARY_VALUE; + app->m_arbitrary_value->m_Opaque = val->getValue(); + break; + case AsnValue::BIG_COUNTER: + objSyn->m_choiceType = Snmp::ObjectSyntax::APPLICATION_WIDE; + objSyn->m_application_wide = app; + app->m_choiceType = Snmp::ApplicationSyntax::BIG_COUNTER_VALUE; + app->m_big_counter_value->m_Counter64 = *((u_int64_t*)val->getValue().c_str()); + break; + case AsnValue::UNSIGNED_INTEGER: + objSyn->m_choiceType = Snmp::ObjectSyntax::APPLICATION_WIDE; + objSyn->m_application_wide = app; + app->m_choiceType = Snmp::ApplicationSyntax::UNSIGNED_INTEGER_VALUE; + app->m_unsigned_integer_value->m_Unsigned32 = (u_int32_t)val->getValue().toInteger(); + break; + default: + Debug(&__plugin, DebugNote, "unknown value"); + } +} + +/** + * Function for handling a v3 SNMP message + * Message structure + * msgVersion = 3 + * msgGlobalData + * - msgId + * - msgMaxSize + * - msgFlags ( report, auth, priv) + * - msgSecurityModel + * msgSecurityParameters - ! NOTE it's a string of octets which should be decoded according to the security model + * msgData + * - plain text + * - contextEngineID + * - contextName + * - data - PDU + * or + * - encrypted Data - string to be decrypted according the encryption methos (DES-CBC / AES-CFB) + */ +int SnmpAgent::processSnmpV3Msg(Snmp::SNMPv3Message& msg) +{ + Debug(&__plugin,DebugAll,"::processSnmpV3Msg() [%p]",&msg); + // initialize a SNMPv3 container + SnmpV3MsgContainer msgContainer; + // message is valid? + int secRes = msgContainer.validate(msg); + if (secRes == MESSAGE_DROP) { + Debug(&__plugin,DebugNote, "::processSnmpV3Msg() - message not validated, silent drop"); + return MESSAGE_DROP; + } + + // if a error was found validating the message and the reportableFlag is set, generate a ReportPDU + if (secRes) { + if (msgContainer.reportable()) { + if (generateReport(msg,secRes,msgContainer) < 0) + return MESSAGE_DROP; + return secRes; + } + else { + Debug(&__plugin,DebugNote,"::processSnmpV3Msg() - an error ocurred during SNMPv3 message processing, further processing aborted"); + return MESSAGE_DROP; + } + } + // generate a ResponsePDU otherwise + if (generateResponse(msg,msgContainer) == MESSAGE_DROP) + return MESSAGE_DROP; + return SUCCESS; +} + +// build a ReportPDU +int SnmpAgent::generateReport(Snmp::SNMPv3Message& msg, const int& secRes, SnmpV3MsgContainer& cont) +{ + Debug(&__plugin,DebugInfo,"::generateReport() - %s",lookup(secRes,s_errors,"unknown cause")); + if (!m_mibTree) + return MESSAGE_DROP; + if (!msg.m_msgGlobalData) + return MESSAGE_DROP; + // reset the message flags + cont.setReportFlag(false); + cont.setPrivFlag(false); + if (secRes == WRONG_DIGEST || secRes == WRONG_USER) + cont.setAuthFlag(false); + + // extract from the ScopedPDU the PDU + Snmp::ScopedPduData* data = msg.m_msgData; + if (!msg.m_msgData) + msg.m_msgData = new Snmp::ScopedPduData(); + int choice = data->m_choiceType; + data->m_choiceType = Snmp::ScopedPduData::PLAINTEXT; + Snmp::ScopedPDU* pdu = 0; + Snmp::PDUs p; + if (choice == Snmp::ScopedPduData::PLAINTEXT) { + pdu = data->m_plaintext; + p.decode(pdu->m_data); + p.m_report->m_Report_PDU = getPDU(p); + } + if (!pdu) { + pdu = new Snmp::ScopedPDU(); + p.m_report->m_Report_PDU = new Snmp::PDU(); + } + + pdu->m_contextEngineID = m_engineId; + pdu->m_contextName = pdu->m_contextName; + // set the PDUs type + p.m_choiceType = Snmp::PDUs::REPORT; + // the error information + p.m_report->m_Report_PDU->m_error_status = Snmp::PDU::s_noError_error_status; + p.m_report->m_Report_PDU->m_error_index = 0; + // clear the VarBindList + p.m_report->m_Report_PDU->m_variable_bindings->m_list.clear(); + Snmp::VarBind* var = new Snmp::VarBind(); + + AsnValue val; + AsnMib* mib = 0; + + // look up the cause for non validating the message + String stat = lookup(secRes,s_stats,""); + if (!stat.null()) { + // find its OID + mib = m_mibTree->find(stat); + // increase the counter for USM stats + m_stats[secRes]++; + // set the value + if (mib) { + var->m_name->m_ObjectName = mib->getOID(); + val.setValue(String(m_stats[secRes])); + val.setType(AsnValue::COUNTER); + } + } + + if (val.getValue().length() == 0) + return MESSAGE_DROP; + + // set the value in the ReportPDU + assignValue(var,&val); + p.m_report->m_Report_PDU->m_variable_bindings->m_list.append(var); + + // build the message + pdu->m_data.clear(); + p.encode(pdu->m_data); + if (!msg.m_msgData) + return MESSAGE_DROP; + msg.m_msgData->m_plaintext = pdu; + cont.prepareForSend(msg); + return SUCCESS; +} + +// build a ResponsePDU +int SnmpAgent::generateResponse(Snmp::SNMPv3Message& msg, SnmpV3MsgContainer& msgContainer) +{ + DDebug(&__plugin,DebugAll,"::generateResponse() for msg=%p",&msg); + // process the request (Get/GetNext/SetRequest) + msgContainer.processRequest(msg); + + // set the security parameters for the ResponsePDU + msgContainer.prepareForSend(msg); + + // encode the message + DataBlock ret; + msg.encode(ret); + // if it passes the maximum length for a SNMP message return a tooBig message + if ((int)ret.length() > msgContainer.msgMaxSize()) + return msgContainer.generateTooBigMsg(msg); + return SUCCESS; +} + +// get a PDU +Snmp::PDU* SnmpAgent::getPDU(Snmp::PDUs& p) +{ + Snmp::PDU* pdu = 0; + switch (p.m_choiceType) { + case Snmp::PDUs::GET_REQUEST: + pdu = p.m_get_request->m_GetRequest_PDU; + p.m_get_request->m_GetRequest_PDU = 0; + return pdu; + case Snmp::PDUs::GET_NEXT_REQUEST: + pdu = p.m_get_next_request->m_GetNextRequest_PDU; + p.m_get_next_request->m_GetNextRequest_PDU = 0; + return pdu; + case Snmp::PDUs::SET_REQUEST: + pdu = p.m_set_request->m_SetRequest_PDU; + p.m_set_request->m_SetRequest_PDU = 0; + return pdu; + case Snmp::PDUs::RESPONSE: + pdu = p.m_response->m_Response_PDU; + p.m_response->m_Response_PDU = 0; + return pdu; + case Snmp::PDUs::INFORM_REQUEST: + pdu = p.m_inform_request->m_InformRequest_PDU; + p.m_inform_request->m_InformRequest_PDU = 0; + return pdu; + case Snmp::PDUs::SNMPV2_TRAP: + pdu = p.m_snmpV2_trap->m_SNMPv2_Trap_PDU; + p.m_snmpV2_trap->m_SNMPv2_Trap_PDU = 0; + return pdu; + case Snmp::PDUs::REPORT: + pdu = p.m_report->m_Report_PDU; + p.m_report->m_Report_PDU = 0; + return pdu; + default: + break; + } + return 0; +} + +// build a remote destination +SocketAddr SnmpAgent::buildDestination(const String& ip, const String& port) +{ + SocketAddr dest(AF_INET); + dest.host(ip); + dest.port(port.toInteger()); + return dest; +} + +// build a Variable Binding list containing the mandatory OIDs for a trap +Snmp::VarBindList* SnmpAgent::addTrapOIDs(String& notifOID) +{ + if (!m_mibTree) + return 0; + Snmp::VarBindList* list = new Snmp::VarBindList(); + + // add sysUpTime + AsnMib* mib = m_mibTree->find("sysUpTime"); + if (!mib) + return 0; + + Snmp::VarBind* sysUpTime = new Snmp::VarBind(); + sysUpTime->m_name->m_ObjectName = mib->getOID(); + u_int32_t sysTime = (Time::secNow() - m_startTime) * 100; // measured hundreths of a second + AsnValue val(String(sysTime),AsnValue::TIMETICKS); + assignValue(sysUpTime,&val); + list->m_list.append(sysUpTime); + + // add trapOID + mib = m_mibTree->find("snmpTrapOID"); + if (!mib) + return 0; + Snmp::VarBind* trapOID = new Snmp::VarBind(); + trapOID->m_name->m_ObjectName = mib->getOID(); + AsnValue trOID(notifOID,AsnValue::OBJECT_ID); + assignValue(trapOID,&trOID); + list->m_list.append(trapOID); + + return list; +} + +// build a trap PDU for SNMPv2 +Snmp::SNMPv2_Trap_PDU SnmpAgent::buildTrapPDU(const String& name, const String& value, unsigned int index) +{ + DDebug(&__plugin,DebugAll,"::buildTrapPDU(notif='%s', value='%s', index='%u')",name.c_str(),value.c_str(),index); + Snmp::SNMPv2_Trap_PDU trapPDU;; + Snmp::PDU* pdu = trapPDU.m_SNMPv2_Trap_PDU; + if (!(m_mibTree && pdu)) + return trapPDU; + // set a requestID and error information + pdu->m_request_id = Time::secNow();// - m_startTime; + pdu->m_error_status = Snmp::PDU::s_noError_error_status; + pdu->m_error_index = 0; + + // try to find the OID of the notification received + AsnMib* notifMib = m_mibTree->find(name); + if (!notifMib) { + DDebug(&__plugin,DebugInfo,"::buildTrapPDU(notif='%s', value='%s') - no such notification exists", + name.c_str(),value.c_str()); + return trapPDU; + } + + // add the mandatory OIDs + notifMib->setIndex(index); + String oid = notifMib->getOID(); + pdu->m_variable_bindings = addTrapOIDs(oid); + if (!pdu->m_variable_bindings) { + Debug(&__plugin,DebugInfo,"::buildTrapPDU() - could not set sysUpTime and/or trapOID"); + return trapPDU; + } + + // add the trap OID with its value + Snmp::VarBind* trapVal = new Snmp::VarBind(); + trapVal->m_name->m_ObjectName = oid; + String typeStr = notifMib->getType(); + int type = lookup(typeStr,s_types,0); + AsnValue* v = new AsnValue(value,type); + assignValue(trapVal,v); + pdu->m_variable_bindings->m_list.append(trapVal); + // return the trapPDU + return trapPDU; +} + +// build a SNMPv3 TrapPDU +int SnmpAgent::buildTrapMsgV3(Snmp::SNMPv3Message& msg, DataBlock d) +{ + if (!m_trapUser) + return -1; + DDebug(&__plugin,DebugAll,"::buildTrapMsgV3() from msg=%p",&msg); + // build header data + msg.m_msgVersion = SNMP_VERSION_3; + Snmp::HeaderData* header = msg.m_msgGlobalData; + if (!header) + return -1; + header->m_msgID = Time::secNow() - m_startTime; + header->m_msgMaxSize = MSG_MAX_SIZE; + header->m_msgSecurityModel = USM_SEC_MODEL; + + // get data to fill + Snmp::ScopedPduData* scopedData = msg.m_msgData; + if (!scopedData) { + scopedData = new Snmp::ScopedPduData(); + msg.m_msgData = scopedData; + } + scopedData->m_choiceType = Snmp::ScopedPduData::PLAINTEXT; + Snmp::ScopedPDU* scopedPdu = scopedData->m_plaintext; + if (!scopedPdu) { + scopedPdu = new Snmp::ScopedPDU(); + scopedData->m_plaintext = scopedPdu; + } + scopedPdu->m_contextEngineID = m_engineId; + scopedPdu->m_contextName = ""; + scopedPdu->m_data = d; + + SnmpV3MsgContainer msgWrapper; + msgWrapper.setScopedPdu(scopedPdu); + msgWrapper.setReportFlag(false); + // get received security parameters + msgWrapper.setUser(m_trapUser); + // build the security parameters + Snmp::UsmSecurityParameters& sec = msgWrapper.getSecurity(); + sec.m_msgAuthoritativeEngineID = m_engineId; + sec.m_msgAuthoritativeEngineBoots = m_engineBoots; + sec.m_msgAuthoritativeEngineTime = Time::secNow() - m_startTime; + sec.m_msgUserName = m_trapUser->toString(); + sec.m_msgAuthenticationParameters = s_zeroKey; + + msgWrapper.prepareForSend(msg); + return 0; +} + +// check to see if a trap is disabled +bool SnmpAgent::trapDisabled(String& name) +{ + if (!m_mibTree) + return true; + AsnMib* mib = m_mibTree->find(name); + if (!mib) { + Debug(&__plugin,DebugMild,"Notification '%s' does not exist",name.c_str()); + return true; + } + String trapOid; + String oid = mib->toString(); + String disabledTraps = s_cfg.getValue("traps","disable_traps",""); + ObjList* list = disabledTraps.split(','); + if (!list) + return false; + for (ObjList* o = list->skipNull(); o; o = o->skipNext()) { + String* trap = static_cast(o->get()); + if (trap->endsWith(".*")) + *trap = trap->substr(0, trap->length() - 2); + AsnMib* trapMib = m_mibTree->find(*trap); + if (trapMib) + trapOid = trapMib->toString(); + if (trapOid == oid || oid.startsWith(trapOid)) { + TelEngine::destruct(list); + return true; + } + } + return false; +} + +// send a trap from a received notification +int SnmpAgent::sendNotification(String& name, String& value, unsigned int index) +{ + Debug(&__plugin,DebugAll,"::sendNotification('%s', '%s')",name.c_str(),value.c_str()); + + if (!m_enabledTraps) + return -1; + // check to see if the trap is enabled + if (trapDisabled(name) || (m_traps->count() && m_traps->find(name))) + return -1; + // check to see if trap handling has beed configured + NamedList* params = s_cfg.getSection("traps"); + if (!params) { + Debug(&__plugin,DebugMild,"::sendNotification('%s', '%s') -" + " traps have not been configured",name.c_str(),value.c_str()); + return -1; + } + + // build a new SNMP message wrapper + SnmpMessage* msgContainer = new SnmpMessage(); + msgContainer->setPeer(s_remote); + + // check to see that the right version for SNMP traps are configured + String protoStr = params->getValue("proto_version","SNMPv2c"); + int proto = lookup(protoStr,s_proto,0); + if (proto < SNMP_VERSION_2C) { + Debug(&__plugin,DebugStub,"::sendNotification() STUB : TRAPS FOR SNMPv1 NOT IMPLEMENTED"); + return -1; + } + else { + if (proto == SNMP_VERSION_2S) { + Debug(&__plugin,DebugStub,"::sendNotification() - SNMPv2S not supported"); + return -1; + } + } + + // build a trap pdu + Snmp::SNMPv2_Trap_PDU trapPDU = buildTrapPDU(name,value,index); + if (trapPDU.m_SNMPv2_Trap_PDU->m_variable_bindings->m_list.count() < 3) { + Debug(&__plugin,DebugWarn,"::sendNotification() - trap PDU incorrectly built - aborting the send of the notification"); + return -1; + } + + // build pdus + Snmp::PDUs pdus; + pdus.m_choiceType = Snmp::PDUs::SNMPV2_TRAP; + pdus.m_snmpV2_trap = &trapPDU; + DataBlock d; + pdus.encode(d); + pdus.m_snmpV2_trap = 0; + + DataBlock data; + // build the required version of a SNMP message + if (proto == SNMP_VERSION_2C) { + Snmp::Message msg; + msg.m_version = Snmp::Message::s_version_2_version; + msg.m_community = params->getValue("community",""); + msg.m_data = d; + msg.encode(data); + } + else if (proto == SNMP_VERSION_3) { + Snmp::SNMPv3Message msg; + if (buildTrapMsgV3(msg,d) == -1) + return -1; + msg.encode(data); + } + + // send the data of the message + msgContainer->setData(data); + if (m_msgQueue) + m_msgQueue->sendMsg(msgContainer); + return 0; +} + +// obtain from the openssl module a cipher for encryption +Cipher* SnmpAgent::getCipher(int cryptoType) +{ + DDebug(this,DebugAll,"::getCipher(%s)",lookup(cryptoType,s_crypto,"")); + if (cryptoType != SnmpUser::AES_ENCRYPT && cryptoType != SnmpUser::DES_ENCRYPT) + return 0; + + Message msg("engine.cipher"); + if (cryptoType == SnmpUser::AES_ENCRYPT) + msg.addParam("cipher","aes_cfb"); + if (cryptoType == SnmpUser::DES_ENCRYPT) + msg.addParam("cipher","des_cbc"); + CipherHolder* cHold = new CipherHolder; + msg.userData(cHold); + cHold->deref(); + return Engine::dispatch(msg) ? cHold->cipher() : 0; +} + +// get the value from a variable binding +DataBlock SnmpAgent::getVal(Snmp::VarBind* varBind) +{ + DDebug(this,DebugAll,"::getVal([%p])",varBind); + Snmp::ObjectSyntax* objSyn = varBind->m_value; + if (!objSyn) + return DataBlock(); + int type = -1; + switch (objSyn->m_choiceType) { + case Snmp::ObjectSyntax::SIMPLE: + type = objSyn->m_simple->m_choiceType; + switch (type) { + case Snmp::SimpleSyntax::INTEGER_VALUE: + return DataBlock((void*)&objSyn->m_simple->m_integer_value,sizeof(objSyn->m_simple->m_integer_value)); + case Snmp::SimpleSyntax::STRING_VALUE: + return DataBlock((void*)objSyn->m_simple->m_string_value.toString().c_str(),sizeof(objSyn->m_simple->m_string_value)); + case Snmp::SimpleSyntax::OBJECTID_VALUE: + return DataBlock((void*)objSyn->m_simple->m_objectID_value.toString().c_str(), + objSyn->m_simple->m_objectID_value.toString().length()); + default: + break; + } + break; + case Snmp::ObjectSyntax::APPLICATION_WIDE: + type = objSyn->m_application_wide->m_choiceType; + switch (type) { + case Snmp::ApplicationSyntax::IPADDRESS_VALUE: + return DataBlock((void*)objSyn->m_application_wide->m_ipAddress_value, + sizeof(objSyn->m_application_wide->m_ipAddress_value)); + case Snmp::ApplicationSyntax::COUNTER_VALUE: + return DataBlock((void*)objSyn->m_application_wide->m_counter_value, + sizeof(objSyn->m_application_wide->m_counter_value)); + case Snmp::ApplicationSyntax::TIMETICKS_VALUE: + return DataBlock((void*)objSyn->m_application_wide->m_timeticks_value, + sizeof(objSyn->m_application_wide->m_timeticks_value)); + case Snmp::ApplicationSyntax::ARBITRARY_VALUE: + return DataBlock((void*)objSyn->m_application_wide->m_timeticks_value, + sizeof(objSyn->m_application_wide->m_timeticks_value)); + case Snmp::ApplicationSyntax::BIG_COUNTER_VALUE: + return DataBlock((void*)objSyn->m_application_wide->m_big_counter_value, + sizeof(objSyn->m_application_wide->m_big_counter_value)); + case Snmp::ApplicationSyntax::UNSIGNED_INTEGER_VALUE: + return DataBlock((void*)objSyn->m_application_wide->m_unsigned_integer_value, + sizeof(objSyn->m_application_wide->m_unsigned_integer_value)); + default: + break; + } + break; + default: + break; + } + Debug(&__plugin,DebugInfo,"SnmpAgent::getVal([%p]) - no value",varBind); + return DataBlock(); +} + +// obtain the value for a query made through SNMP +AsnValue SnmpAgent::makeQuery(const String& query, unsigned int& index, AsnMib* mib) +{ + DDebug(&__plugin,DebugAll, "::makeQuery(query='%s', index='%d')",query.c_str(),index); + AsnValue val; + if (query == "version") { + String v = Engine::runParams().getValue("version",""); + val.setValue(v); + val.setType(AsnValue::STRING); + return val; + } + if (query == "snmpEngineID") { + val.setValue(m_engineId.toHexString()); + val.setType(AsnValue::STRING); + return val; + } + if (query == "snmpEngineBoots") { + val.setValue(String(m_engineBoots)); + val.setType(AsnValue::INTEGER); + return val; + } + + if (query == "yateMIBRevision") { + String rev = m_mibTree->findRevision(query); + val.setValue(rev); + val.setType(AsnValue::STRING); + return val; + } + if (!queryIsSupported(query,mib)) + return val; + + // ask the monitor module + Message msg("monitor.query"); + msg.addParam("name",query); + msg.addParam("index",String(index)); + if (Engine::dispatch(msg)) { + String value = msg.getValue("value",""); + if (!value.null()) { + val.setValue(value); + val.setType(STRING); + } + } + + return val; +} + +bool SnmpAgent::queryIsSupported(const String& query, AsnMib* mib) +{ + if (!m_mibTree || s_yateRoot.null()) + return false; + if (!mib) + mib = m_mibTree->find(query); + if (!mib) + return false; + return (mib->toString().startsWith(s_yateRoot,false)); +} + +// generate snmpEngineID from configuration parameters +OctetString SnmpAgent::genEngineId(const int format, String& info) +{ + DDebug(&__plugin,DebugInfo,"::genEngineId(%d,%s)",format,info.c_str()); + OctetString aux; + + // set the first 4 bytes to the PEN number and first bit set to 1 (see RFC 3411) + u_int32_t firstPart = s_pen | 0x80000000; + for (unsigned int i = 0; i < sizeof(u_int32_t); i++) { + u_int8_t byte = (firstPart >> (8 * i)); + DataBlock d; + d.append(&byte,1); + aux.insert(d); + } + int size = 1, base = 10; + // add the format for of the 6 bytes remaining from the engine id + aux.append((void*)&format,1); + ObjList* list = 0; + DataBlock db; + // according to the given format, build the rest of 6 bytes + switch (format) { + case IPv4: + list = info.split('.'); + base = 10; + break; + case IPv6: + list = info.split(':'); + size = 2; + break; + case MAC: + list = info.split(':'); + base = 16; + break; + case TEXT: + aux.append(info); + break; + case OCTETS: + db.unHexify(info,info.length()); + aux.append(db); + break; + case ENTERPRISE: + aux.append(info); + break; + default: + break; + } + if (list) { + for (ObjList* o = list->skipNull(); o; o = o->skipNext()) { + u_int8_t val; + String* str = static_cast(o->get()); + if (size == 2) { + int intVal = str->toInteger(0,16); + DataBlock d,daux; + val = intVal; + intVal = intVal >> 8; + d.append(&val,1); + daux.insert(d); + d.clear(); + val = intVal; + d.append(&val,1); + daux.insert(d); + aux.append(daux); + } + else { + val = str->toInteger(0,base); + aux.append(&val,size); + } + } + TelEngine::destruct(list); + } + return aux; +} + +}; // anonymous namespace + +/* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/modules/server/zapcard.cpp b/modules/server/zapcard.cpp index bfd0a855..4f4fb79b 100644 --- a/modules/server/zapcard.cpp +++ b/modules/server/zapcard.cpp @@ -555,6 +555,7 @@ private: bool m_sendReadOnly; // Print send attempt on readonly interface error int m_notify; // Notify receiver on channel non idle (0: success. 1: not notified. 2: notified) SignallingTimer m_timerRxUnder; // RX underrun notification + bool m_down; // Interface status }; // Signalling span used to create voice circuits @@ -775,6 +776,32 @@ static inline bool getBoolValue(const char* param, const NamedList& config, return params.getBoolValue(param,defVal); } +static void sendModuleUpdate(const String& notif, const String& device, bool& notifStat, int status = 0) +{ + Message* msg = new Message("module.update"); + msg->addParam("module",plugin.name()); + msg->addParam("interface",device); + msg->addParam("notify",notif); + if(notifStat && status == SignallingInterface::LinkUp) { + notifStat = false; + Engine::enqueue(msg); + return; + } + if (!notifStat && status == SignallingInterface::LinkDown) { + notifStat = true; + Engine::enqueue(msg); + return; + } + if (notif == "alarm") { + if (status == ZapDevice::Yellow) + msg->addParam("notify","RAI"); + if (status == ZapDevice::Blue) + msg->addParam("notify","AIS"); + Engine::enqueue(msg); + return; + } + TelEngine::destruct(msg); +} /** * ZapWorkerClient @@ -1363,8 +1390,13 @@ bool ZapDevice::checkAlarms() m_alarmsText = ""; if (m_alarms) { for(int i = 0; s_alarms[i].token; i++) - if (m_alarms & s_alarms[i].value) + if (m_alarms & s_alarms[i].value) { m_alarmsText.append(s_alarms[i].token,","); + if (s_alarms[i].value == ZapDevice::Yellow || s_alarms[i].value == ZapDevice::Blue) { + bool notifStat = false; + sendModuleUpdate("alarm",zapName(),notifStat,s_alarms[i].value); + } + } Debug(m_owner,DebugNote,"%sAlarms changed (%d,'%s') on channel %u [%p]", m_name.safe(),m_alarms,m_alarmsText.safe(),m_channel,m_owner); } @@ -1788,6 +1820,7 @@ bool ZapInterface::init(ZapDevice::Type type, unsigned int code, unsigned int ch s << " priority=" << Thread::priority(m_priority); Debug(this,DebugInfo,"D-channel: %s [%p]",s.c_str(),this); } + m_down = false; return true; } @@ -1941,11 +1974,13 @@ void ZapInterface::checkEvents() Debug(this,DebugNote,"Alarms changed '%s' [%p]", m_device.alarmsText().safe(),this); notify(LinkDown); + sendModuleUpdate("interfaceDown",m_device.zapName(),m_down,LinkDown); } else { m_device.resetAlarms(); DDebug(this,DebugInfo,"No more alarms [%p]",this); notify(LinkUp); + sendModuleUpdate("interfaceUp",m_device.zapName(),m_down,LinkUp); } return; case ZapDevice::HdlcAbort: diff --git a/modules/yiaxchan.cpp b/modules/yiaxchan.cpp index 6049020b..f4135318 100644 --- a/modules/yiaxchan.cpp +++ b/modules/yiaxchan.cpp @@ -182,6 +182,12 @@ public: inline bool hasLine(const String& line) { Lock lock(this); return findLine(line) != 0; } + /** + * Get a copy of the lines list + */ + inline ObjList* lines() + { Lock lock(this); return m_lines.skipNull();} + protected: bool updateLine(YIAXLine* line, Message &msg); bool addLine(Message &msg); @@ -384,6 +390,9 @@ public: bool userAuth(IAXTransaction* tr, bool response, bool& requestAuth, bool& invalidAuth); + bool commandComplete(Message& msg, const String& partLine, const String& partWord); + void msgStatus(Message& msg); + protected: YIAXEngine* m_iaxEngine; u_int32_t m_defaultCodec; @@ -528,6 +537,7 @@ static YIAXLineContainer s_lines; // Lines static Thread::Priority s_priority = Thread::Normal; // Threads priority static YIAXDriver iplugin; // Init the driver +static String s_statusCmd = "status"; /* * Class definitions @@ -1151,6 +1161,7 @@ void YIAXDriver::initialize() installRelay(Halt); installRelay(Route); installRelay(Progress); + installRelay(Status); Engine::install(new YIAXRegDataHandler); // Init IAX engine u_int16_t transListCount = 64; @@ -1261,6 +1272,12 @@ bool YIAXDriver::received(Message& msg, int id) channels().clear(); s_lines.clear(); } + else + if (id == Status) { + String target = msg.getValue("module"); + if (target && target.startsWith(name()) && !target.startsWith(prefix())) + msgStatus(msg); + } return Driver::received(msg,id); } @@ -1343,6 +1360,41 @@ bool YIAXDriver::userAuth(IAXTransaction* tr, bool response, bool& requestAuth, return true; } +bool YIAXDriver::commandComplete(Message& msg, const String& partLine, const String& partWord) +{ + String cmd = s_statusCmd; + cmd << " " << name(); + if (partLine == cmd) + itemComplete(msg.retValue(),"accounts",partWord); + else + return Driver::commandComplete(msg,partLine,partWord); + return false; +} + +void YIAXDriver::msgStatus(Message& msg) +{ + String str = msg.getValue("module"); + while (str.startSkip(name())) { + str.trimBlanks(); + if (str.null()) + break; + if (str.startSkip("accounts")) { + msg.retValue().clear(); + msg.retValue() << "module=" << name(); + msg.retValue() << ",format=Protocol|Status"; + for (ObjList* o = s_lines.lines(); o; o = o->skipNext()) { + YIAXLine* line = static_cast(o->get()); + str.append(line->username(),",") << "=IAX|"; + str << (line-> registered() ? "online" : "offline"); + } + msg.retValue().append(str,";"); + msg.retValue() << "\r\n"; + return; + } + } + Driver::msgStatus(msg); +} + /** * IAXConsumer */ diff --git a/modules/yrtpchan.cpp b/modules/yrtpchan.cpp index 923fb389..5bc8a85a 100644 --- a/modules/yrtpchan.cpp +++ b/modules/yrtpchan.cpp @@ -188,6 +188,9 @@ private: unsigned int m_port; bool m_audio; bool m_valid; + + unsigned int m_noAudio; + unsigned int m_lostAudio; }; class YRTPSession : public RTPSession @@ -366,6 +369,10 @@ public: virtual bool received(Message& msg, int id); virtual void statusParams(String& str); virtual void statusDetail(String& str); + + void addStats(const NamedList& stats); + void genUpdate(Message& msg); + private: bool reflectSetup(Message& msg, const char* id, RTPTransport& rtp, const char* rHost, const char* leg); bool reflectStart(Message& msg, const char* id, RTPTransport& rtp, SocketAddr& rAddr); @@ -374,6 +381,7 @@ private: void reflectAnswer(Message& msg, bool ignore); void reflectHangup(Message& msg); bool m_first; + ObjList m_updates; }; static YRTPPlugin splugin; @@ -387,7 +395,7 @@ static Mutex s_srcMutex(false,"YRTPChan::source"); YRTPWrapper::YRTPWrapper(const char* localip, CallEndpoint* conn, const char* media, RTPSession::Direction direction, Message& msg, bool udptl) : m_rtp(0), m_udptl(0), m_dir(direction), m_conn(conn), m_source(0), m_consumer(0), m_media(media), - m_bufsize(0), m_port(0), m_valid(true) + m_bufsize(0), m_port(0), m_valid(true), m_noAudio(0), m_lostAudio(0) { Debug(&splugin,DebugAll,"YRTPWrapper::YRTPWrapper('%s',%p,'%s',%s,%p,%s) [%p]", localip,conn,media,lookup(direction,dict_yrtp_dir), @@ -825,6 +833,10 @@ void YRTPWrapper::timeout(bool initial) { if (!(initial ? s_warnFirst : s_warnLater)) return; + if (initial) + m_noAudio++; + else + m_lostAudio++; Debug(&splugin,DebugWarn,"%s timeout in%s%s wrapper [%p]", (initial ? "Initial" : "Later"), (m_master ? " channel " : ""), @@ -885,8 +897,15 @@ void YRTPWrapper::terminate(Message& msg) { Debug(&splugin,DebugInfo,"YRTPWrapper::terminate() [%p]",this); String stats; - if (m_rtp) + if (m_rtp) { + NamedList nl(""); + m_rtp->getStats(nl); + nl.setParam("noaudio",String(m_noAudio)); + nl.setParam("lostaudio",String(m_lostAudio)); + splugin.addStats(nl); + splugin.changed(); m_rtp->getStats(stats); + } if (m_udptl) m_udptl->getStats(stats); if (stats) @@ -1461,6 +1480,25 @@ YRTPPlugin::~YRTPPlugin() s_mirrors.clear(); } +void YRTPPlugin::addStats(const NamedList& stats) +{ + DDebug(this,DebugAll,"Add updates"); + s_mutex.lock(); + m_updates.append(new NamedList(stats)); + s_mutex.unlock(); +} + +void YRTPPlugin::genUpdate(Message& msg) +{ + DDebug(this,DebugAll,"::genUpdate() [%p] updates=%d",this,m_updates.count()); + Lock l(s_mutex); + if (m_updates.count() == 0) + return; + NamedList* updateParams = static_cast(m_updates.remove(false)); + msg.copyParams(*updateParams); + TelEngine::destruct(updateParams); +} + void YRTPPlugin::statusParams(String& str) { s_mutex.lock(); diff --git a/modules/ysipchan.cpp b/modules/ysipchan.cpp index 709c5c0f..2781d70e 100644 --- a/modules/ysipchan.cpp +++ b/modules/ysipchan.cpp @@ -199,6 +199,26 @@ public: { return m_port; } inline Socket* socket() const { return m_sock; } + inline void incFailedAuths() + { m_failedAuths++; } + inline unsigned int failedAuths() + { + unsigned int tmp = m_failedAuths; + m_failedAuths = 0; + return tmp; + } + inline unsigned int timedOutTrs() + { + unsigned int tmp = m_timedOutTrs; + m_timedOutTrs = 0; + return tmp; + } + inline unsigned int timedOutByes() + { + unsigned int tmp = m_timedOutByes; + m_timedOutByes = 0; + return tmp; + } private: void addMessage(const char* buf, int len, const SocketAddr& addr, int port); int m_port; @@ -207,6 +227,10 @@ private: SocketAddr m_addr; YateSIPEngine *m_engine; DataBlock m_buffer; + + unsigned int m_failedAuths; + unsigned int m_timedOutTrs; + unsigned int m_timedOutByes; }; // Handle transfer requests @@ -460,6 +484,10 @@ public: YateSIPLine* findLine(const String& line) const; YateSIPLine* findLine(const String& addr, int port, const String& user = String::empty()); bool validLine(const String& line); + bool commandComplete(Message& msg, const String& partLine, const String& partWord); + void msgStatus(Message& msg); +protected: + virtual void genUpdate(Message& msg); private: SDPParser m_parser; YateSIPEndPoint *m_endpoint; @@ -491,6 +519,8 @@ static int s_expires_min = EXPIRES_MIN; static int s_expires_def = EXPIRES_DEF; static int s_expires_max = EXPIRES_MAX; +static String s_statusCmd = "status"; + // Check if an IPv4 address belongs to one of the non-routable blocks static bool isPrivateAddr(const String& host) { @@ -988,15 +1018,24 @@ bool YateSIPEngine::checkUser(const String& username, const String& realm, const return copyAuthParams(params,m); // if the URI included some parameters retry after stripping them off int sc = uri.find(';'); - if (sc < 0) - return false; - buildAuth(username,realm,m.retValue(),nonce,method,uri.substr(0,sc),res); - return (res == response) && copyAuthParams(params,m); + bool ok = false; + if (sc >= 0) { + buildAuth(username,realm,m.retValue(),nonce,method,uri.substr(0,sc),res); + ok = (res == response) && copyAuthParams(params,m); + } + + if (!ok && !response.null()) { + DDebug(&plugin,DebugNote,"Failed authentication for username='%s'",username.c_str()); + m_ep->incFailedAuths(); + plugin.changed(); + } + return ok; } YateSIPEndPoint::YateSIPEndPoint(Thread::Priority prio) : Thread("YSIP EndPoint",prio), - m_sock(0), m_engine(0) + m_sock(0), m_engine(0), + m_failedAuths(0),m_timedOutTrs(0), m_timedOutByes(0) { Debug(&plugin,DebugAll,"YateSIPEndPoint::YateSIPEndPoint(%s) [%p]", Thread::priority(prio),this); @@ -1215,10 +1254,25 @@ void YateSIPEndPoint::run() evCount = 0; // hack: use a loop so we can use break and continue for (; e; m_engine->processEvent(e),e = 0) { - if (!e->getTransaction()) + SIPTransaction* t = e->getTransaction(); + if (!t) continue; plugin.lock(); - GenObject* obj = static_cast(e->getTransaction()->getUserData()); + + if (t->isOutgoing() && t->getResponseCode() == 408) { + if (t->getMethod() == "BYE") { + DDebug(&plugin,DebugInfo,"BYE for transaction %p has timed out",t); + m_timedOutByes++; + plugin.changed(); + } + if (e->getState() == SIPTransaction::Cleared && e->getUserData()) { + DDebug(&plugin,DebugInfo,"Transaction %p has timed out",t); + m_timedOutTrs++; + plugin.changed(); + } + } + + GenObject* obj = static_cast(t->getUserData()); RefPointer conn = YOBJECT(YateSIPConnection,obj); YateSIPLine* line = YOBJECT(YateSIPLine,obj); YateSIPGenerate* gen = YOBJECT(YateSIPGenerate,obj); @@ -4117,6 +4171,13 @@ bool SIPDriver::received(Message& msg, int id) channels().clear(); s_lines.clear(); } + else if (id == Status) { + String target = msg.getValue("module"); + if (target && target.startsWith(name()) && !target.startsWith(prefix())) { + msgStatus(msg); + return true; + } + } return Driver::received(msg,id); } @@ -4206,12 +4267,59 @@ void SIPDriver::initialize() installRelay(Progress); installRelay(Update); installRelay(Route); + installRelay(Status); Engine::install(new UserHandler); if (s_cfg.getBoolValue("general","generate")) Engine::install(new SipHandler); } } +void SIPDriver::genUpdate(Message& msg) +{ + DDebug(this,DebugInfo,"fill module.update message"); + Lock l(this); + if (m_endpoint) { + msg.setParam("failed_auths",String(m_endpoint->failedAuths())); + msg.setParam("transaction_timeouts",String(m_endpoint->timedOutTrs())); + msg.setParam("bye_timeouts",String(m_endpoint->timedOutByes())); + } +} + +bool SIPDriver::commandComplete(Message& msg, const String& partLine, const String& partWord) +{ + String cmd = s_statusCmd; + cmd << " " << name(); + if (partLine == cmd) + itemComplete(msg.retValue(),"accounts",partWord); + else + return Driver::commandComplete(msg,partLine,partWord); + return false; +} + +void SIPDriver::msgStatus(Message& msg) +{ + String str = msg.getValue("module"); + while (str.startSkip(name())) { + str.trimBlanks(); + if (str.null()) + Module::msgStatus(msg); + else if (str.startSkip("accounts")) { + msg.retValue().clear(); + msg.retValue() << "module=" << name(); + msg.retValue() << ",format=Protocol|Status"; + String accounts = ""; + for (ObjList* o = s_lines.skipNull(); o; o = o->skipNext()) { + YateSIPLine* line = static_cast(o->get()); + accounts.append(line->getUserName(),",") << "=SIP|"; + accounts << (line->valid() ? "online" : "offline"); + } + msg.retValue().append(accounts,";"); + msg.retValue() << "\r\n"; + return; + } + } +} + }; // anonymous namespace /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/packing/rpm/yate.spec.in b/packing/rpm/yate.spec.in index d930c6b4..1be7667b 100644 --- a/packing/rpm/yate.spec.in +++ b/packing/rpm/yate.spec.in @@ -86,6 +86,8 @@ for small to large scale projects. %{_bindir}/yate %{_mandir}/*/yate.* %{_initrddir}/yate +%dir %{_datadir}/yate/data +%{_datadir}/yate/data/* %dir %{_libdir}/yate %{_libdir}/yate/cdrbuild.yate %{_libdir}/yate/cdrfile.yate @@ -140,6 +142,8 @@ for small to large scale projects. %{_libdir}/yate/server/users.yate %{_libdir}/yate/server/presence.yate %{_libdir}/yate/server/subscription.yate +%{_libdir}/yate/server/monitoring.yate +%{_libdir}/yate/server/ysnmpagent.yate %{_libdir}/yate/client/osschan.yate %{_libdir}/yate/client/jabberclient.yate %{_libdir}/yate/jabber/jabberserver.yate @@ -182,6 +186,11 @@ for small to large scale projects. %config(noreplace) %{_sysconfdir}/yate/ciscosm.conf %config(noreplace) %{_sysconfdir}/yate/sigtransport.conf %config(noreplace) %{_sysconfdir}/yate/isupmangler.conf +%config(noreplace) %{_sysconfdir}/yate/monitoring.conf +%config(noreplace) %{_sysconfdir}/yate/ysnmpagent.conf +%config(noreplace) %{_sysconfdir}/yate/users.conf +%config(noreplace) %{_sysconfdir}/yate/presence.conf +%config(noreplace) %{_sysconfdir}/yate/subscription.conf %config(noreplace) %{_sysconfdir}/yate/jabberclient.conf %config(noreplace) %{_sysconfdir}/yate/jabberserver.conf %config(noreplace) %{_sysconfdir}/yate/jbfeatures.conf diff --git a/share/Makefile.in b/share/Makefile.in index 11ba8eb8..b87152e8 100644 --- a/share/Makefile.in +++ b/share/Makefile.in @@ -4,7 +4,7 @@ # override DESTDIR at install time to prefix the install directory DESTDIR := -SUBDIRS := help skins scripts sounds +SUBDIRS := data help skins scripts sounds prefix = @prefix@ exec_prefix = @exec_prefix@ diff --git a/share/data/Makefile.in b/share/data/Makefile.in new file mode 100644 index 00000000..e4da3b71 --- /dev/null +++ b/share/data/Makefile.in @@ -0,0 +1,38 @@ +# Makefile +# This file holds the make rules for miscellaneous Yate data files + +# override DESTDIR at install time to prefix the install directory +DESTDIR := + +DATA := snmp_mib.conf \ + NULL-TEAM-MIB.txt YATE-MIB.txt + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datarootdir = @datarootdir@ +datadir = @datadir@ +shrdir = $(datadir)/yate +datdir = $(shrdir)/data + +# include optional local make rules +-include YateLocal.mak + +.PHONY: all +all: + +.PHONY: install +install: + @cd @srcdir@ && mkdir -p "$(DESTDIR)$(datdir)/" && \ + test -z "$(DATA)" || \ + install -m 0644 $(DATA) "$(DESTDIR)$(datdir)/" + +.PHONY: uninstall +uninstall: + @-for i in $(DATA) ; do \ + rm "$(DESTDIR)$(datdir)/$$i" ; \ + done; + @-rmdir "$(DESTDIR)$(datdir)" + @-rmdir "$(DESTDIR)$(datdir)" + +Makefile: @srcdir@/Makefile.in ../../config.status + cd ../.. && ./config.status diff --git a/share/data/NULL-TEAM-MIB.txt b/share/data/NULL-TEAM-MIB.txt new file mode 100644 index 00000000..e85bb22d --- /dev/null +++ b/share/data/NULL-TEAM-MIB.txt @@ -0,0 +1,24 @@ +NULL-TEAM-MIB DEFINITIONS ::= BEGIN + +IMPORTS + enterprises, MODULE-IDENTITY + FROM SNMPv2-SMI; + +null-team MODULE-IDENTITY + LAST-UPDATED "200910201200Z" + ORGANIZATION "S.C. Null Team Impex S.R.L." + CONTACT-INFO + "Diana Cionoiu + phone: +40726088939 + office: +40316201400 + Email: office@null.ro" + + DESCRIPTION + "Null Team's private-enterprise MIB." + REVISION "200910201200Z" + DESCRIPTION + "Initial revision." + + ::= { enterprises 34501 } + +END diff --git a/share/data/YATE-MIB.txt b/share/data/YATE-MIB.txt new file mode 100644 index 00000000..53ba1055 --- /dev/null +++ b/share/data/YATE-MIB.txt @@ -0,0 +1,1773 @@ +YATE-MIB DEFINITIONS ::= BEGIN + +IMPORTS + OBJECT-TYPE, MODULE-IDENTITY, Integer32, Counter32, TimeTicks, + Unsigned32, Gauge32 + FROM SNMPv2-SMI + + DisplayString, TruthValue + FROM SNMPv2-TC + + null-team + FROM NULL-TEAM-MIB; + +yate MODULE-IDENTITY + LAST-UPDATED "201009281300Z" + ORGANIZATION "S.C. Null Team Impex S.R.L." + CONTACT-INFO + "Diana Cionoiu + phone: +40726088939 + office: +40316201400 + Email: office@null.ro" + DESCRIPTION + "The MIB module for Yate." + REVISION "201009281300Z" + DESCRIPTION + "Initial published revision." + ::= { null-team 1 } + +yateMIBRevision OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "YATE MIB Revision." + ::= { yate 1 } + +-- yateVersion + +version OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "String form for the YATE version." + ::= { yate 2 } + +status OBJECT IDENTIFIER ::= { yate 3 } +moduleInfo OBJECT IDENTIFIER ::= { yate 4 } +activeCalls OBJECT IDENTIFIER ::= { yate 5 } +connections OBJECT IDENTIFIER ::= { yate 6 } +statistics OBJECT IDENTIFIER ::= { yate 7 } +alarms OBJECT IDENTIFIER ::= { yate 8 } +commands OBJECT IDENTIFIER ::= { yate 9 } + + + +-- status BEGIN + +engine OBJECT IDENTIFIER ::= { status 1 } + +plugins OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of plugins loaded by the engine." + ::= { engine 1 } + +handlers OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of message handlers installed by the engine." + ::= { engine 2 } + +messages OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Engine number of messages waiting to be handled." + ::= { engine 3 } + +threads OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Engine number of threads." + ::= { engine 4 } + +workers OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Engine number of workers." + ::= { engine 5 } + +mutexes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Engine total number of mutexes." + ::= { engine 6 } + +locks OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Engine number of locked mutexes." + ::= { mutexes 1 } + +semaphores OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Engine total number of semaphores." + ::= { engine 7 } + +waitingSemaphores OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Engine number of waiting semaphores." + ::= { semaphores 1 } + +-- engine END +-- nodeInfo BEGIN + +nodeInfo OBJECT IDENTIFIER ::= { status 2 } + +name OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Name of the node on which YATE runs." + ::= { nodeInfo 1 } + +runAttempt OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times Yate has been restarted by the supervisor." + ::= { nodeInfo 2 } + +state OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The state of the YATE node." + ::= { nodeInfo 3 } + +-- nodeInfo END +-- databaseInfo BEGIN + +databaseInfo OBJECT IDENTIFIER ::= { status 3 } + +successfulConnections OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of succesful connections made to the database." + ::= { databaseInfo 1 } + +failedConnections OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of failed connections to the database." + ::= { databaseInfo 2 } + +-- databaseInfo END +-- moduleInfo BEGIN + +moduleCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of loaded modules." + ::= { moduleInfo 1 } + +moduleTable OBJECT-TYPE + SYNTAX SEQUENCE OF ModuleEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Module information table." + ::= { moduleInfo 2 } + +moduleEntry OBJECT-TYPE + SYNTAX ModuleEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Module information table entry." + ::= { moduleTable 1 } + +ModuleEntry ::= SEQUENCE { + moduleIndex Counter32, + moduleName DisplayString, + moduleType DisplayString, + moduleInfo DisplayString +} + +moduleIndex OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Module table index." + ::= { moduleEntry 1 } + +moduleName OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Module name." + ::= { moduleEntry 2 } + +moduleType OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Module type." + ::= { moduleEntry 3 } + +moduleInfo OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Module additional information." + ::= { moduleEntry 4 } + +-- moduleInfo END +-- activeCalls BEGIN + +activeCallsCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of active calls." + ::= { activeCalls 1 } + +activeCallsTable OBJECT-TYPE + SYNTAX SEQUENCE OF ActiveCallEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table containing information about current calls." + ::= { activeCalls 2 } + +activeCallEntry OBJECT-TYPE + SYNTAX ActiveCallEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table entry containing information about a current call." + ::= { activeCallsTable 1 } + +ActiveCallEntry ::= SEQUENCE { + callEntryIndex Counter32, + callEntryID DisplayString, + callEntryStatus DisplayString, + callEntryCaller DisplayString, + callEntryCalled DisplayString, + callEntryDuration Counter32, + callEntryPeerChan DisplayString +} + +callEntryIndex OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Active call index." + ::= { activeCallEntry 1 } + +callEntryID OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Active call identification." + ::= { activeCallEntry 2 } + +callEntryStatus OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Active call status." + ::= { activeCallEntry 3 } + +callEntryCaller OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Name of the caller of this active call." + ::= { activeCallEntry 4 } + +callEntryCalled OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Name of the called party of this active call." + ::= { activeCallEntry 5 } + +callEntryDuration OBJECT-TYPE + SYNTAX DisplayString + UNITS "seconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Duration of this active call in seconds." + ::= { activeCallEntry 6 } + +callEntryPeerChan OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The peer of this active call." + ::= { activeCallEntry 7 } + +-- activeCalls END +-- connections BEGIN + +trunks OBJECT IDENTIFIER ::= { connections 1 } + +trunksCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of configured PSTN trunks." + ::= { trunks 1 } + +trunkTable OBJECT-TYPE + SYNTAX SEQUENCE OF TrunkEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table containing information about configured PSTN trunks." + ::= { trunks 2 } + +trunkEntry OBJECT-TYPE + SYNTAX TrunkEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table entry containing information about a configured PSTN trunk." + ::= { trunkTable 1 } + +TrunkEntry ::= SEQUENCE { + trunkIndex Counter32, + trunkID DisplayString, + trunkType DisplayString, + trunkCircuitCount Counter32, + trunkCurrentCallsCount Counter32, + trunkDownAlarms Counter32 +} + +trunkIndex OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Index of the PSTN trunk in the table." + ::= { trunkEntry 1 } + +trunkID OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the PSTN trunk." + ::= { trunkEntry 2 } + +trunkType OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "PSTN trunk type." + ::= { trunkEntry 3 } + +trunkCircuitCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of circuits of the PSTN trunk." + ::= { trunkEntry 4 } + +trunkCurrentCallsCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of calls of the PSTN trunk." + ::= { trunkEntry 5 } + +trunkDownAlarms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times an alarm that signals that a trunk is down alarm has been sent." + ::= { trunkEntry 6 } + +-- trunks END +-- linksets BEGIN + +linksets OBJECT IDENTIFIER ::= { connections 2 } + +linksetCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of configured linksets." + ::= { linksets 1 } + +linksetTable OBJECT-TYPE + SYNTAX SEQUENCE OF LinksetEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table containing information about configured linksets." + ::= { linksets 2 } + +linksetEntry OBJECT-TYPE + SYNTAX LinksetEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table entry containing information about a configured linkset." + ::= { linksetTable 1 } + +LinksetEntry ::= SEQUENCE { + linksetIndex Counter32, + linksetID DisplayString, + linksetType DisplayString, + linksetStatus DisplayString, + linksetDownAlarms Counter32 +} + +linksetIndex OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Index of the linkset in the table." + ::= { linksetEntry 1 } + +linksetID OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the linkset." + ::= { linksetEntry 2 } + +linksetType OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the linkset." + ::= { linksetEntry 3 } + +linksetStatus OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The status of the linkset." + ::= { linksetEntry 4 } + +linksetDownAlarms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times an alarm that signals that this linkset is down alarm has been sent." + ::= { linksetEntry 5 } + + +-- linksets END +-- links BEGIN + +links OBJECT IDENTIFIER ::= { connections 3 } + +linkCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of configured links." + ::= { links 1 } + +linksTable OBJECT-TYPE + SYNTAX SEQUENCE OF LinkEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table containing information about configured links." + ::= { links 2 } + +linkEntry OBJECT-TYPE + SYNTAX LinkEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table entry containing information about a configured link." + ::= { linksTable 1 } + +LinkEntry ::= SEQUENCE { + linkIndex Counter32, + linkID DisplayString, + linkType DisplayString, + linkStatus DisplayString, + linkDownAlarms Counter32 +} + +linkIndex OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The index of the link in the table." + ::= { linkEntry 1 } + +linkID OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the link." + ::= { linkEntry 2 } + +linkType OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The type of the link." + ::= { linkEntry 3 } + +linkStatus OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The status of the link." + ::= { linkEntry 4 } + +linkDownAlarms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times an alarm that signals that this link is down alarm has been sent." + ::= { linkEntry 5 } + +-- links END +-- interfaces BEGIN + +interfaces OBJECT IDENTIFIER ::= { connections 4 } + +interfacesCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of configured interfaces." + ::= { interfaces 1 } + +interfacesTable OBJECT-TYPE + SYNTAX SEQUENCE OF InterfaceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table containing information about configured interfaces." + ::= { interfaces 2 } + +interfaceEntry OBJECT-TYPE + SYNTAX InterfaceEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table entry containing information about a interface." + ::= { interfacesTable 1 } + +InterfaceEntry ::= SEQUENCE { + interfaceIndex Counter32, + interfaceID DisplayString, + interfaceStatus DisplayString, + interfaceDownAlarms Counter32 +} + +interfaceIndex OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The index of this interface in the table." + ::= { interfaceEntry 1 } + +interfaceID OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the link." + ::= { interfaceEntry 2 } + +interfaceStatus OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The status of the link." + ::= { interfaceEntry 3} + +interfaceDownAlarms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times an alarm that signals that this interface is down has been sent." + ::= { interfaceEntry 4 } + +-- interfaces END +-- isdnQ921 BEGIN +isdnQ921 OBJECT IDENTIFIER ::= { connections 5 } +-- isdnQ921 END + +-- accounts begin +accounts OBJECT IDENTIFIER ::= { connections 6 } + +accountsCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of accounts." + ::= { accounts 1 } + +accountsTable OBJECT-TYPE + SYNTAX SEQUENCE OF AccountEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table containing information about configured accounts." + ::= { accounts 2 } + +accountEntry OBJECT-TYPE + SYNTAX AccountEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table entry containing information about an account." + ::= { accountsTable 1 } + +AccountEntry ::= SEQUENCE { + accountIndex Counter32, + accountID DisplayString, + accountStatus DisplayString, + accountProtocol DisplayString +} + +accountIndex OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The index of the account in the table." + ::= { accountEntry 1 } + +accountID OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the account." + ::= { accountEntry 2 } + +accountStatus OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The status of the account." + ::= { accountEntry 3 } + +accountProtocol OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The protocol used for this account." + ::= { accountEntry 4 } + +-- accounts end + +-- connections END + +-- statistics BEGIN + +calls OBJECT IDENTIFIER ::= { statistics 1 } + +-- callCounters BEGIN + +callCounters OBJECT IDENTIFIER ::= { calls 1 } + +incomingCalls OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of incoming calls." + ::= { callCounters 1 } + +outgoingCalls OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of outgoing calls." + ::= { callCounters 2 } + +-- callCounters END + +-- serviceQuality BEGIN + +serviceQuality OBJECT IDENTIFIER ::= { calls 2 } + +qosDirectionsCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of monitored for service quality directions." + ::= { serviceQuality 1 } + +qosDirectionsTable OBJECT-TYPE + SYNTAX SEQUENCE OF QOSEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table containing service quality information about configured directions." + ::= { serviceQuality 2 } + +qosEntry OBJECT-TYPE + SYNTAX QOSEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table entry containing service quality information about a direction." + ::= { qosDirectionsTable 1 } + +QOSEntry ::= SEQUENCE { + qosEntryIndex Counter32, + qosEntryDirection DisplayString, + asrData ASRData, + nerData NERData, + callEndCauseCounters EndCauseCounters +} + +qosEntryIndex OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The index for a monitored direction." + ::= { qosEntry 1 } + +qosEntryDirection OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the monitored direction." + ::= { qosEntry 2 } + +asrData OBJECT-TYPE + SYNTAX ASRData + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "ASR information for this direction." + ::= { qosEntry 3 } + +ASRData ::= SEQUENCE { + lowASRThreshold INTEGER (1..100), + highASRThreshold INTEGER (1..100), + currentASR INTEGER (1..100), + overallASR INTEGER (1..100), + currentLowASRAlarmCount Counter32, + currentHighASRAlarmCount Counter32, + overallLowASRAlarmCount Counter32, + overallHighASRAlarmCount Counter32 +} + +lowASRThreshold OBJECT-TYPE + SYNTAX INTEGER (1..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The lower threshold for triggering an ASR alarm." + ::= { asrData 1 } + +highASRThreshold OBJECT-TYPE + SYNTAX INTEGER (1..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The upper threshold for triggering an ASR alarm." + ::= { asrData 2 } + +currentASR OBJECT-TYPE + SYNTAX INTEGER (1..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The ASR value for the configured time interval." + ::= { asrData 3 } + +overallASR OBJECT-TYPE + SYNTAX INTEGER (1..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The ASR value since YATE started." + ::= { asrData 4 } + +currentLowASRAlarmCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times a low ASR alarm has been sent." + ::= { asrData 5 } + +currentHighASRAlarmCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times a high ASR alarm has been sent since Yate started." + ::= { asrData 6 } + +overallLowASRAlarmCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times a low ASR alarm has been sent." + ::= { asrData 7 } + +overallHighASRAlarmCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times a high ASR alarm has been sent since Yate started." + ::= { asrData 8 } + +nerData OBJECT-TYPE + SYNTAX NERData + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "NER information about this direction." + ::= { qosEntry 4 } + +NERData ::= SEQUENCE { + lowNERThreshold INTEGER (1..100), + currentNER INTEGER (1..100), + overallNER INTEGER (1..100), + currentLowNERAlarmCount Counter32, + overallLowNERAlarmCount Counter32 +} + +lowNERThreshold OBJECT-TYPE + SYNTAX INTEGER (1..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The lower threshold for triggering a NER alarm." + ::= { nerData 1 } + +currentNER OBJECT-TYPE + SYNTAX INTEGER (1..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The NER value for the configured time interval." + ::= { nerData 2 } + +overallNER OBJECT-TYPE + SYNTAX INTEGER (1..100) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The NER value since YATE started." + ::= { nerData 3 } + +currentLowNERAlarmCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times a low NER alarm has been sent." + ::= { nerData 4 } + +overallLowNERAlarmCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of times a low NER alarm has been sent since YATE started." + ::= { nerData 5 } + +callEndCauseCounters OBJECT-TYPE + SYNTAX EndCauseCounters + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Counters for call end reasons." + ::= { qosEntry 5 } + +EndCauseCounters ::= SEQUENCE { + currentHangupEndCause Counter32, + overallHangupEndCause Counter32, + currentRejectedEndCause Counter32, + overallRejectedEndCause Counter32, + currentBusyEndCause Counter32, + overallBusyEndCause Counter32, + currentCancelledEndCause Counter32, + overallCancelledEndCause Counter32, + currentNoAnswerEndCause Counter32, + overallNoAnswerEndCause Counter32, + currentNoRouteEndCause Counter32, + overallNoRouteEndCause Counter32, + currentNoConnectionEndCause Counter32, + overallNoConnectionEndCause Counter32, + currentNoAuthEndCause Counter32, + overallNoAuthEndCause Counter32, + currentCongestionEndCause Counter32, + overallCongestionEndCause Counter32 +} + +currentHangupEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended with hangup in the configured time interval." + ::= { callEndCauseCounters 1 } + +overallHangupEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended with hangup since YATE started." + ::= { callEndCauseCounters 2 } + +currentRejectedEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended by being rejected in the configured time interval." + ::= { callEndCauseCounters 3 } + +overallRejectedEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended by being rejected since YATE started." + ::= { callEndCauseCounters 4 } + +currentBusyEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended because of busy in the configured time interval." + ::= { callEndCauseCounters 5 } + +overallBusyEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended because of busy since YATE started." + ::= { callEndCauseCounters 6 } + +currentCancelledEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls cancelled in the configured time interval." + ::= { callEndCauseCounters 7 } + +overallCancelledEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls cancelled since YATE started." + ::= { callEndCauseCounters 8 } + +currentNoAnswerEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended because of no answer in the configured time interval." + ::= { callEndCauseCounters 9 } + +overallNoAnswerEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended because of no answer since YATE started." + ::= { callEndCauseCounters 10 } + +currentNoRouteEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended due to a lack of route in the configured time interval." + ::= { callEndCauseCounters 11 } + +overallNoRouteEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended due to a lack of route since YATE started." + ::= { callEndCauseCounters 12 } + +currentNoConnectionEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended with service unavailable in the configured time interval." + ::= { callEndCauseCounters 13 } + +overallNoConnectionEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended with service unavailable since YATE started." + ::= { callEndCauseCounters 14 } + +currentNoAuthEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended due to a lack of authorization in the configured time interval." + ::= { callEndCauseCounters 15 } + +overallNoAuthEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended due to a lack of authorization since YATE started." + ::= { callEndCauseCounters 16 } + +currentCongestionEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended with congestion in the configured time interval." + ::= { callEndCauseCounters 17 } + +overallCongestionEndCause OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of calls ended due with congestion since YATE started." + ::= { callEndCauseCounters 18 } + +-- serviceQuality END +-- calls END + +-- database BEGIN + +database OBJECT IDENTIFIER ::= { statistics 2 } + +databaseCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of configured database accounts." + ::= { database 1 } + +databaseTable OBJECT-TYPE + SYNTAX SEQUENCE OF DatabaseEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table containing service quality information about configured database accounts." + ::= { database 2 } + +databaseEntry OBJECT-TYPE + SYNTAX DatabaseEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table entry containing information about a database account." + ::= { databaseTable 1 } + +DatabaseEntry ::= SEQUENCE { + databaseIndex Counter32, + databaseAccount DisplayString, + queriesCount Counter32, + failedQueries Counter32, + errorQueries Counter32, + queryExecTime INTEGER, + databaseAlarmCounters DatabaseAlarmCounters, + databaseThresholds DatabaseThresholds +} + +databaseIndex OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The index of a database account." + ::= { databaseEntry 1 } + +databaseAccount OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of a database account." + ::= { databaseEntry 2 } + +queriesCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries requested to be executed in a configured time interval." + ::= { databaseEntry 3 } + +failedQueries OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries that failed to be executed in a configured time interval." + ::= { databaseEntry 4 } + +errorQueries OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of queries that return from execution with an error status in a configured time interval." + ::= { databaseEntry 5 } + +queryExecTime OBJECT-TYPE + SYNTAX INTEGER + UNITS "miliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Report the average time spent executing a database query received in a configured time interval." + ::= { databaseEntry 6 } + +databaseAlarmCounters OBJECT-TYPE + SYNTAX DatabaseAlarmCounters + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Alarm counters for this database account." + ::= { databaseEntry 7 } + +DatabaseAlarmCounters ::= SEQUENCE { + tooManyQueriesAlarms Counter32, + tooManyFailedQueriesAlarms Counter32, + tooManyErrorQueriesAlarms Counter32, + queryExecTooLongAlarms Counter32, + noConnectionAlarms Counter32 +} + +tooManyQueriesAlarms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times an alarm that signals that too many database queries were requested has been sent." + ::= { databaseAlarmCounters 1 } + +tooManyFailedQueriesAlarms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times an alarm that signals that too many database queries failed to be executed has been sent." + ::= { databaseAlarmCounters 2 } + +tooManyErrorQueriesAlarms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times an alarm that signals that too many database queries returned with an error status has been sent." + ::= { databaseAlarmCounters 3 } + +queryExecTooLongAlarms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times an alarm that signals that a query is taking too long to be executed has been sent." + ::= { databaseAlarmCounters 4 } + +noConnectionAlarms OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times an alarm that signals that a connection to the database could not be established has been sent." + ::= { databaseAlarmCounters 5 } + +databaseThresholds OBJECT-TYPE + SYNTAX DatabaseThresholds + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Alarm thresholds for this database account." + ::= { databaseEntry 8 } + +DatabaseAlarmCounters ::= SEQUENCE { + queriesCountThreshold Counter32, + failedQueriesThreshold Counter32, + errorQueriesThreshold Counter32, + queryExecTimeThreshold Counter32 +} + +queriesCountThreshold OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Threshold for triggering a alarm that too many queries were requested to be executed." + ::= { databaseThresholds 1 } + +failedQueriesThreshold OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Threshold for triggering a alarm that too many queries failed to be executed." + ::= { databaseThresholds 2 } + +errorQueriesThreshold OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Threshold for triggering a alarm that too many queries returned with an error." + ::= { databaseThresholds 3 } + +queryExecTimeThreshold OBJECT-TYPE + SYNTAX Counter32 + UNITS "miliseconds" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Threshold for triggering a alarm that queries take too long to be executed." + ::= { databaseThresholds 4 } + +-- database END +-- rtp BEGIN + +rtpData OBJECT IDENTIFIER ::= { statistics 3} + +rtpDirectionsCount OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of RTP directions." + ::= { rtpData 1 } + +rtpDirectionsTable OBJECT-TYPE + SYNTAX SEQUENCE OF RTPEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table containing information about RTP directions." + ::= { rtpData 2 } + +rtpEntry OBJECT-TYPE + SYNTAX RTPEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table entry containing information about an account." + ::= { rtpDirectionsTable 1 } + +RTPEntry ::= SEQUENCE { + rtpEntryIndex Counter32, + rtpDirection DisplayString, + noAudioCounter Counter32, + lostAudioCounter Counter32, + packetsLost Counter32, + syncLost Counter32, + sequenceNumberLost Counter32, + wrongSRC Counter32, + wrongSSRC Counter32 +} + +rtpEntryIndex OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Index of the RTP direction in the table." + ::= { rtpEntry 1 } + +rtpDirection OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name for the RTP direction." + ::= { rtpEntry 2 } + +noAudioCounter OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times lack of audio has been detected on RTP." + ::= { rtpEntry 3 } + +lostAudioCounter OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times a loss of audio has been detected on RTP." + ::= { rtpEntry 4 } + +packetsLost OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of RTP packets lost." + ::= { rtpEntry 5 } + +syncLost OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times synchronization has been lost on RTP." + ::= { rtpEntry 6 } + +sequenceNumberLost OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times the sequence number has been lost on RTP." + ::= { rtpEntry 7 } + +wrongSRC OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of received RTP packets with wrong SRC in packet." + ::= { rtpEntry 8 } + +wrongSSRC OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of received RTP packets with wrong SSRC in packet." + ::= { rtpEntry 9 } + +-- rtp END +-- requests BEGIN + +requests OBJECT IDENTIFIER ::= { statistics 4 } + +authenticationRequests OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of received authentication requests." + ::= { requests 1 } + +registerRequests OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of received register requests." + ::= { requests 2 } + +-- requests END +-- statistics END + +-- alarms BEGIN + +-- databaseAlarms BEGIN + +databaseAlarms OBJECT IDENTIFIER ::= { alarms 1 } + +tooManyQueries OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that signals that the number of queries requested to be executed + in a set time interval surpassed a configured threshold." + ::= { databaseAlarms 1 } + +tooManyFailedQueries OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that signals that the number of queries that could not be executed + in a set time interval surpassed a configured threshold." + ::= { databaseAlarms 2 } + +tooManyErrorQueries OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that signals that the number of queries that returned with an error status + in a set time interval surpassed a configured threshold." + ::= { databaseAlarms 3 } + +queryExecTimeTooLong OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that signals that the average time for executing a query has surpassed + a configured threshold." + ::= { databaseAlarms 4 } + +noConnection OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notify that Yate has failed to establish a connection to this database." + ::= { databaseAlarms 5 } + +-- databaseAlarms END + +-- serviceQualityAlarms BEGIN + +serviceQualityAlarms OBJECT IDENTIFIER ::= { alarms 2 } + +asrAlarms OBJECT IDENTIFIER ::= { serviceQualityAlarms 1 } + +lowASRAlarms OBJECT IDENTIFIER ::= { asrAlarms 1 } + +currentLowASR OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Alarm that signals that the ASR value is bellow a set threshold for a configured time interval." + ::= { lowASRAlarms 1 } + +overallLowASR OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Alarm that signals that the ASR value since Yate started is bellow a set threshold." + ::= { lowASRAlarms 2 } + +highASRAlarms OBJECT IDENTIFIER ::= { asrAlarms 2 } + +currentHighASR OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Alarm that signals that the ASR value for a configured time interval has surpassed a set threshold." + ::= { highASRAlarms 1 } + +overallHighASR OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Alarm that signals that the overall ASR value has surpassed a set threshold." + ::= { highASRAlarms 2 } + +lowNERAlarms OBJECT IDENTIFIER ::= { serviceQualityAlarms 2 } + +currentLowNER OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Alarm that signals that the NER value for a configured time interval is bellow a set threshold." + ::= { lowNERAlarms 1 } + +overallLowNER OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Alarm that signals that the overall NER value is bellow a set threshold." + ::= { lowNERAlarms 2 } + +-- serviceQualityAlarms END + +-- connectionAlarms BEGIN + +connectionAlarms OBJECT IDENTIFIER ::= { alarms 3 } + +trunkDown OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that this trunk is down." + ::= { connectionAlarms 1 } + +trunkUp OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that this trunk is up." + ::= { connectionAlarms 2 } + +linksetDown OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that this linkset component is down." + ::= { connectionAlarms 3 } + +linksetUp OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that this linkset component is up." + ::= { connectionAlarms 4 } + +linkDown OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that this link is down." + ::= { connectionAlarms 5 } + +linkUp OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that this link is up." + ::= { connectionAlarms 6 } + +interfaceDown OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that signals that this interface is down." + ::= { connectionAlarms 7 } + +interfaceUp OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that signals that this interface is up." + ::= { connectionAlarms 8 } + +isdnQ921Down OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that this ISDN Q921 component is down." + ::= { connectionAlarms 9 } + +isdnQ921Up OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that this ISDN Q921 component is up." + ::= { connectionAlarms 10 } + +routeDown OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that this route is down." + ::= { connectionAlarms 11 } + +routeUp OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notification that this route is up." + ::= { connectionAlarms 12 } + +-- connectionAlarms END + +-- sipAlarms BEGIN + +sipAlarms OBJECT IDENTIFIER ::= { alarms 4 } + +transactionsTimedOut OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of SIP transactions that have timed out." + ::= { sipAlarms 1 } + +failedAuths OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of failed SIP authentications." + ::= { sipAlarms 2 } + +byesTimedOut OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of BYE tranctions that timed out." + ::= { sipAlarms 3 } + +gatewayAlarms OBJECT IDENTIFIER ::= { sipAlarms 4 } + +gatewayTimeout OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notify that a monitored SIP gateway timed out." + ::= { gatewayAlarms 1 } + +gatewayUp OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notify that a previously timed out SIP gateway went back online." + ::= { gatewayAlarms 2 } + +-- sipAlarms END +-- mgcpAlarms BEGIN + +mgcpAlarms OBJECT IDENTIFIER ::= { alarms 5 } + +mgcpTransactionsTimedOut OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of MGCP transactions that have timed out." + ::= { mgcpAlarms 1 } + +deleteTransactionsTimedOut OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of DELETE transactions that have timed out." + ::= { mgcpAlarms 2 } + +mgcpGatewayTimedOut OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notify that this MGCP gateway has timed out." + ::= { mgcpAlarms 3 } + +mgcpGatewayUp OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS accessible-for-notify + STATUS current + DESCRIPTION + "Notify that this MGCP gateway is online." + ::= { mgcpAlarms 4 } + +-- mgcpAlarms END + +-- alarms END + + +-- commands BEGIN + +enableTrap OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Activate the trap with the given object identifier." + ::= { commands 1 } + +disableTrap OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Deactivate trap with the given object identifier." + ::= { commands 2 } + +-- yateCommands END + +END diff --git a/share/data/snmp_mib.conf b/share/data/snmp_mib.conf new file mode 100644 index 00000000..fff9ae80 --- /dev/null +++ b/share/data/snmp_mib.conf @@ -0,0 +1,1464 @@ +; generated on Oct 19, 2010 3:18 PM. DO NOT MODIFY! + +[1.3] +name=org + +[1.3.6] +name=dod + +[1.3.6.1] +name=internet + +[1.3.6.1.1] +name=directory + +[1.3.6.1.2] +name=mgmt + +[1.3.6.1.2.1] +name=mib_2 + +[1.3.6.1.2.1.1] +name=system + +[1.3.6.1.2.1.1.1] +name=sysDescr +access=read-only +type=DisplayString + +[1.3.6.1.2.1.1.2] +name=sysObjectID +access=read-only +type=OBJECT_ID + +[1.3.6.1.2.1.1.3] +name=sysUpTime +access=read-only +type=TimeTicks + +[1.3.6.1.2.1.1.4] +name=sysContact +access=read-write +type=DisplayString + +[1.3.6.1.2.1.1.5] +name=sysName +access=read-write +type=DisplayString + +[1.3.6.1.2.1.1.6] +name=sysLocation +access=read-write +type=DisplayString + +[1.3.6.1.2.1.1.7] +name=sysServices +access=read-only +type=INTEGER + +[1.3.6.1.2.1.1.8] +name=sysORLastChange +access=read-only +type=TimeStamp + +[1.3.6.1.2.1.1.9] +name=sysORTable +access=not-accessible + +[1.3.6.1.2.1.1.9.1] +name=sysOREntry +access=not-accessible + +[1.3.6.1.2.1.1.9.1.1] +name=sysORIndex +access=not-accessible + +[1.3.6.1.2.1.1.9.1.2] +name=sysORID +access=read-only +type=OBJECT_ID + +[1.3.6.1.2.1.1.9.1.3] +name=sysORDescr +access=read-only +type=DisplayString + +[1.3.6.1.2.1.1.9.1.4] +name=sysORUpTime +access=read-only +type=TimeStamp + +[1.3.6.1.2.1.10] +name=transmission + +[1.3.6.1.2.1.11] +name=snmp + +[1.3.6.1.2.1.11.1] +name=snmpInPkts +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.2] +name=snmpOutPkts +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.3] +name=snmpInBadVersions +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.4] +name=snmpInBadCommunityNames +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.5] +name=snmpInBadCommunityUses +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.6] +name=snmpInASNParseErrs +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.8] +name=snmpInTooBigs +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.9] +name=snmpInNoSuchNames +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.10] +name=snmpInBadValues +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.11] +name=snmpInReadOnlys +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.12] +name=snmpInGenErrs +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.13] +name=snmpInTotalReqVars +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.14] +name=snmpInTotalSetVars +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.15] +name=snmpInGetRequests +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.16] +name=snmpInGetNexts +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.17] +name=snmpInSetRequests +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.18] +name=snmpInGetResponses +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.19] +name=snmpInTraps +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.20] +name=snmpOutTooBigs +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.21] +name=snmpOutNoSuchNames +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.22] +name=snmpOutBadValues +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.24] +name=snmpOutGenErrs +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.25] +name=snmpOutGetRequests +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.26] +name=snmpOutGetNexts +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.27] +name=snmpOutSetRequests +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.28] +name=snmpOutGetResponses +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.29] +name=snmpOutTraps +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.30] +name=snmpEnableAuthenTraps +access=read-write +type=INTEGER + +[1.3.6.1.2.1.11.31] +name=snmpSilentDrops +access=read-only +type=Counter32 + +[1.3.6.1.2.1.11.32] +name=snmpProxyDrops +access=read-only +type=Counter32 + +[1.3.6.1.3] +name=experimental + +[1.3.6.1.4] +name=private + +[1.3.6.1.4.1] +name=enterprises + +[1.3.6.1.4.1.34501] +name=null_team +revision=200910201200Z + +[1.3.6.1.4.1.34501.1] +name=yate +revision=201009281300Z + +[1.3.6.1.4.1.34501.1.1] +name=yateMIBRevision +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.2] +name=version +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.3] +name=status + +[1.3.6.1.4.1.34501.1.3.1] +name=engine + +[1.3.6.1.4.1.34501.1.3.1.1] +name=plugins +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.1.2] +name=handlers +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.1.3] +name=messages +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.1.4] +name=threads +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.1.5] +name=workers +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.1.6] +name=mutexes +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.1.6.1] +name=locks +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.1.7] +name=semaphores +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.1.7.1] +name=waitingSemaphores +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.2] +name=nodeInfo + +[1.3.6.1.4.1.34501.1.3.2.1] +name=name +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.3.2.2] +name=runAttempt +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.2.3] +name=state +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.3.3] +name=databaseInfo + +[1.3.6.1.4.1.34501.1.3.3.1] +name=successfulConnections +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.3.3.2] +name=failedConnections +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.4] +name=moduleInfo + +[1.3.6.1.4.1.34501.1.4.1] +name=moduleCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.4.2] +name=moduleTable +access=not-accessible + +[1.3.6.1.4.1.34501.1.4.2.1] +name=moduleEntry +access=not-accessible + +[1.3.6.1.4.1.34501.1.4.2.1.1] +name=moduleIndex +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.4.2.1.2] +name=moduleName +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.4.2.1.3] +name=moduleType +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.4.2.1.4] +name=moduleInfo +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.5] +name=activeCalls + +[1.3.6.1.4.1.34501.1.5.1] +name=activeCallsCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.5.2] +name=activeCallsTable +access=not-accessible + +[1.3.6.1.4.1.34501.1.5.2.1] +name=activeCallEntry +access=not-accessible + +[1.3.6.1.4.1.34501.1.5.2.1.1] +name=callEntryIndex +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.5.2.1.2] +name=callEntryID +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.5.2.1.3] +name=callEntryStatus +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.5.2.1.4] +name=callEntryCaller +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.5.2.1.5] +name=callEntryCalled +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.5.2.1.6] +name=callEntryDuration +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.5.2.1.7] +name=callEntryPeerChan +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6] +name=connections + +[1.3.6.1.4.1.34501.1.6.1] +name=trunks + +[1.3.6.1.4.1.34501.1.6.1.1] +name=trunksCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.1.2] +name=trunkTable +access=not-accessible + +[1.3.6.1.4.1.34501.1.6.1.2.1] +name=trunkEntry +access=not-accessible + +[1.3.6.1.4.1.34501.1.6.1.2.1.1] +name=trunkIndex +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.1.2.1.2] +name=trunkID +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.1.2.1.3] +name=trunkType +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.1.2.1.4] +name=trunkCircuitCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.1.2.1.5] +name=trunkCurrentCallsCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.1.2.1.6] +name=trunkDownAlarms +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.2] +name=linksets + +[1.3.6.1.4.1.34501.1.6.2.1] +name=linksetCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.2.2] +name=linksetTable +access=not-accessible + +[1.3.6.1.4.1.34501.1.6.2.2.1] +name=linksetEntry +access=not-accessible + +[1.3.6.1.4.1.34501.1.6.2.2.1.1] +name=linksetIndex +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.2.2.1.2] +name=linksetID +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.2.2.1.3] +name=linksetType +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.2.2.1.4] +name=linksetStatus +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.2.2.1.5] +name=linksetDownAlarms +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.3] +name=links + +[1.3.6.1.4.1.34501.1.6.3.1] +name=linkCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.3.2] +name=linksTable +access=not-accessible + +[1.3.6.1.4.1.34501.1.6.3.2.1] +name=linkEntry +access=not-accessible + +[1.3.6.1.4.1.34501.1.6.3.2.1.1] +name=linkIndex +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.3.2.1.2] +name=linkID +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.3.2.1.3] +name=linkType +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.3.2.1.4] +name=linkStatus +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.3.2.1.5] +name=linkDownAlarms +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.4] +name=interfaces + +[1.3.6.1.4.1.34501.1.6.4.1] +name=interfacesCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.4.2] +name=interfacesTable +access=not-accessible + +[1.3.6.1.4.1.34501.1.6.4.2.1] +name=interfaceEntry +access=not-accessible + +[1.3.6.1.4.1.34501.1.6.4.2.1.1] +name=interfaceIndex +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.4.2.1.2] +name=interfaceID +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.4.2.1.3] +name=interfaceStatus +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.4.2.1.4] +name=interfaceDownAlarms +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.5] +name=isdnQ921 + +[1.3.6.1.4.1.34501.1.6.6] +name=accounts + +[1.3.6.1.4.1.34501.1.6.6.1] +name=accountsCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.6.2] +name=accountsTable +access=not-accessible + +[1.3.6.1.4.1.34501.1.6.6.2.1] +name=accountEntry +access=not-accessible + +[1.3.6.1.4.1.34501.1.6.6.2.1.1] +name=accountIndex +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.6.6.2.1.2] +name=accountID +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.6.2.1.3] +name=accountStatus +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.6.6.2.1.4] +name=accountProtocol +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.7] +name=statistics + +[1.3.6.1.4.1.34501.1.7.1] +name=calls + +[1.3.6.1.4.1.34501.1.7.1.1] +name=callCounters + +[1.3.6.1.4.1.34501.1.7.1.1.1] +name=incomingCalls +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.1.2] +name=outgoingCalls +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2] +name=serviceQuality + +[1.3.6.1.4.1.34501.1.7.1.2.1] +name=qosDirectionsCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2] +name=qosDirectionsTable +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.1.2.2.1] +name=qosEntry +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.1] +name=qosEntryIndex +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.2] +name=qosEntryDirection +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.3] +name=asrData +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.3.1] +name=lowASRThreshold +access=read-only +type=INTEGER + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.3.2] +name=highASRThreshold +access=read-only +type=INTEGER + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.3.3] +name=currentASR +access=read-only +type=INTEGER + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.3.4] +name=overallASR +access=read-only +type=INTEGER + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.3.5] +name=currentLowASRAlarmCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.3.6] +name=currentHighASRAlarmCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.3.7] +name=overallLowASRAlarmCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.3.8] +name=overallHighASRAlarmCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.4] +name=nerData +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.4.1] +name=lowNERThreshold +access=read-only +type=INTEGER + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.4.2] +name=currentNER +access=read-only +type=INTEGER + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.4.3] +name=overallNER +access=read-only +type=INTEGER + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.4.4] +name=currentLowNERAlarmCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.4.5] +name=overallLowNERAlarmCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5] +name=callEndCauseCounters +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.1] +name=currentHangupEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.2] +name=overallHangupEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.3] +name=currentRejectedEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.4] +name=overallRejectedEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.5] +name=currentBusyEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.6] +name=overallBusyEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.7] +name=currentCancelledEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.8] +name=overallCancelledEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.9] +name=currentNoAnswerEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.10] +name=overallNoAnswerEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.11] +name=currentNoRouteEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.12] +name=overallNoRouteEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.13] +name=currentNoConnectionEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.14] +name=overallNoConnectionEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.15] +name=currentNoAuthEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.16] +name=overallNoAuthEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.17] +name=currentCongestionEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.1.2.2.1.5.18] +name=overallCongestionEndCause +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2] +name=database + +[1.3.6.1.4.1.34501.1.7.2.1] +name=databaseCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2] +name=databaseTable +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.2.2.1] +name=databaseEntry +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.2.2.1.1] +name=databaseIndex +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.2] +name=databaseAccount +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.7.2.2.1.3] +name=queriesCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.4] +name=failedQueries +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.5] +name=errorQueries +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.6] +name=queryExecTime +access=read-only +type=INTEGER + +[1.3.6.1.4.1.34501.1.7.2.2.1.7] +name=databaseAlarmCounters +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.2.2.1.7.1] +name=tooManyQueriesAlarms +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.7.2] +name=tooManyFailedQueriesAlarms +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.7.3] +name=tooManyErrorQueriesAlarms +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.7.4] +name=queryExecTooLongAlarms +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.7.5] +name=noConnectionAlarms +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.8] +name=databaseThresholds +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.2.2.1.8.1] +name=queriesCountThreshold +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.8.2] +name=failedQueriesThreshold +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.8.3] +name=errorQueriesThreshold +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.2.2.1.8.4] +name=queryExecTimeThreshold +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.3] +name=rtpData + +[1.3.6.1.4.1.34501.1.7.3.1] +name=rtpDirectionsCount +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.3.2] +name=rtpDirectionsTable +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.3.2.1] +name=rtpEntry +access=not-accessible + +[1.3.6.1.4.1.34501.1.7.3.2.1.1] +name=rtpEntryIndex +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.3.2.1.2] +name=rtpDirection +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.7.3.2.1.3] +name=noAudioCounter +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.3.2.1.4] +name=lostAudioCounter +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.3.2.1.5] +name=packetsLost +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.3.2.1.6] +name=syncLost +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.3.2.1.7] +name=sequenceNumberLost +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.3.2.1.8] +name=wrongSRC +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.3.2.1.9] +name=wrongSSRC +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.4] +name=requests + +[1.3.6.1.4.1.34501.1.7.4.1] +name=authenticationRequests +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.7.4.2] +name=registerRequests +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.8] +name=alarms + +[1.3.6.1.4.1.34501.1.8.1] +name=databaseAlarms + +[1.3.6.1.4.1.34501.1.8.1.1] +name=tooManyQueries +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.1.2] +name=tooManyFailedQueries +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.1.3] +name=tooManyErrorQueries +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.1.4] +name=queryExecTimeTooLong +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.1.5] +name=noConnection +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.2] +name=serviceQualityAlarms + +[1.3.6.1.4.1.34501.1.8.2.1] +name=asrAlarms + +[1.3.6.1.4.1.34501.1.8.2.1.1] +name=lowASRAlarms + +[1.3.6.1.4.1.34501.1.8.2.1.1.1] +name=currentLowASR +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.2.1.1.2] +name=overallLowASR +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.2.1.2] +name=highASRAlarms + +[1.3.6.1.4.1.34501.1.8.2.1.2.1] +name=currentHighASR +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.2.1.2.2] +name=overallHighASR +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.2.2] +name=lowNERAlarms + +[1.3.6.1.4.1.34501.1.8.2.2.1] +name=currentLowNER +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.2.2.2] +name=overallLowNER +access=read-only +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3] +name=connectionAlarms + +[1.3.6.1.4.1.34501.1.8.3.1] +name=trunkDown +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.2] +name=trunkUp +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.3] +name=linksetDown +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.4] +name=linksetUp +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.5] +name=linkDown +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.6] +name=linkUp +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.7] +name=interfaceDown +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.8] +name=interfaceUp +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.9] +name=isdnQ921Down +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.10] +name=isdnQ921Up +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.11] +name=routeDown +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.3.12] +name=routeUp +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.4] +name=sipAlarms + +[1.3.6.1.4.1.34501.1.8.4.1] +name=transactionsTimedOut +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.8.4.2] +name=failedAuths +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.8.4.3] +name=byesTimedOut +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.8.4.4] +name=gatewayAlarms + +[1.3.6.1.4.1.34501.1.8.4.4.1] +name=gatewayTimeout +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.4.4.2] +name=gatewayUp +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.5] +name=mgcpAlarms + +[1.3.6.1.4.1.34501.1.8.5.1] +name=mgcpTransactionsTimedOut +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.8.5.2] +name=deleteTransactionsTimedOut +access=read-only +type=Counter32 + +[1.3.6.1.4.1.34501.1.8.5.3] +name=mgcpGatewayTimedOut +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.8.5.4] +name=mgcpGatewayUp +access=accessible-for-notify +type=DisplayString + +[1.3.6.1.4.1.34501.1.9] +name=commands + +[1.3.6.1.4.1.34501.1.9.1] +name=enableTrap +access=read-write +type=OBJECT_ID + +[1.3.6.1.4.1.34501.1.9.2] +name=disableTrap +access=read-write +type=OBJECT_ID + +[1.3.6.1.5] +name=security + +[1.3.6.1.6] +name=snmpV2 + +[1.3.6.1.6.1] +name=snmpDomains + +[1.3.6.1.6.2] +name=snmpProxys + +[1.3.6.1.6.3] +name=snmpModules + +[1.3.6.1.6.3.1] +name=snmpMIB +revision=200210160000Z + +[1.3.6.1.6.3.1.1] +name=snmpMIBObjects + +[1.3.6.1.6.3.1.1.4] +name=snmpTrap + +[1.3.6.1.6.3.1.1.4.1] +name=snmpTrapOID +access=accessible-for-notify +type=OBJECT_ID + +[1.3.6.1.6.3.1.1.4.3] +name=snmpTrapEnterprise +access=accessible-for-notify +type=OBJECT_ID + +[1.3.6.1.6.3.1.1.5] +name=snmpTraps + +[1.3.6.1.6.3.1.1.6] +name=snmpSet + +[1.3.6.1.6.3.1.1.6.1] +name=snmpSetSerialNo +access=read-write +type=TestAndIncr + +[1.3.6.1.6.3.1.2] +name=snmpMIBConformance + +[1.3.6.1.6.3.1.2.1] +name=snmpMIBCompliances + +[1.3.6.1.6.3.1.2.2] +name=snmpMIBGroups + +[1.3.6.1.6.3.10] +name=snmpFrameworkMIB +revision=200210140000Z + +[1.3.6.1.6.3.10.1] +name=snmpFrameworkAdmin + +[1.3.6.1.6.3.10.2] +name=snmpFrameworkMIBObjects + +[1.3.6.1.6.3.10.2.1] +name=snmpEngine + +[1.3.6.1.6.3.10.2.1.1] +name=snmpEngineID +access=read-only +type=SnmpEngineID + +[1.3.6.1.6.3.10.2.1.2] +name=snmpEngineBoots +access=read-only +type=INTEGER + +[1.3.6.1.6.3.10.2.1.3] +name=snmpEngineTime +access=read-only +type=INTEGER + +[1.3.6.1.6.3.10.2.1.4] +name=snmpEngineMaxMessageSize +access=read-only +type=INTEGER + +[1.3.6.1.6.3.10.3] +name=snmpFrameworkMIBConformance + +[1.3.6.1.6.3.10.3.1] +name=snmpFrameworkMIBCompliances + +[1.3.6.1.6.3.10.3.2] +name=snmpFrameworkMIBGroups + +[1.3.6.1.6.3.15] +name=snmpUsmMIB +revision=200210160000Z + +[1.3.6.1.6.3.15.1] +name=usmMIBObjects + +[1.3.6.1.6.3.15.1.1] +name=usmStats + +[1.3.6.1.6.3.15.1.1.1] +name=usmStatsUnsupportedSecLevels +access=read-only +type=Counter32 + +[1.3.6.1.6.3.15.1.1.2] +name=usmStatsNotInTimeWindows +access=read-only +type=Counter32 + +[1.3.6.1.6.3.15.1.1.3] +name=usmStatsUnknownUserNames +access=read-only +type=Counter32 + +[1.3.6.1.6.3.15.1.1.4] +name=usmStatsUnknownEngineIDs +access=read-only +type=Counter32 + +[1.3.6.1.6.3.15.1.1.5] +name=usmStatsWrongDigests +access=read-only +type=Counter32 + +[1.3.6.1.6.3.15.1.1.6] +name=usmStatsDecryptionErrors +access=read-only +type=Counter32 + +[1.3.6.1.6.3.15.1.2] +name=usmUser + +[1.3.6.1.6.3.15.1.2.1] +name=usmUserSpinLock +access=read-write +type=TestAndIncr + +[1.3.6.1.6.3.15.1.2.2] +name=usmUserTable +access=not-accessible + +[1.3.6.1.6.3.15.1.2.2.1] +name=usmUserEntry +access=not-accessible + +[1.3.6.1.6.3.15.1.2.2.1.1] +name=usmUserEngineID +access=not-accessible + +[1.3.6.1.6.3.15.1.2.2.1.2] +name=usmUserName +access=not-accessible + +[1.3.6.1.6.3.15.1.2.2.1.3] +name=usmUserSecurityName +access=read-only +type=SnmpAdminString + +[1.3.6.1.6.3.15.1.2.2.1.4] +name=usmUserCloneFrom +access=read-create +type=RowPointer + +[1.3.6.1.6.3.15.1.2.2.1.5] +name=usmUserAuthProtocol +access=read-create +type=AutonomousType + +[1.3.6.1.6.3.15.1.2.2.1.6] +name=usmUserAuthKeyChange +access=read-create +type=KeyChange + +[1.3.6.1.6.3.15.1.2.2.1.7] +name=usmUserOwnAuthKeyChange +access=read-create +type=KeyChange + +[1.3.6.1.6.3.15.1.2.2.1.8] +name=usmUserPrivProtocol +access=read-create +type=AutonomousType + +[1.3.6.1.6.3.15.1.2.2.1.9] +name=usmUserPrivKeyChange +access=read-create +type=KeyChange + +[1.3.6.1.6.3.15.1.2.2.1.10] +name=usmUserOwnPrivKeyChange +access=read-create +type=KeyChange + +[1.3.6.1.6.3.15.1.2.2.1.11] +name=usmUserPublic +access=read-create +type=OCTET_STRING + +[1.3.6.1.6.3.15.1.2.2.1.12] +name=usmUserStorageType +access=read-create +type=StorageType + +[1.3.6.1.6.3.15.1.2.2.1.13] +name=usmUserStatus +access=read-create +type=RowStatus + +[1.3.6.1.6.3.15.2] +name=usmMIBConformance + +[1.3.6.1.6.3.15.2.1] +name=usmMIBCompliances + +[1.3.6.1.6.3.15.2.2] +name=usmMIBGroups + diff --git a/share/sounds/Makefile.in b/share/sounds/Makefile.in index 9c10d0b2..a8af288f 100644 --- a/share/sounds/Makefile.in +++ b/share/sounds/Makefile.in @@ -1,5 +1,5 @@ # Makefile -# This file holds the make rules for Yate script files +# This file holds the make rules for Yate sound files # override DESTDIR at install time to prefix the install directory DESTDIR :=