]> git.stg.codes - ssmd.git/commitdiff
Initial adding
authorMaxim Mamontov <faust.madf@gmail.com>
Wed, 23 Nov 2011 17:08:57 +0000 (19:08 +0200)
committerMaxim Mamontov <faust.madf@gmail.com>
Wed, 23 Nov 2011 17:08:57 +0000 (19:08 +0200)
101 files changed:
3rdparty/Makefile [new file with mode: 0644]
3rdparty/snmp++/Makefile [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/IPv6Utility.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/address.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/asn1.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/auth_priv.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/collect.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/config_snmp_pp.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/counter.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/ctr64.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/eventlist.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/eventlistholder.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/gauge.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/idea.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/integer.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/log.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/md5.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/mp_v3.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/msec.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/msgqueue.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/notifyqueue.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/octet.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/oid.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/oid_def.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/pdu.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/reentrant.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/sha.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/smi.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/smival.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/snmp_pp.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/snmperrs.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/snmpmsg.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/target.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/timetick.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/usm_v3.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/uxsnmp.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/v3.h [new file with mode: 0644]
3rdparty/snmp++/include/snmp_pp/vb.h [new file with mode: 0644]
3rdparty/snmp++/src/IPv6Utility.cpp [new file with mode: 0644]
3rdparty/snmp++/src/address.cpp [new file with mode: 0644]
3rdparty/snmp++/src/asn1.cpp [new file with mode: 0644]
3rdparty/snmp++/src/auth_priv.cpp [new file with mode: 0644]
3rdparty/snmp++/src/counter.cpp [new file with mode: 0644]
3rdparty/snmp++/src/ctr64.cpp [new file with mode: 0644]
3rdparty/snmp++/src/eventlist.cpp [new file with mode: 0644]
3rdparty/snmp++/src/eventlistholder.cpp [new file with mode: 0644]
3rdparty/snmp++/src/gauge.cpp [new file with mode: 0644]
3rdparty/snmp++/src/idea.cpp [new file with mode: 0644]
3rdparty/snmp++/src/integer.cpp [new file with mode: 0644]
3rdparty/snmp++/src/log.cpp [new file with mode: 0644]
3rdparty/snmp++/src/md5c.cpp [new file with mode: 0644]
3rdparty/snmp++/src/mp_v3.cpp [new file with mode: 0644]
3rdparty/snmp++/src/msec.cpp [new file with mode: 0644]
3rdparty/snmp++/src/msgqueue.cpp [new file with mode: 0644]
3rdparty/snmp++/src/notifyqueue.cpp [new file with mode: 0644]
3rdparty/snmp++/src/octet.cpp [new file with mode: 0644]
3rdparty/snmp++/src/oid.cpp [new file with mode: 0644]
3rdparty/snmp++/src/pdu.cpp [new file with mode: 0644]
3rdparty/snmp++/src/reentrant.cpp [new file with mode: 0644]
3rdparty/snmp++/src/sha.cpp [new file with mode: 0644]
3rdparty/snmp++/src/snmpmsg.cpp [new file with mode: 0644]
3rdparty/snmp++/src/target.cpp [new file with mode: 0644]
3rdparty/snmp++/src/timetick.cpp [new file with mode: 0644]
3rdparty/snmp++/src/usm_v3.cpp [new file with mode: 0644]
3rdparty/snmp++/src/uxsnmp.cpp [new file with mode: 0644]
3rdparty/snmp++/src/v3.cpp [new file with mode: 0644]
3rdparty/snmp++/src/vb.cpp [new file with mode: 0644]
Makefile [new file with mode: 0644]
gssmd.conf [new file with mode: 0644]
include/.switch.h.swp [new file with mode: 0644]
include/.syncer.h.swp [new file with mode: 0644]
include/acl.h [new file with mode: 0644]
include/datatypes.h [new file with mode: 0644]
include/logger.h [new file with mode: 0644]
include/oids.h [new file with mode: 0644]
include/pidfile.h [new file with mode: 0644]
include/settings.h [new file with mode: 0644]
include/settings.inl.h [new file with mode: 0644]
include/snmptable.h [new file with mode: 0644]
include/snmptable.inl.h [new file with mode: 0644]
include/subscriber.h [new file with mode: 0644]
include/switch.h [new file with mode: 0644]
include/syncer.h [new file with mode: 0644]
include/version.h.in [new file with mode: 0644]
src/.main.cpp.swp [new file with mode: 0644]
src/.switch.cpp.swp [new file with mode: 0644]
src/.syncer.cpp.swp [new file with mode: 0644]
src/acl.cpp [new file with mode: 0644]
src/dataparser.cpp [new file with mode: 0644]
src/logger.cpp [new file with mode: 0644]
src/main.cpp [new file with mode: 0644]
src/pidfile.cpp [new file with mode: 0644]
src/settings.cpp [new file with mode: 0644]
src/settingsfileparser.cpp [new file with mode: 0644]
src/snmptable.cpp [new file with mode: 0644]
src/subscriber.cpp [new file with mode: 0644]
src/switch.cpp [new file with mode: 0644]
src/syncer.cpp [new file with mode: 0644]
tests/Makefile [new file with mode: 0644]
tests/test_data_parser.cpp [new file with mode: 0644]
tests/test_switch.cpp [new file with mode: 0644]

diff --git a/3rdparty/Makefile b/3rdparty/Makefile
new file mode 100644 (file)
index 0000000..6474668
--- /dev/null
@@ -0,0 +1,8 @@
+SHELL = /bin/sh
+
+.PHONY: all clean
+
+all:
+       $(MAKE) $(MAKECMDGOALS) -C snmp++
+
+clean: all
diff --git a/3rdparty/snmp++/Makefile b/3rdparty/snmp++/Makefile
new file mode 100644 (file)
index 0000000..2a67cd9
--- /dev/null
@@ -0,0 +1,57 @@
+SHELL = /bin/sh
+DEFS += -D_USE_OPENSSL
+INCS += -Iinclude
+CXXFLAGS += -W -Wall -Wextra $(DEFS) $(INCS)
+PROG = libsnmp++.a
+
+SOURCES = src/address.cpp \
+         src/counter.cpp \
+                 src/eventlistholder.cpp \
+                 src/integer.cpp \
+         src/msec.cpp \
+         src/octet.cpp \
+                 src/reentrant.cpp \
+                 src/target.cpp \
+         src/uxsnmp.cpp \
+         src/asn1.cpp \
+         src/ctr64.cpp \
+         src/gauge.cpp \
+         src/IPv6Utility.cpp \
+                 src/md5c.cpp \
+         src/msgqueue.cpp \
+         src/oid.cpp \
+         src/sha.cpp \
+         src/timetick.cpp \
+         src/v3.cpp \
+         src/auth_priv.cpp \
+                 src/eventlist.cpp \
+                 src/idea.cpp \
+         src/log.cpp \
+         src/mp_v3.cpp \
+                 src/notifyqueue.cpp \
+                 src/pdu.cpp \
+         src/snmpmsg.cpp \
+         src/usm_v3.cpp \
+         src/vb.cpp
+
+.PHONY: all clear
+
+all: $(PROG) 
+
+$(PROG): $(subst .cpp,.o,$(SOURCES))
+       $(AR) rc $@ $^
+       ranlib $@
+
+clean:
+       rm -f src/*.o src/*.d $(PROG)
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+-include $(subst .cpp,.d,$(SOURCES))
+endif
+endif
+
+%.d: %.cpp
+       @$(CXX) -MM $(CXXFLAGS) $< > $@.$$$$; \
+       sed 's,\($*\).o[ :]*,src\/\1.o $@ : ,g' < $@.$$$$ > $@; \
+       rm -f $@.$$$$
diff --git a/3rdparty/snmp++/include/snmp_pp/IPv6Utility.h b/3rdparty/snmp++/include/snmp_pp/IPv6Utility.h
new file mode 100644 (file)
index 0000000..20df968
--- /dev/null
@@ -0,0 +1,77 @@
+/*_############################################################################
+  _## 
+  _##  IPv6Utility.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*
+ * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*===================================================================
+
+  SNMP++ IPV6Utility.h
+
+  DESCRIPTION:
+  This module contains the Utility functions for IPV6 support functions 
+  required for WIN32 environment
+
+  Adapted and integrated into snmp++ by Ragavan Tetchinamourty
+
+=====================================================================*/
+// $Id: $
+
+#ifndef _IPV6UTILITY_H
+#define _IPV6UTILITY_H
+
+#include "snmp_pp/config_snmp_pp.h"
+
+//FIXME #if defined(_MSC_VER) && defined(SNMP_PP_IPv6)
+#if defined(WIN32) && defined(SNMP_PP_IPv6)
+
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define ENOSPC 28
+
+
+const char * inet_ntop(int af, const void *src, char *dst, size_t size);
+
+int inet_pton(int af, const char *src, void *dst);
+
+#endif // defined(WIN32) && defined(SNMP_PP_IPv6)
+
+#endif // IPV6UTILITY_H
+
diff --git a/3rdparty/snmp++/include/snmp_pp/address.h b/3rdparty/snmp++/include/snmp_pp/address.h
new file mode 100644 (file)
index 0000000..7e6866f
--- /dev/null
@@ -0,0 +1,1165 @@
+/*_############################################################################
+  _## 
+  _##  address.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++ A D D R E S S . H
+
+  ADDRESS CLASS DEFINITION
+
+  DESIGN + AUTHOR:   Peter E Mellquist
+
+  DESCRIPTION:
+  Address class definition. Encapsulates various network
+  addresses into easy to use, safe and portable classes.
+
+=====================================================================*/
+// $Id: address.h 307 2007-09-14 20:01:45Z katz $
+
+#ifndef _ADDRESS
+#define _ADDRESS
+
+
+//----[ includes ]-----------------------------------------------------
+#include <string.h>
+
+#if defined (CPU) && CPU == PPC603
+#undef HASH1
+#undef HASH2
+#else
+#include <memory.h>
+#endif
+
+#include "snmp_pp/config_snmp_pp.h" // for _IPX_ADDRESS and _MAC_ADDRESS
+#include "snmp_pp/smival.h"
+#include "snmp_pp/collect.h"
+#include "snmp_pp/reentrant.h"
+
+// include sockets header files
+// for Windows16 and Windows32 include Winsock
+// otherwise assume UNIX
+#if defined (CPU) && CPU == PPC603
+#include <inetLib.h>
+#include <hostLib.h>
+#endif
+
+#ifdef __unix
+#if !defined(_AIX) && !defined(__QNX_NEUTRINO)
+#include <unistd.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#if defined _AIX
+#include <strings.h> // This is needed for FD_SET, bzero
+#endif
+
+#if !defined __CYGWIN32__ && !defined __hpux && !defined linux && !defined _AIX
+extern int h_errno;  // defined in WinSock header, but not for UX?!
+#endif
+#endif // __unix
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//----[ macros ]-------------------------------------------------------
+#define ADDRBUF 50     // worst case of address lens
+#define OUTBUFF 80     // worst case of output lens
+
+#define IPLEN      4
+#define UDPIPLEN   6
+#define IP6LEN_NO_SCOPE   16
+#define IP6LEN_WITH_SCOPE 20
+#define UDPIP6LEN_NO_SCOPE   18
+#define UDPIP6LEN_WITH_SCOPE 22
+#define IS_IP6LEN(n) ((n==16) || (n==20))
+#define IS_UDPIP6LEN(n) ((n==18) || (n==22))
+#define IPXLEN     10
+#define IPXSOCKLEN 12
+#define MACLEN     6
+#define MAX_FRIENDLY_NAME 80
+#define HASH0 19
+#define HASH1 13
+#define HASH2 7
+
+//---[ forward declarations ]-----------------------------------------
+class GenAddress;
+
+//----[ Address class ]-----------------------------------------------
+
+/**
+ * Base class of all Address classes.
+ */
+class DLLOPT Address : public SnmpSyntax
+{
+  friend class GenAddress;
+
+ public:
+  //----[ enumerated types for address types ]---------------------------
+  /**
+   * Type returned by Address::get_type().
+   */
+  enum addr_type
+  {
+    type_ip,      ///< IpAddress (IPv4 or IPv6)
+    type_ipx,     ///< IpxAddress
+    type_udp,     ///< UdpAddress (IPv4 or IPv6)
+    type_ipxsock, ///< IpxSockAddress
+    type_mac,     ///< MacAddress
+    type_invalid  ///< Used by GenAddress::get_type() if address is not valid
+  };
+
+  /**
+   * Type returned by IpAddress::get_ip_version() and
+   * UdpAddress::get_ip_version().
+   */
+  enum version_type
+  {
+    version_ipv4, ///< IPv4
+    version_ipv6  ///< IPv6
+  };
+
+  /**
+   * Default constructor, clears the buffer and sets valid flag to false.
+   */
+  Address();
+
+  /**
+   * Allow destruction of derived classes.
+   */
+  virtual ~Address() {};
+
+  /// overloaded equivlence operator, are two addresses equal?
+  DLLOPT friend int operator==(const Address &lhs,const Address &rhs);
+
+  /// overloaded not equivlence operator, are two addresses not equal?
+  DLLOPT friend int operator!=(const Address &lhs, const Address &rhs)
+    { return !(lhs == rhs); };
+
+  /// overloaded > operator, is a1 > a2
+  DLLOPT friend int operator>(const Address &lhs,const Address &rhs);
+
+  /// overloaded >= operator, is a1 >= a2
+  DLLOPT friend int operator>=(const Address &lhs,const Address &rhs)
+    { if ((lhs > rhs) || (lhs == rhs)) return true;  return false; };
+
+  /// overloaded < operator, is a1 < a2
+  DLLOPT friend int operator<(const Address &lhs,const Address &rhs);
+
+  /// overloaded <= operator, is a1 <= a2
+  DLLOPT friend int operator<=(const Address &lhs, const Address &rhs)
+    { if ((lhs < rhs) || (lhs == rhs)) return true; return false; };
+
+  /// equivlence operator overloaded, are an address and a string equal?
+  DLLOPT friend int operator==(const Address &lhs,const char *rhs);
+
+  /// overloaded not equivlence operator, are an address and string not equal?
+  DLLOPT friend int operator!=(const Address &lhs,const char *rhs)
+    { return !(lhs == rhs); };
+
+  /// overloaded < , is an address greater than a string?
+  DLLOPT friend int operator>(const Address &lhs,const char *rhs);
+
+  /// overloaded >=, is an address greater than or equal to a string?
+  DLLOPT friend int operator>=(const Address &lhs,const char *rhs);
+
+  /// overloaded < , is an address less than a string?
+  DLLOPT friend int operator<(const Address &lhs,const char *rhs);
+
+  /// overloaded <=, is an address less than or equal to a string?
+  DLLOPT friend int operator<=(const Address &lhs,const char *rhs);
+
+  /**
+   * Overloaded operator for streaming output.
+   *
+   * @return String containing the numerical address
+   */
+  virtual operator const char *() const = 0;
+
+  /**
+   * Return if the object contains a valid address.
+   *
+   * @return true if the object is valid
+   */
+  virtual bool valid() const { return valid_flag; };
+
+  /**
+   * Return the space needed for serialization.
+   */
+  virtual int get_asn1_length() const = 0;
+
+  /**
+   * Access as an array (read and write).
+   * @note Only pass in values between 0 and get_length().
+   *
+   * @param position - pos to return
+   * @return reference to the byte at the given position
+   */
+  unsigned char& operator[](const int position)
+    { addr_changed = true; valid_flag = true;
+      return (position < ADDRBUF) ? address_buffer[position]
+                                  : address_buffer[0]; };
+
+  /**
+   * Access as an array (read only).
+   * @note Only pass in values between 0 and get_length().
+   *
+   * @param position - pos to return
+   * @return the byte at the given position
+   */
+  unsigned char operator[](const int position) const
+    { return (position < ADDRBUF) ? address_buffer[ position] : 0; }
+
+
+  /**
+   * Get the length of the binary address (accessible through operator[]).
+   */
+  virtual int get_length() const = 0;
+
+  /**
+   * Get the type of the address.
+   * @see Address::addr_type
+   */
+  virtual addr_type get_type() const = 0;
+
+  /**
+   * Overloaded assignment operator.
+   */
+  virtual SnmpSyntax& operator=(const SnmpSyntax &val) = 0;
+
+  // return a hash key
+  virtual unsigned int hashFunction() const { return 0;};
+
+ protected:
+  SNMP_PP_MUTABLE bool addr_changed;
+  bool valid_flag;
+  unsigned char address_buffer[ADDRBUF]; // internal representation
+
+  // parse the address string
+  // redefined for each specific address subclass
+  virtual bool parse_address(const char * inaddr) = 0;
+
+  // format the output
+  // redefined for each specific address subclass
+  virtual void format_output() const = 0;
+
+  /**
+   * Trim of whitespaces at the start and the end of the string.
+   *
+   * @param ptr - string to trim
+   */
+  void trim_white_space(char * ptr);
+
+  /**
+   * Is this a GenAddress object.
+   */
+  virtual bool is_gen_address() const { return false; };
+
+  /**
+   * Reset the object.
+   */
+  void clear();
+
+#if !defined HAVE_GETHOSTBYNAME_R || !defined HAVE_GETHOSTBYADDR_R || !defined HAVE_REENTRANT_GETHOSTBYNAME || !defined HAVE_REENTRANT_GETHOSTBYADDR
+#ifdef _THREADS
+  static SnmpSynchronized syscall_mutex;
+#endif
+#endif
+
+};
+
+
+//-----------------------------------------------------------------------
+//---------[ IP Address Class ]------------------------------------------
+//-----------------------------------------------------------------------
+class DLLOPT IpAddress : public Address
+{
+ public:
+  /**
+   * Construct an empty invalid IP address.
+   */
+  IpAddress();
+
+  /**
+   * Construct an IP address from a string.
+   *
+   * The following formats can be used:
+   * - hostname with or without domain ("www.agentpp.com", "printsrv")
+   * - Numerical IPv4 address ("192.168.17.1")
+   * - Numerical IPv6 address ("abcd:1234::a:b:1", "::abcd:1")
+   * - Numerical IPv6 address with scope ("abcd:1234::a:b:1%3", "::abcd:1%1")
+   *
+   * @param inaddr - Hostname or IP address
+   */
+  IpAddress(const char *inaddr);
+
+  /**
+   * Construct an IP address from another IP address.
+   *
+   * @param ipaddr - address to copy
+   */
+  IpAddress(const IpAddress &ipaddr);
+
+  /**
+   * Construct an IP address from a GenAddress.
+   *
+   * @param genaddr - address to copy
+   */
+  IpAddress(const GenAddress &genaddr);
+
+  /**
+   * Destructor (ensure that SnmpSyntax::~SnmpSyntax() is overridden).
+   */
+  ~IpAddress() {};
+
+  /**
+   * Map other SnmpSyntax objects to IpAddress.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  /**
+   * Overloaded assignment operator for other IP addresses.
+   */
+  IpAddress& operator=(const IpAddress &ipaddress);
+
+  /**
+   * Overloaded assignment operator for strings.
+   */
+  IpAddress& operator=(const char *inaddr);
+
+  /**
+   * Clone this object.
+   *
+   * @return Pointer to the newly created object (allocated through new).
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *) new IpAddress(*this); };
+
+  /**
+   * Return the friendly name. Does a reverse DNS lookup for the IP address.
+   *
+   * @param status - The errno value for the lookup
+   *
+   * @return the friendly name or a zero length string (no null pointer)
+   */
+  char *friendly_name(int &status);
+
+  /**
+   * Get a printable ASCII value of the address.
+   *
+   * @return String containing the numerical address
+   */
+  virtual const char *get_printable() const
+    { if (addr_changed) format_output(); return output_buffer; };
+
+  /**
+   * Overloaded operator for streaming output.
+   *
+   * @return String containing the numerical address
+   */
+  virtual operator const char *() const
+    { if (addr_changed) format_output(); return output_buffer; };
+
+  /**
+   * Logically AND the address with the param.
+   *
+   * @param ipaddr - address to use as mask
+   */
+  void mask(const IpAddress &ipaddr);
+
+
+  /**
+   * Get the count of matching bits from the left.
+   *
+   * @param match_ip - address to match with
+   */
+  int get_match_bits(const IpAddress match_ip) const;
+
+  /**
+   * Get the length of the binary address (accessible through operator[]).
+   */
+  virtual int get_length() const
+    { return (ip_version == version_ipv4) ? IPLEN : 
+            (have_ipv6_scope ? IP6LEN_WITH_SCOPE : IP6LEN_NO_SCOPE); };
+
+  /**
+   * Return the type of the address.
+   * @see Address::addr_type
+   * @return Always Address:type_ip
+   */
+  virtual addr_type get_type() const { return type_ip; };
+
+  /**
+   * Return the syntax.
+   *
+   * @return This method always returns sNMP_SYNTAX_IPADDR.
+   */
+  virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_IPADDR; };
+
+  /**
+   * Return the space needed for serialization.
+   */
+  virtual int get_asn1_length() const
+    { return get_length() + 2; };
+
+  /**
+   * Return the IP version of the address.
+   *
+   * @return one of Address::version_type
+   */
+  virtual version_type get_ip_version() const { return ip_version; };
+
+  /**
+   * Map a IPv4 address to a IPv6 address.
+   *
+   * @return - TRUE if no error occured.
+   */
+  virtual int map_to_ipv6();
+
+  /**
+   * Get the IPv6 scope
+   */
+  virtual unsigned int get_scope() const;
+
+  /**
+   * Set the IPv6 scope
+   */
+  virtual bool set_scope(const unsigned int scope);
+
+  /**
+   * Reset the object.
+   */
+  void clear();
+
+  bool has_ipv6_scope() const
+      { return (ip_version == version_ipv6) && have_ipv6_scope; };
+
+ protected:
+  SNMP_PP_MUTABLE char output_buffer[OUTBUFF];           // output buffer
+
+  // friendly name storage
+  char iv_friendly_name[MAX_FRIENDLY_NAME];
+  int  iv_friendly_name_status;
+
+  // redefined parse address
+  // specific to IP addresses
+  virtual bool parse_address(const char *inaddr);
+
+  // redefined format output
+  // specific to IP addresses
+  virtual void format_output() const;
+
+  // parse a dotted string
+  int parse_dotted_ipstring(const char *inaddr);
+
+  // parse a coloned string
+  int parse_coloned_ipstring(const char *inaddr);
+
+  // using the currently defined address, do a DNS
+  // and try to fill up the name
+  int addr_to_friendly();
+
+  // support both ipv4 and ipv6 addresses
+  version_type ip_version;
+
+  bool have_ipv6_scope;
+};
+
+//------------------------------------------------------------------------
+//---------[ UDP Address Class ]------------------------------------------
+//------------------------------------------------------------------------
+class DLLOPT UdpAddress : public IpAddress
+{
+ public:
+  /**
+   * Construct an empty invalid UDP address.
+   */
+  UdpAddress();
+
+  /**
+   * Construct an UDP address from a string.
+   *
+   * The following formats can be used additional to those recognized by
+   * IpAdress:
+   * - Port added to IPv4 address with '/' or ':'
+   *   ("192.168.17.1:161", "192.168.17.1/161", "printsrv/161")
+   * - Port added to IPv6 address with '/' or using '[...]:'
+   *   ("::1/162", "[::1]/162", "[::1]:162")
+   *
+   * @param inaddr - Hostname or IP address
+   */
+  UdpAddress(const char *inaddr);
+
+  /**
+   * Construct an UDP address from another UDP address.
+   *
+   * @param udpaddr - address to copy
+   */
+  UdpAddress(const UdpAddress &udpaddr);
+
+  /**
+   * Construct an UDP address from a GenAddress.
+   *
+   * @param genaddr - address to copy
+   */
+  UdpAddress(const GenAddress &genaddr);
+
+  /**
+   * Construct an UDP address from a IP address.
+   * The port will be set to 0.
+   *
+   * @param ipaddr - address to copy
+   */
+  UdpAddress(const IpAddress &ipaddr);
+
+  /**
+   * Destructor (ensure that SnmpSyntax::~SnmpSyntax() is overridden).
+   */
+  ~UdpAddress() {};
+
+  /**
+   * Map other SnmpSyntax objects to UdpAddress.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  /**
+   * Overloaded assignment operator for UdpAddress.
+   */
+  UdpAddress& operator=(const UdpAddress &udpaddr);
+
+  /**
+   * Overloaded assignment operator for IpAddress.
+   */
+  UdpAddress& operator=(const IpAddress &ipaddr);
+
+  /**
+   * Overloaded assignment operator for strings.
+   */
+  UdpAddress& operator=(const char *inaddr);
+
+  /**
+   * Return the syntax.
+   *
+   * @return This method always returns sNMP_SYNTAX_OCTETS.
+   */
+  SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OCTETS; };
+
+  /**
+   * Return the space needed for serialization.
+   */
+  virtual int get_asn1_length() const
+    { return get_length() + 2; };
+
+  /**
+   * Clone this object.
+   *
+   * @return Pointer to the newly created object (allocated through new).
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *) new UdpAddress(*this); };
+
+  /**
+   * Get a printable ASCII value of the address.
+   *
+   * @return String containing the numerical address
+   */
+  virtual const char *get_printable() const
+    { if (addr_changed) format_output(); return output_buffer; };
+
+  /**
+   * Overloaded operator for streaming output.
+   *
+   * @return String containing the numerical address
+   */
+  virtual operator const char *() const
+    { if (addr_changed) format_output(); return output_buffer; };
+
+  /**
+   * Set the port number.
+   *
+   * @note If the object is not valid(), the port may not be set.
+   */
+  void set_port(const unsigned short p);
+
+  /**
+   * Get the port number.
+   *
+   * @return The port number, or 0 is the object is not valid.
+   */
+  unsigned short get_port() const;
+
+  /**
+   * Get the length of the binary address (accessible through operator[]).
+   */
+  virtual int get_length() const
+    { return (ip_version == version_ipv4) ? UDPIPLEN : 
+             (have_ipv6_scope ? UDPIP6LEN_WITH_SCOPE : UDPIP6LEN_NO_SCOPE);};
+
+  /**
+   * Return the type of the address.
+   * @see Address::addr_type
+   * @return Always Address:type_udp
+   */
+  virtual addr_type get_type() const { return type_udp; };
+
+  /**
+   * Map a IPv4 UDP address to a IPv6 UDP address.
+   *
+   * @return - TRUE if no error occured.
+   */
+  virtual int map_to_ipv6();
+
+  /**
+   * Reset the object.
+   */
+  void clear()
+    { Address::clear(); memset(output_buffer, 0, sizeof(output_buffer)); };
+
+  /**
+   * Set the IPv6 scope
+   */
+  virtual bool set_scope(const unsigned int scope);
+
+ protected:
+  SNMP_PP_MUTABLE char output_buffer[OUTBUFF];           // output buffer
+  char sep;                              // separator
+
+  // redefined parse address
+  // specific to IP addresses
+  virtual bool parse_address(const char *inaddr);
+
+  // redefined format output
+  // specific to IP addresses
+  virtual void format_output() const;
+};
+
+#ifdef _MAC_ADDRESS
+//-------------------------------------------------------------------------
+//---------[ 802.3 MAC Address Class ]-------------------------------------
+//-------------------------------------------------------------------------
+class DLLOPT MacAddress : public Address {
+
+public:
+  // constructor, no arguments
+  MacAddress();
+
+  // constructor with a string argument
+  MacAddress(const char  *inaddr);
+
+  // constructor with another MAC object
+  MacAddress(const MacAddress  &macaddr);
+
+  // construct a MacAddress with a GenAddress
+  MacAddress(const GenAddress &genaddr);
+
+  // destructor
+  ~MacAddress() {};
+
+  /**
+   * Return the syntax.
+   *
+   * @return This method always returns sNMP_SYNTAX_OCTETS.
+   */
+  SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OCTETS; };
+
+  /**
+   * Return the space needed for serialization.
+   */
+  virtual int get_asn1_length() const { return MACLEN + 2; };
+
+  /**
+   * Map other SnmpSyntax objects to MacAddress.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  // assignment to another IpAddress object overloaded
+  MacAddress& operator=(const MacAddress &macaddress);
+
+  /**
+   * Clone this object.
+   *
+   * @return Pointer to the newly created object (allocated through new).
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *) new MacAddress(*this); };
+
+  /**
+   * Get a printable ASCII value of the address.
+   *
+   * @return String containing the numerical address
+   */
+  virtual const char *get_printable() const
+    { if (addr_changed) format_output(); return output_buffer; };
+
+  /**
+   * Overloaded operator for streaming output.
+   *
+   * @return String containing the numerical address
+   */
+  virtual operator const char *() const
+    { if (addr_changed) format_output(); return output_buffer; };
+
+  /**
+   * Get the length of the binary address (accessible through operator[]).
+   */
+  virtual int get_length() const { return MACLEN; };
+
+  /**
+   * Return the type of the address.
+   * @see Address::addr_type
+   * @return Always Address:type_mac
+   */
+  virtual addr_type get_type() const { return type_mac; };
+
+  // return a hash key
+  unsigned int hashFunction() const;
+
+  /**
+   * Reset the object.
+   */
+  void clear()
+    { Address::clear(); memset(output_buffer, 0, sizeof(output_buffer)); };
+
+ protected:
+  SNMP_PP_MUTABLE char output_buffer[OUTBUFF];           // output buffer
+
+  // redefined parse address for macs
+  virtual bool parse_address(const char *inaddr);
+
+  // redefined format output for MACs
+  virtual void format_output() const;
+};
+#endif // _MAC_ADDRESS
+
+#ifdef _IPX_ADDRESS
+//------------------------------------------------------------------------
+//---------[ IPX Address Class ]------------------------------------------
+//------------------------------------------------------------------------
+class DLLOPT IpxAddress : public Address {
+
+public:
+  // constructor no args
+  IpxAddress();
+
+  // constructor with a string arg
+  IpxAddress(const char  *inaddr);
+
+  // constructor with another ipx object
+  IpxAddress(const IpxAddress  &ipxaddr);
+
+  // construct with a GenAddress
+  IpxAddress(const GenAddress &genaddr);
+
+  // destructor
+  ~IpxAddress() {};
+
+  /**
+   * Return the syntax.
+   *
+   * @return This method always returns sNMP_SYNTAX_OCTETS.
+   */
+  virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OCTETS; };
+
+  /**
+   * Return the space needed for serialization.
+   */
+  virtual int get_asn1_length() const  { return IPXLEN + 2; };
+
+  /**
+   * Map other SnmpSyntax objects to IpxAddress.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  // assignment to another IpAddress object overloaded
+  IpxAddress& operator=(const IpxAddress &ipxaddress);
+
+#ifdef _MAC_ADDRESS
+  // get the host id portion of an ipx address
+  int get_hostid(MacAddress& mac) const;
+#endif
+
+  /**
+   * Clone this object.
+   *
+   * @return Pointer to the newly created object (allocated through new).
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *) new IpxAddress(*this); };
+
+  /**
+   * Get a printable ASCII value of the address.
+   *
+   * @return String containing the numerical address
+   */
+  virtual const char *get_printable() const
+    { if (addr_changed) format_output(); return output_buffer; };
+
+  /**
+   * Overloaded operator for streaming output.
+   *
+   * @return String containing the numerical address
+   */
+  virtual operator const char *() const
+    { if (addr_changed) format_output(); return output_buffer; };
+
+  /**
+   * Get the length of the binary address (accessible through operator[]).
+   */
+  virtual int get_length() const { return IPXLEN; };
+
+  /**
+   * Return the type of the address.
+   * @see Address::addr_type
+   * @return Always Address:type_ipx
+   */
+  virtual addr_type get_type() const { return type_ipx; };
+
+  /**
+   * Reset the object.
+   */
+  void clear()
+    { Address::clear(); memset(output_buffer, 0, sizeof(output_buffer)); };
+
+ protected:
+  // ipx format separator
+  char separator;
+  SNMP_PP_MUTABLE char output_buffer[OUTBUFF];           // output buffer
+
+  // redefined parse address for ipx strings
+  virtual bool parse_address(const char  *inaddr);
+
+  // redefined format output for ipx strings
+  // uses same separator as when constructed
+  virtual void format_output() const;
+
+};
+
+
+
+//------------------------------------------------------------------------
+//---------[ IpxSock Address Class ]--------------------------------------
+//------------------------------------------------------------------------
+class DLLOPT IpxSockAddress : public IpxAddress {
+
+public:
+  // constructor, no args
+  IpxSockAddress();
+
+  // constructor with a dotted string
+  IpxSockAddress(const char *inaddr);
+
+  // construct an Udp address with another Udp address
+  IpxSockAddress(const IpxSockAddress &ipxaddr);
+
+  //constructor with a GenAddress
+  IpxSockAddress(const GenAddress &genaddr);
+
+  //constructor with a IpxAddress
+  // default socket # is 0
+  IpxSockAddress(const IpxAddress &ipxaddr);
+
+  // destructor
+  ~IpxSockAddress() {};
+
+  // syntax type
+  //virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OCTETS; };
+
+  /**
+   * Return the space needed for serialization.
+   */
+  virtual int get_asn1_length() const { return IPXSOCKLEN + 2; };
+
+  /**
+   * Map other SnmpSyntax objects to IpxSockAddress.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  // assignment to another IpAddress object overloaded
+  IpxSockAddress& operator=(const IpxSockAddress &ipxaddr);
+
+  /**
+   * Clone this object.
+   *
+   * @return Pointer to the newly created object (allocated through new).
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *)new IpxSockAddress(*this); };
+
+  // set the socket number
+  void set_socket(const unsigned short s);
+
+  // get the socket number
+  unsigned short get_socket() const;
+
+  /**
+   * Get a printable ASCII value of the address.
+   *
+   * @return String containing the numerical address
+   */
+  virtual const char *get_printable() const
+    { if (addr_changed) format_output(); return output_buffer; };
+
+  /**
+   * Overloaded operator for streaming output.
+   *
+   * @return String containing the numerical address
+   */
+  virtual operator const char *() const
+    { if (addr_changed) format_output(); return output_buffer; };
+
+  /**
+   * Get the length of the binary address (accessible through operator[]).
+   */
+  virtual int get_length() const { return IPXSOCKLEN; };
+
+  /**
+   * Return the type of the address.
+   * @see Address::addr_type
+   * @return Always Address:type_ipxsock
+   */
+  virtual addr_type get_type() const { return type_ipxsock; };
+
+  /**
+   * Reset the object.
+   */
+  void clear()
+    { Address::clear(); memset(output_buffer, 0, sizeof(output_buffer)); };
+
+ protected:
+  SNMP_PP_MUTABLE char output_buffer[OUTBUFF];           // output buffer
+
+  // redefined parse address for ipx strings
+  virtual bool parse_address(const char  *inaddr);
+
+  // redefined format output
+  // specific to IP addresses
+  virtual void format_output() const;
+};
+#endif // _IPX_ADDRESS
+
+
+
+
+//-------------------------------------------------------------------------
+//--------[ Generic Address ]----------------------------------------------
+//-------------------------------------------------------------------------
+class DLLOPT GenAddress : public Address
+{
+ public:
+  /**
+   * Construct an empty invalid generic address object.
+   */
+  GenAddress();
+
+  /**
+   * Construct a generic address from a string.
+   *
+   * To optimize the speed of the parsing method, use_type can be used
+   * to indicate that the address string is of the specified type.
+   *
+   * @param addr     - address string
+   * @param use_type - if this value is set, the input string is only
+   *                   parsed for the given type 
+   */
+  GenAddress(const char *addr,
+            const Address::addr_type use_type = Address::type_invalid);
+
+  /**
+   * Construct a generic address from an Address object.
+   *
+   * @param addr - Any address object
+   */
+  GenAddress(const Address &addr);
+
+  /**
+   * Construct a generic address from another generic address object.
+   *
+   * @param addr - Generic address object to copy
+   */
+  GenAddress(const GenAddress &addr);
+
+  /**
+   * Destructor, free memory.
+   */
+  ~GenAddress() { if (address) delete address; };
+
+  /**
+   * Return the syntax.
+   *
+   * @return This method returns sNMP_SYNTAX_IPADDR, sNMP_SYNTAX_OCTETS
+   *         or sNMP_SYNTAX_NULL if the generic address does not have
+   *         an address object.
+   */
+  SmiUINT32 get_syntax() const
+    { return address ? address->get_syntax() : sNMP_SYNTAX_NULL; };
+
+  /**
+   * Return the space needed for serialization.
+   */
+  virtual int get_asn1_length() const
+    { return address ? address->get_asn1_length() : 2; };
+
+  /**
+   * Clone this object.
+   *
+   * @return Pointer to the newly created object (allocated through new).
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *)new GenAddress(*this); };
+
+  /**
+   * Overloaded assignment operator for a GenAddress.
+   */
+  GenAddress& operator=(const GenAddress &addr);
+
+  /**
+   * Overloaded assignment operator for a Address.
+   */
+  GenAddress& operator=(const Address &addr);
+
+  /**
+   * Map other SnmpSyntax objects to GenAddress.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  /**
+   * Get a printable ASCII value of the address.
+   *
+   * @return String containing the numerical address
+   */
+  virtual const char *get_printable() const
+    { return (address) ? address->get_printable() : output_buffer; };
+
+  /**
+   * Overloaded operator for streaming output.
+   *
+   * @return String containing the numerical address
+   */
+  virtual operator const char *() const
+    { return address ? (const char *)*address : output_buffer; };
+
+  /**
+   * Get the length of the binary address (accessible through operator[]).
+   */
+  virtual int get_length() const
+    { return (address) ? address->get_length() : 0; };
+
+  /**
+   * Reset the object.
+   */
+  void clear() { if (address) address->clear(); };
+
+  /**
+   * Return the type of the address.
+   * @see Address::addr_type
+   * @return Type of the contained address object or Address::type_invalid
+   *         if it is not valid().
+   */
+  virtual addr_type get_type() const
+    { return (valid()) ? address->get_type() : type_invalid; };
+
+  /**
+   * Access the protected address.
+   * The caller must make sure that this GenAddress object ist valid()
+   * and is of the right type (get_type()).
+   */
+  const IpAddress  &cast_ipaddress()  const { return (IpAddress& )*address; };
+
+  /**
+   * Access the protected address.
+   * The caller must make sure that this GenAddress object ist valid()
+   * and is of the right type (get_type()).
+   */
+  const UdpAddress &cast_udpaddress() const { return (UdpAddress&)*address; };
+
+#ifdef _MAC_ADDRESS
+  /**
+   * Access the protected address.
+   * The caller must make sure that this GenAddress object ist valid()
+   * and is of the right type (get_type()).
+   */
+  const MacAddress &cast_macaddress() const { return (MacAddress&)*address; };
+#endif
+
+#ifdef _IPX_ADDRESS
+  /**
+   * Access the protected address.
+   * The caller must make sure that this GenAddress object ist valid()
+   * and is of the right type (get_type()).
+   */
+  const IpxAddress &cast_ipxaddress() const { return (IpxAddress&)*address; };
+
+  /**
+   * Access the protected address.
+   * The caller must make sure that this GenAddress object ist valid()
+   * and is of the right type (get_type()).
+   */
+  const IpxSockAddress &cast_ipxsockaddress() const
+    { return (IpxSockAddress&)*address; };
+#endif
+
+protected:
+  // pointer to a concrete address
+  Address *address;
+  char output_buffer[1];           // output buffer
+
+  // redefined parse address for generic address
+  virtual bool parse_address(const char *addr)
+    { return parse_address(addr, Address::type_invalid); };
+
+  virtual bool parse_address(const char *addr,
+                            const Address::addr_type use_type);
+
+  // format output for a generic address
+  virtual void format_output() const {};
+
+  /**
+   * Is this a GenAddress object.
+   */
+  virtual bool is_gen_address() const { return true; };
+};
+
+// create AddressCollection type
+typedef SnmpCollection <GenAddress> AddressCollection;
+typedef SnmpCollection <UdpAddress> UdpAddressCollection;
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif  //_ADDRESS
diff --git a/3rdparty/snmp++/include/snmp_pp/asn1.h b/3rdparty/snmp++/include/snmp_pp/asn1.h
new file mode 100644 (file)
index 0000000..84ab242
--- /dev/null
@@ -0,0 +1,444 @@
+/*_############################################################################
+  _## 
+  _##  asn1.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+// $Id: asn1.h 1554 2009-06-28 19:50:17Z katz $
+
+#ifndef _ASN1
+#define _ASN1
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/target.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifndef EIGHTBIT_SUBIDS
+typedef unsigned long oid;
+#define MAX_SUBID   0xFFFFFFFF
+#else
+typedef unsigned char oid;
+#define MAX_SUBID   0xFF
+#endif
+
+#define MAX_OID_LEN      128 /* max subid's in an oid */
+
+// asn.1 values
+#define ASN_BOOLEAN      (0x01)
+#ifndef ASN_INTEGER
+#define ASN_INTEGER      (0x02)
+#endif
+#define ASN_BIT_STR      (0x03)
+#define ASN_OCTET_STR    (0x04)
+#ifndef ASN_NULL
+#define ASN_NULL         (0x05)
+#endif
+#define ASN_OBJECT_ID    (0x06)
+#ifndef ASN_SEQUENCE
+#define ASN_SEQUENCE     (0x10)
+#endif
+#define ASN_SET          (0x11)
+#ifndef ASN_UNIVERSAL
+#define ASN_UNIVERSAL    (0x00)
+#endif
+#ifndef ASN_APPLICATION
+#define ASN_APPLICATION  (0x40)
+#endif
+#ifndef ASN_CONTEXT
+#define ASN_CONTEXT      (0x80)
+#endif
+#ifndef ASN_PRIVATE
+#define ASN_PRIVATE      (0xC0)
+#endif
+#ifndef ASN_PRIMITIVE
+#define ASN_PRIMITIVE    (0x00)
+#endif
+#ifndef ASN_CONSTRUCTOR
+#define ASN_CONSTRUCTOR  (0x20)
+#endif
+#define ASN_LONG_LEN     (0x80)
+#define ASN_EXTENSION_ID (0x1F)
+#define ASN_BIT8         (0x80)
+
+#define IS_CONSTRUCTOR(byte)  ((byte) & ASN_CONSTRUCTOR)
+#define IS_EXTENSION_ID(byte) (((byte) & ASN_EXTENSION_ID) == ASN_EXTENSION_ID)
+
+#define ASN_UNI_PRIM (ASN_UNIVERSAL | ASN_PRIMITIVE)
+#define ASN_SEQ_CON  (ASN_SEQUENCE | ASN_CONSTRUCTOR)
+
+#define ASN_MAX_NAME_LEN   128
+#define SNMP_VERSION_1      0
+#define SNMP_VERSION_2C     1
+#define SNMP_VERSION_2STERN 2
+#define SNMP_VERSION_3      3
+
+// defined types (from the SMI, RFC 1065)
+#define SMI_IPADDRESS       (ASN_APPLICATION | 0)
+#define SMI_COUNTER         (ASN_APPLICATION | 1)
+#define SMI_GAUGE           (ASN_APPLICATION | 2)
+#define SMI_TIMETICKS       (ASN_APPLICATION | 3)
+#define SMI_OPAQUE          (ASN_APPLICATION | 4)
+#define SMI_NSAP            (ASN_APPLICATION | 5)
+#define SMI_COUNTER64       (ASN_APPLICATION | 6)
+#define SMI_UINTEGER        (ASN_APPLICATION | 7)
+
+#define GET_REQ_MSG         (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x0)
+#define GETNEXT_REQ_MSG     (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x1)
+#define GET_RSP_MSG         (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x2)
+#define SET_REQ_MSG         (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x3)
+#define TRP_REQ_MSG         (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x4)
+
+#define GETBULK_REQ_MSG     (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x5)
+#define INFORM_REQ_MSG      (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x6)
+#define TRP2_REQ_MSG        (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x7)
+#define REPORT_MSG          (ASN_CONTEXT | ASN_CONSTRUCTOR | 0x8)
+
+#define SNMP_NOSUCHOBJECT   (ASN_CONTEXT | ASN_PRIMITIVE | 0x0)
+#define SNMP_NOSUCHINSTANCE (ASN_CONTEXT | ASN_PRIMITIVE | 0x1)
+#define SNMP_ENDOFMIBVIEW   (ASN_CONTEXT | ASN_PRIMITIVE | 0x2)
+
+
+#ifdef _DEBUG
+#define ASNERROR(string)    debugprintf(3, "ASN parse error (%s)\n", string )
+#else
+#define ASNERROR(string)
+#endif
+
+
+typedef struct sockaddr_in  ipaddr;
+
+// pdu
+struct snmp_pdu {
+    int        command;      // pdu type
+    unsigned long  reqid;    // Request id
+#ifdef _SNMPv3
+    unsigned long  msgid;
+    unsigned long  maxsize_scopedpdu;
+#endif
+    unsigned long  errstat;  // Error status
+    unsigned long  errindex; // Error index
+
+    // Trap information
+    oid        *enterprise;   // System OID
+    int        enterprise_length;
+    ipaddr  agent_addr;       // address of object generating trap
+    int        trap_type;     // trap type
+    int        specific_type; // specific type
+    unsigned long  time;      // Uptime
+
+    // vb list
+    struct variable_list *variables;
+};
+
+// vb list
+struct variable_list {
+    struct variable_list *next_variable;    // NULL for last variable
+    oid        *name;                       // Object identifier of variable
+    int        name_length;                 // number of subid's in name
+    unsigned char   type;                   // ASN type of variable
+    union {                                 // value of variable
+    long    *integer;
+    unsigned char     *string;
+    oid    *objid;
+    unsigned char   *bitstring;
+    struct counter64 *counter64;
+    } val;
+    int        val_len;
+};
+
+struct counter64 {
+    unsigned long high;
+    unsigned long low;
+};
+
+
+// prototypes for encoding routines
+DLLOPT unsigned char *asn_parse_int(unsigned char *data, int *datalength,
+                                    unsigned char *type,
+                                    long *intp);
+
+
+inline unsigned char *asn_parse_int(unsigned char *data, int *datalength,
+                                    unsigned char *type,
+                                    unsigned long *intp)
+{ return asn_parse_int(data, datalength, type, (long*)intp); }
+
+
+DLLOPT unsigned char *asn_parse_unsigned_int(unsigned char *data,        
+                                             int *datalength,
+                                             unsigned char *type,
+                                             unsigned long *intp);
+inline unsigned char *asn_parse_unsigned_int(unsigned char *data,        
+                                             int *datalength,
+                                             unsigned char *type,
+                                             long *intp)
+{ return asn_parse_unsigned_int(data, datalength, type, (unsigned long*)intp); }
+
+DLLOPT unsigned char *asn_build_int(unsigned char *data, int *datalength,
+                                    const unsigned char type,
+                                    const long *intp);
+
+inline unsigned char *asn_build_int(unsigned char *data, int *datalength,
+                                    const unsigned char type,
+                                    const unsigned long *intp)
+{ return asn_build_int(data, datalength, type, (const long*)intp); }
+
+DLLOPT unsigned char *asn_build_unsigned_int(unsigned char *data,
+                                             int *datalength,
+                                             unsigned char type,
+                                             unsigned long *intp);
+
+DLLOPT unsigned char *asn_parse_string(unsigned char *data, int *datalength,
+                                       unsigned char *type,
+                                       unsigned char *string,
+                                       int *strlength);
+
+DLLOPT unsigned char *asn_build_string(unsigned char *data, int *datalength,
+                                       const unsigned char type,
+                                       const unsigned char *string,
+                                       const int strlength);
+
+DLLOPT unsigned char *asn_parse_header(unsigned char *data, int *datalength,
+                                       unsigned char *type);
+
+DLLOPT unsigned char *asn_build_header(unsigned char *data, int *datalength,
+                                       unsigned char type, int length);
+
+DLLOPT unsigned char *asn_build_sequence(unsigned char *data,
+                                         int *datalength,
+                                         unsigned char type,
+                                         int length);
+
+DLLOPT unsigned char *asn_parse_length(unsigned char *data,
+                                       unsigned long *length);
+
+DLLOPT unsigned char *asn_build_length(unsigned char *data, int *datalength,
+                                       int length);
+
+DLLOPT unsigned char *asn_parse_objid(unsigned char *data, int *datalength,
+                                      unsigned char *type,
+                                      oid *objid, int *objidlength);
+
+DLLOPT unsigned char *asn_build_objid(unsigned char *data, int *datalength,
+                                      unsigned char type,
+                                      oid *objid, int objidlength);
+
+DLLOPT unsigned char *asn_parse_null(unsigned char *data, int *datalength,
+                                     unsigned char *type);
+
+DLLOPT unsigned char *asn_build_null(unsigned char *data,int *datalength,
+                                     unsigned char type);
+
+DLLOPT unsigned char *asn_parse_bitstring(unsigned char *data, int *datalength,
+                                          unsigned char *type,
+                                          unsigned char *string,
+                                          int *strlength);
+
+DLLOPT unsigned char *asn_build_bitstring(unsigned char *data, int *datalength,
+                                          unsigned char type,
+                                          unsigned char *string,
+                                          int strlength);
+
+DLLOPT unsigned char *asn_parse_unsigned_int64(unsigned char *data,
+                                               int *datalength,
+                                               unsigned char *type,
+                                               struct counter64 *cp);
+
+DLLOPT unsigned char *asn_build_unsigned_int64(unsigned char *data,
+                                               int *datalength,
+                                               unsigned char type,
+                                               struct counter64 *cp);
+
+DLLOPT struct snmp_pdu *snmp_pdu_create(int command);
+
+DLLOPT void snmp_free_pdu(struct snmp_pdu *pdu);
+
+DLLOPT int snmp_build(struct snmp_pdu *pdu,
+                      unsigned char *packet,
+                      int *out_length,
+                      const long version,
+                      const unsigned char* community, const int community_len);
+
+DLLOPT void snmp_add_var(struct snmp_pdu *pdu,
+                         oid *name, int name_length,
+                         SmiVALUE *smival);
+
+DLLOPT int snmp_parse(struct snmp_pdu *pdu,
+                      unsigned char *data, int data_length,
+                      unsigned char *community_name, int &community_len,
+                      snmp_version &version);
+
+DLLOPT unsigned char *build_vb(struct snmp_pdu *pdu,
+                              unsigned char *buf, int *buf_len);
+
+DLLOPT unsigned char *build_data_pdu(struct snmp_pdu *pdu,
+                                    unsigned char *buf, int *buf_len,
+                                    unsigned char *vb_buf, int vb_buf_len);
+
+DLLOPT unsigned char *snmp_build_var_op(unsigned char *data,
+                                        oid * var_name, int *var_name_len,
+                                        unsigned char var_val_type,
+                                        int var_val_len,
+                                        unsigned char *var_val,
+                                        int *listlength);
+
+DLLOPT unsigned char *snmp_parse_var_op(unsigned char *data,
+                                        oid *var_name, int *var_name_len,
+                                        unsigned char  *var_val_type,
+                                        int *var_val_len,
+                                        unsigned char  **var_val,        
+                                        int *listlength);
+
+DLLOPT int snmp_parse_data_pdu(struct snmp_pdu *pdu,
+                               unsigned char *&data, int &length);
+                               
+DLLOPT int snmp_parse_vb(struct snmp_pdu *pdu,
+                         unsigned char *&data, int &data_len);
+
+DLLOPT void clear_pdu(struct snmp_pdu *pdu, bool clear_all = false);
+
+/**
+ * Encode the given values for the HeaderData into the buffer.
+ *                                                                  <pre>
+ *  HeaderData ::= SEQUENCE {
+ *    msgID      INTEGER (0..2147483647),
+ *    msgMaxSize INTEGER (484..2147483647),
+ *    msgFlags   OCTET STRING (SIZE(1)),
+ *    msgSecurityModel INTEGER (0..2147483647)
+ *  }
+ *                                                                 </pre>
+ * @param outBuf         - The buffer
+ * @param maxLength      - IN: length of the buffer
+ *                         OUT: free bytes left in the buffer
+ * @param msgID          - The message ID
+ * @param maxMessageSize - The maximum size of a SNMPv3 message
+ * @param msgFlags       - The message Flags
+ * @param securityModel  - The security model
+ *
+ * @return - Pointer to the first free byte in the buffer or
+ *           NULL if an error occured
+ */
+DLLOPT unsigned char *asn1_build_header_data(unsigned char *outBuf,
+                                            int *maxLength,
+                                            long msgID,
+                                            long maxMessageSize,
+                                            unsigned char msgFlags,
+                                            long securityModel);
+
+/**
+ * Parse the filled HeaderData of a SNMPv3 message and return
+ * the encoded values.
+ *                                                                  <pre>
+ *      HeaderData ::= SEQUENCE {
+ *          msgID      INTEGER (0..2147483647),
+ *          msgMaxSize INTEGER (484..2147483647),
+ *          msgFlags   OCTET STRING (SIZE(1)),
+ *          msgSecurityModel INTEGER (0..2147483647)
+ *      }
+ *                                                                 </pre>
+ *
+ * @param buf                - The buffer to parse
+ * @param buf_len            - IN: The length of the buffer
+ *                             OUT: The number of bytes after this object
+ *                                  int the buffer
+ * @param msg_id             - OUT: The message id
+ * @param msg_max_size       - OUT: THe maximum message size of the sender
+ * @param msg_flags          - OUT: The message flags
+ * @param msg_security_model - OUT: The security model used to build this
+ *                                message
+ *
+ * @return -  Returns a pointer to the first byte past the end of
+ *            the object HeaderData (i.e. the start of the next object).
+ *            Returns NULL on any error.
+ */
+DLLOPT unsigned char *asn1_parse_header_data(unsigned char *buf, int *buf_len,
+                                            long *msg_id, long *msg_max_size,
+                                            unsigned char *msg_flags,
+                                            long *msg_security_model);
+
+/**
+ * Parse the ScopedPDU and return the encoded values.
+ *                                                                  <pre>
+ *      ScopedPDU ::= SEQUENCE {
+ *          contextEngineID  OCTET STRING,
+ *          contextName      OCTET STRING,
+ *          data             ANY -- e.g., PDUs as defined in RFC 1905
+ *      }
+ *                                                                 </pre>
+ *
+ * @param scoped_pdu            - The buffer to parse
+ * @param scoped_pdu_len        - IN: The length of the buffer
+ *                                OUT: The number of bytes after this object
+ *                                     int the buffer
+ * @param context_engine_id     - OUT: The parsed contextEngineID
+ * @param context_engine_id_len - OUT: The length of the contextEngineID
+ * @param context_name          - OUT: The parsed contextName
+ * @param context_name_len      - OUT: The length of the contextName
+ *
+ * @return - Pointer to the data object of the scopedPDU or
+ *           NULL on any error.
+ */
+DLLOPT unsigned char *asn1_parse_scoped_pdu(
+         unsigned char *scoped_pdu, int *scoped_pdu_len,
+         unsigned char *context_engine_id, int *context_engine_id_len,
+         unsigned char *context_name, int *context_name_len );
+
+/**
+ * Encode the given values for the scopedPDU into the buffer.
+ *                                                                  <pre>
+ *    ScopedPDU ::= SEQUENCE {
+ *           contextEngineID OCTET STRING
+ *           contextName     OCTET STRING
+ *           data            ANY  -- PDU
+ *       }
+ *                                                                 </pre>
+ * param outBuf            - The buffer
+ * param max_len           - IN: length of the buffer
+ *                           OUT: free bytes left in the buffer
+ * param contextEngineID   - The contextEngineID
+ * param contextEngineIDLength - The length of the contextEngineID
+ * param contextName       - The contextName
+ * param contextNameLength - The length of the contextName
+ * param data              - The already encoded data
+ * param dataLength        - The length of the data
+ *
+ * @return - Pointer to the first free byte in the buffer or
+ *           NULL if an error occured
+ */
+DLLOPT unsigned char *asn1_build_scoped_pdu(
+               unsigned char *outBuf, int *max_len,
+               unsigned char *contextEngineID, long contextEngineIDLength,
+               unsigned char *contextName, long contextNameLength,
+               unsigned char *data, long dataLength);
+
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif  // _ASN1
diff --git a/3rdparty/snmp++/include/snmp_pp/auth_priv.h b/3rdparty/snmp++/include/snmp_pp/auth_priv.h
new file mode 100644 (file)
index 0000000..5b78870
--- /dev/null
@@ -0,0 +1,860 @@
+/*_############################################################################
+  _## 
+  _##  auth_priv.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+// $Id: auth_priv.h 345 2008-10-29 20:14:40Z katz $
+
+#ifndef _AUTH_PRIV_
+#define _AUTH_PRIV_
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+
+#include "snmp_pp/usm_v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define SNMPv3_USM_MAX_KEY_LEN        32
+
+/* Accept Messages with auth/priv param fields up to this length */
+#define SNMPv3_AP_MAXLENGTH_AUTHPARAM      128
+#define SNMPv3_AP_MAXLENGTH_PRIVPARAM      128
+
+
+#define SNMPv3_AP_OUTPUT_LENGTH_MD5   16
+#define SNMPv3_AP_OUTPUT_LENGTH_SHA   20
+
+class OctetStr;
+
+/**
+ * Abstract class for auth modules.
+ *
+ * This class has to be subclassed to add new authentication
+ * protocols.
+ *
+ */
+class DLLOPT Auth
+{
+public:
+
+  virtual ~Auth() {};
+
+  /**
+   * Generate the localized key for the given password and engine id.
+   *
+   * @param password      - the password
+   * @param password_len  - the length of the password
+   * @param engine_id     - pointer to snmpEngineID
+   * @param engine_id_len - length of snmpEngineID
+   * @param key           - pointer to an empty buffer that will be filled
+   *                        with generated key
+   * @param key_len       - IN: length of the buffer
+   *                        OUT: length of the key
+   *
+   * @return SNMPv3_USM_OK on success
+   */
+  virtual int password_to_key(const unsigned char *password,
+                              const unsigned int   password_len,
+                              const unsigned char *engine_id,
+                              const unsigned int   engine_id_len,
+                              unsigned char       *key,
+                              unsigned int        *key_len) = 0;
+
+  /**
+   * Generate a hash value for the given data.
+   *
+   * @param data      - the data
+   * @param data_len  - the length of the data
+   * @param digest    - pointer to the generated digest
+   *
+   * @return SNMPv3_USM_OK on success
+   */
+  virtual int hash(const unsigned char *data,
+                   const unsigned int   data_len,
+                   unsigned char       *digest) const = 0;
+
+  /**
+   * Authenticate an outgoing message.
+   *
+   * This method fills the authentication parameters field of the
+   * given message. The param auth_par_ptr is pointing inside the
+   * message buffer and must be zeroed before the authentication value
+   * is computed.
+   *
+   * @param key          - pointer to the (fixed length) key
+   * @param msg          - pointer to the whole message
+   * @param msg_len      - the length of the message
+   * @param auth_par_ptr - pointer to the auth field inside the msg buffer
+   *
+   * @return SNMPv3_USM_OK on success and
+   *         SNMPv3_USM_ERROR for unexpected errors.
+   */
+  virtual int auth_out_msg(const unsigned char *key,
+                           unsigned char       *msg,
+                           const int            msg_len,
+                           unsigned char       *auth_par_ptr) = 0;
+
+
+  /**
+   * Authenticate an incoming message.
+   *
+   * This method checks if the value in the authentication parameters
+   * field of the message is valid.
+   *
+   * The following procedure is used to verify the authenitcation value
+   * - copy the authentication value to a temp buffer
+   * - zero the auth field
+   * - recalculate the authenthication value
+   * - compare the two authentcation values
+   * - write back the received authentication value if values differ
+   *
+   * @param key          - pointer to the (fixed length) key
+   * @param msg          - pointer to the whole message
+   * @param msg_len      - the length of the message
+   * @param auth_par_ptr - pointer to the auth field inside the msg buffer
+   * @param auth_par_len - Length of the received auth field
+   *
+   * @return SNMPv3_USM_OK if the msg is valid,
+   *         SNMPv3_USM_AUTHENTICATION_FAILURE if not and
+   *         SNMPv3_USM_ERROR for unexpected errors.
+   */
+  virtual int auth_inc_msg(const unsigned char *key,
+                           unsigned char       *msg,
+                           const int            msg_len,
+                           unsigned char       *auth_par_ptr,
+                           const int            auth_par_len) = 0;
+
+  /**
+   * Get the unique id of the authentication protocol.
+   */
+  virtual int get_id() const = 0;
+
+
+  /**
+   * Get the unique identifier string of the authentication protocol.
+   */
+  virtual const char *get_id_string() const = 0;
+
+  /**
+   * Set the pointer to the salt that should be used.
+   */
+  virtual void set_salt(pp_uint64 *new_salt) { salt = new_salt; };
+
+  /**
+   * Get the maximum length that is needed for the
+   * msgAuthenticationParameters field.
+   */
+  virtual int get_auth_params_len() const = 0;
+
+  /**
+   * Get length of a hash output.
+   */
+  virtual int get_hash_len() const = 0;
+
+ protected:
+  pp_uint64 *salt;
+};
+
+
+/**
+ * Abstract class for priv modules
+ *
+ * This class has to be subclassed to add new privacy
+ * protocols.
+ *
+ */
+class DLLOPT Priv
+{
+public:
+  virtual ~Priv() {};
+
+  /**
+   * Encrypt the buffer with the given key.
+   *
+   * This method fills the privacy parameters field of the given
+   * message.
+   *
+   * @param key            - pointer to the encryption key
+   * @param key_len        - length of encryption key
+   * @param buffer         - pointer to the unencrypted buffer
+   * @param buffer_len     - length of the buffer
+   * @param out_buffer     - pointer to the buffer for the encryptet data
+   * @param out_buffer_len - Input:  Length of the output buffer.
+   *                         Output: Bytes written
+   * @param privacy_params - Buffer, where the privacy parameters
+   *                         are written to.
+   * @param privacy_params_len - Length of the privacy parameters buffer
+   * @param engine_boots   - The engine boots value for the message
+   * @param engine_time    - The engine time value for the message
+   *
+   * @return SNMPv3_USM_OK on success
+   */
+  virtual int encrypt(const unsigned char *key,
+                      const unsigned int   key_len,
+                      const unsigned char *buffer,
+                      const unsigned int   buffer_len,
+                      unsigned char       *out_buffer,
+                      unsigned int        *out_buffer_len,
+                      unsigned char       *privacy_params,
+                      unsigned int        *privacy_params_len,
+                      const unsigned long  engine_boots,
+                      const unsigned long  engine_time) = 0;
+
+
+  /**
+   * Decrypt the buffer with the given key.
+   *
+   * This method needs the privacy parameters field for the given
+   * message.
+   *
+   * @param key            - pointer to the (fixed length) dencryption key
+   * @param key_len        - length of encryption key
+   * @param buffer         - pointer to the encrypted buffer
+   * @param buffer_len     - length of the buffer
+   * @param out_buffer     - pointer to the buffer for the decryptet data
+   * @param out_buffer_len - Input:  Length of the output buffer.
+   *                         Output: Bytes written
+   * @param privacy_params - Buffer, where the privacy parameters
+   *                         are read from.
+   * @param privacy_params_len - Length of the privacy parameters buffer
+   * @param engine_boots   - The engine boots value for the message
+   * @param engine_time    - The engine time value for the message
+   *
+   * @return SNMPv3_USM_OK on success
+   */
+  virtual int decrypt(const unsigned char *key,
+                      const unsigned int   key_len,
+                      const unsigned char *buffer,
+                      const unsigned int   buffer_len,
+                      unsigned char       *out_buffer,
+                      unsigned int        *out_buffer_len,
+                      const unsigned char *privacy_params,
+                      const unsigned int   privacy_params_len,
+                     const unsigned long  engine_boots,
+                     const unsigned long  engine_time) = 0;
+
+  /**
+   * Extend a localized key that is too short.
+   *
+   * Some privacy protocols require a key that is longer than the key
+   * generated by the pasword to key algorithm of the authentication
+   * protocol. This function extends a short key to the required length.
+   *
+   * @param password      - the password
+   * @param password_len  - the length of the password
+   * @param engine_id     - pointer to snmpEngineID
+   * @param engine_id_len - length of snmpEngineID
+   * @param key           - pointer to the short key that was generated
+   *                        using Auth::password_to_key() function
+   * @param key_len       - IN: length of the short key
+   *                        OUT: length of the extended key
+   * @param max_key_len   - Length of the key buffer
+   * @param auth          - Pointer of the authentication protocol that
+   *                        should be used
+   *
+   * @return SNMPv3_USM_OK on success
+   */
+
+  virtual int extend_short_key(const unsigned char *password,
+                               const unsigned int   password_len,
+                               const unsigned char *engine_id,
+                               const unsigned int   engine_id_len,
+                               unsigned char       *key,
+                               unsigned int        *key_len,
+                               const unsigned int   max_key_len,
+                               Auth                *auth) = 0;
+
+  /**
+   * Get the uniqhe id of the privacy protocol.
+   */
+  virtual int get_id() const = 0;
+
+  /**
+   * Get the unique identifier string of the privacy protocol.
+   */
+  virtual const char *get_id_string() const = 0;
+
+  /**
+   * Set the pointer to the salt that should be used.
+   */
+  virtual void set_salt(pp_uint64 *new_salt) { salt = new_salt; };
+
+  /**
+   * Get the maximum length that is needed for the
+   * msgPrivacyParameters field.
+   */
+  virtual int get_priv_params_len() const = 0;
+
+  /**
+   * Get the minimum key length needed for encryption and decryption.
+   */
+  virtual int get_min_key_len() const = 0;
+
+  /**
+   * Decrease a too long length to the right value.
+   */
+  virtual void fix_key_len(unsigned int &key_len) const = 0;
+
+ protected:
+  pp_uint64 *salt;
+
+};
+
+typedef Auth* AuthPtr;
+typedef Priv* PrivPtr;
+
+
+/**
+ * Class that holds all authentication and privacy protocols
+ * for a snmp entity.
+ */
+class DLLOPT AuthPriv
+{
+public:
+
+  /**
+   * Default constructor, initializes random values
+   */
+  AuthPriv(int &construct_state);
+
+  /**
+   * Destructor, deletes all auth and priv protocol objets.
+   */
+  ~AuthPriv();
+
+  /**
+   * Add the default authentication protocols.
+   *
+   * The following authentication protocols are added:
+   * - MD5
+   * - SHA
+   *
+   * The following privacy protocols are added:
+   * - DES
+   * - AES128, AES192 and AES256 if libtomcrypt or OpenSSL is enabled
+   * - IDEA if enabled
+   *
+   * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_ERROR.
+   */
+  int add_default_modules();
+
+  /**
+   * Add a new authentication protocol.
+   *
+   * All added objects will be deleted in the destructor
+   *
+   * @param auth - Pointer to a new auth protocol object
+   *
+   * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_ERROR
+   */
+  int add_auth(Auth *auth);
+
+  /**
+   * Delete a authentication protocol.
+   *
+   * @param auth_id - The id of the authentication protocol to remove
+   *
+   * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_ERROR
+   */
+  int del_auth(const int auth_id);
+
+  /**
+   * Add a new privacy protocol.
+   *
+   * All added objects will be deleted in the destructor
+   *
+   * @param priv - Pointer to a new privacy protocol object
+   *
+   * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_ERROR
+   */
+  int add_priv(Priv *priv);
+
+  /**
+   * Delete a privacy protocol.
+   *
+   * @param priv_id - The id of the privacy protocol to remove
+   *
+   * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_ERROR
+   */
+  int del_priv(const int priv_id);
+
+  /**
+   * Call the password-to-key method of the specified authentication
+   * protocol.
+   */
+  int password_to_key_auth(const int      auth_prot,
+                           const unsigned char *password,
+                           const unsigned int   password_len,
+                           const unsigned char *engine_id,
+                           const unsigned int   engine_id_len,
+                           unsigned char *key,
+                           unsigned int  *key_len);
+
+  /**
+   * Call the password-to-key method of the specified privacy
+   * protocol.
+   */
+  int password_to_key_priv(const int      auth_prot,
+                           const int      priv_prot,
+                           const unsigned char *password,
+                           const unsigned int   password_len,
+                           const unsigned char *engine_id,
+                           const unsigned int   engine_id_len,
+                           unsigned char *key,
+                           unsigned int  *key_len);
+
+  /**
+   * Get the keyChange value for the specified keys using the given
+   * authentication protocol.
+   */
+  int get_keychange_value(const int       auth_prot,
+                          const OctetStr& old_key,
+                          const OctetStr& new_key,
+                          OctetStr&       keychange_value);
+
+  /**
+   * Get a pointer to a privacy protocol object.
+   */
+  Priv *get_priv(const int priv_prot);
+
+  /**
+   * Get a pointer to a authentication protocol object.
+   */
+  Auth *get_auth(const int auth_prot);
+
+  /**
+   * Get the unique id for the given auth protocol.
+   *
+   * @param string_id - The string returned by Auth::get_id_string()
+   *
+   * @return The id or -1
+   */
+  int get_auth_id(const char *string_id) const;
+
+  /**
+   * Get the unique id for the given priv protocol.
+   *
+   * @param string_id - The string returned by Priv::get_id_string()
+   *
+   * @return The id or -1
+   */
+  int get_priv_id(const char *string_id) const;
+
+  /**
+   * Encrypt a message.
+   */
+  int encrypt_msg(const int            priv_prot,
+                  const unsigned char *key,
+                  const unsigned int   key_len,
+                  const unsigned char *buffer,
+                  const unsigned int   buffer_len,
+                  unsigned char       *out_buffer,
+                  unsigned int        *out_buffer_len,
+                  unsigned char       *privacy_params,
+                  unsigned int        *privacy_params_len,
+                  const unsigned long  engine_boots,
+                  const unsigned long  engine_time);
+
+  /**
+   * Decrypt a message.
+   */
+  int decrypt_msg(const int            priv_prot,
+                  const unsigned char *key,
+                  const unsigned int   key_len,
+                  const unsigned char *buffer,
+                  const unsigned int   buffer_len,
+                  unsigned char       *out_buffer,
+                  unsigned int        *out_buffer_len,
+                  const unsigned char *privacy_params,
+                  const unsigned int   privacy_params_len,
+                 const unsigned long  engine_boots,
+                 const unsigned long  engine_time);
+
+  /**
+   * Get the length of the authentication parameters field of the given
+   * authentication protocol.
+   */
+  int get_auth_params_len(const int auth_prot);
+
+  /**
+   * Get the length of the privacy parameters field of the given
+   * privacy protocol.
+   */
+  int get_priv_params_len(const int priv_prot);
+
+  /**
+   * Fill in the authentication field of an outgoing message
+   */
+  int auth_out_msg(const int            auth_prot,
+                   const unsigned char *key,
+                   unsigned char       *msg,
+                   const int            msg_len,
+                   unsigned char       *auth_par_ptr);
+
+  /**
+   * Check the authentication field of an incoming message
+   */
+  int auth_inc_msg(const int            auth_prot,
+                   const unsigned char *key,
+                   unsigned char       *msg,
+                   const int            msg_len,
+                   unsigned char       *auth_par_ptr,
+                   const int            auth_par_len);
+
+private:
+
+  AuthPtr *auth;   ///< Array of pointers to Auth-objects
+  PrivPtr *priv;   ///< Array of pointers to Priv-objects
+  int   auth_size; ///< current size of the auth array
+  int   priv_size; ///< current size of the priv array
+  pp_uint64 salt;  ///< current salt value (64 bits)
+};
+
+
+/**
+ * Authentication module using SHA.
+ *
+ * @see Auth
+ */
+class DLLOPT AuthSHA: public Auth
+{
+public:
+  int password_to_key(const unsigned char *password,
+                     const unsigned int   password_len,
+                     const unsigned char *engine_id,
+                     const unsigned int   engine_id_len,
+                     unsigned char       *key,
+                     unsigned int        *key_len);
+
+  int hash(const unsigned char *data,
+          const unsigned int   data_len,
+          unsigned char       *digest) const;
+
+  int auth_out_msg(const unsigned char *key,
+                  unsigned char       *msg,
+                  const int            msg_len,
+                  unsigned char       *auth_par_ptr);
+
+  int auth_inc_msg(const unsigned char *key,
+                  unsigned char       *msg,
+                  const int            msg_len,
+                  unsigned char       *auth_par_ptr,
+                   const int            auth_par_len);
+
+  int get_id() const { return SNMP_AUTHPROTOCOL_HMACSHA; };
+
+  const char *get_id_string() const { return "HMAC-SHA"; };
+
+  int get_auth_params_len() const { return 12; };
+
+  int get_hash_len() const { return SNMPv3_AP_OUTPUT_LENGTH_SHA;};
+};
+
+/**
+ * Authentication module using MD5.
+ *
+ * @see Auth
+ */
+class DLLOPT AuthMD5: public Auth
+{
+public:
+  int password_to_key(const unsigned char *password,
+                     const unsigned int   password_len,
+                     const unsigned char *engine_id,
+                     const unsigned int   engine_id_len,
+                     unsigned char       *key,
+                     unsigned int        *key_len);
+
+  int hash(const unsigned char *data,
+          const unsigned int   data_len,
+          unsigned char       *digest) const;
+
+  int auth_out_msg(const unsigned char *key,
+                  unsigned char       *msg,
+                  const int            msg_len,
+                  unsigned char       *auth_par_ptr);
+
+
+  int auth_inc_msg(const unsigned char *key,
+                  unsigned char       *msg,
+                  const int            msg_len,
+                  unsigned char       *auth_par_ptr,
+                   const int            auth_par_len);
+
+  int get_id() const { return SNMP_AUTHPROTOCOL_HMACMD5; };
+
+  const char *get_id_string() const { return "HMAC-MD5"; };
+
+  int get_auth_params_len() const { return 12; };
+
+  int get_hash_len() const { return SNMPv3_AP_OUTPUT_LENGTH_MD5;};
+};
+
+/**
+ * Encryption module using DES.
+ *
+ * @see Priv
+ */
+class DLLOPT PrivDES: public Priv
+{
+ public:
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+  PrivDES();
+ private:
+  int cipher;
+ public:
+#endif
+  int encrypt(const unsigned char *key,
+              const unsigned int   key_len,
+              const unsigned char *buffer,
+              const unsigned int   buffer_len,
+              unsigned char       *out_buffer,
+              unsigned int        *out_buffer_len,
+              unsigned char       *privacy_params,
+              unsigned int        *privacy_params_len,
+              const unsigned long  engine_boots,
+              const unsigned long  engine_time);
+
+  int decrypt(const unsigned char *key,
+              const unsigned int   key_len,
+              const unsigned char *buffer,
+              const unsigned int   buffer_len,
+              unsigned char       *out_buffer,
+              unsigned int        *out_buffer_len,
+              const unsigned char *privacy_params,
+              const unsigned int   privacy_params_len,
+             const unsigned long  engine_boots,
+             const unsigned long  engine_time);
+
+  int extend_short_key(const unsigned char *password,
+                       const unsigned int   password_len,
+                       const unsigned char *engine_id,
+                       const unsigned int   engine_id_len,
+                       unsigned char       *key,
+                       unsigned int        *key_len,
+                       const unsigned int   max_key_len,
+                       Auth                *auth)
+    { return SNMPv3_USM_ERROR; /* not needed for DES! */ };
+
+  int get_id() const { return SNMP_PRIVPROTOCOL_DES; };
+  const char *get_id_string() const { return "DES"; };
+  int get_priv_params_len() const { return 8; };
+  int get_min_key_len() const { return 16; };
+  void fix_key_len(unsigned int &key_len) const
+    { key_len = (key_len >= 16 ? 16 : 0); };
+};
+
+#ifdef _USE_IDEA
+/**
+ * Encryption module using IDEA.
+ *
+ * @see Priv
+ */
+class DLLOPT PrivIDEA: public Priv
+{
+public:
+
+  int encrypt(const unsigned char *key,
+              const unsigned int   key_len,
+              const unsigned char *buffer,
+              const unsigned int   buffer_len,
+              unsigned char       *out_buffer,
+              unsigned int        *out_buffer_len,
+              unsigned char       *privacy_params,
+              unsigned int        *privacy_params_len,
+              const unsigned long  engine_boots,
+              const unsigned long  engine_time);
+
+  int decrypt(const unsigned char *key,
+              const unsigned int   key_len,
+              const unsigned char *buffer,
+              const unsigned int   buffer_len,
+              unsigned char       *out_buffer,
+              unsigned int        *out_buffer_len,
+              const unsigned char *privacy_params,
+              const unsigned int   privacy_params_len,
+             const unsigned long  engine_boots,
+             const unsigned long  engine_time);
+
+  int extend_short_key(const unsigned char *password,
+                       const unsigned int   password_len,
+                       const unsigned char *engine_id,
+                       const unsigned int   engine_id_len,
+                       unsigned char       *key,
+                       unsigned int        *key_len,
+                       const unsigned int   max_key_len,
+                       Auth                *auth)
+    { return SNMPv3_USM_ERROR; /* not needed for IDEA! */ };
+
+  int get_id() const { return SNMP_PRIVPROTOCOL_IDEA; };
+  const char *get_id_string() const { return "IDEA"; };
+  int get_priv_params_len() const { return 8; };
+  int get_min_key_len() const { return 16; };
+  void fix_key_len(unsigned int &key_len) const
+    { key_len = (key_len >= 16 ? 16 : 0); };
+};
+
+#endif
+
+
+#if defined(_USE_LIBTOMCRYPT) || defined(_USE_OPENSSL)
+
+/**
+ * Encryption module using AES (only available with libtomcrypt).
+ *
+ * @see Priv
+ */
+class DLLOPT PrivAES: public Priv
+{
+public:
+
+  PrivAES(const int aes_type_);
+
+  int encrypt(const unsigned char *key,
+              const unsigned int   key_len,
+              const unsigned char *buffer,
+              const unsigned int   buffer_len,
+              unsigned char       *out_buffer,
+              unsigned int        *out_buffer_len,
+              unsigned char       *privacy_params,
+              unsigned int        *privacy_params_len,
+              const unsigned long  engine_boots,
+              const unsigned long  engine_time);
+
+  int decrypt(const unsigned char *key,
+              const unsigned int   key_len,
+              const unsigned char *buffer,
+              const unsigned int   buffer_len,
+              unsigned char       *out_buffer,
+              unsigned int        *out_buffer_len,
+              const unsigned char *privacy_params,
+              const unsigned int   privacy_params_len,
+             const unsigned long  engine_boots,
+             const unsigned long  engine_time);
+
+  int extend_short_key(const unsigned char *password,
+                       const unsigned int   password_len,
+                       const unsigned char *engine_id,
+                       const unsigned int   engine_id_len,
+                       unsigned char       *key,
+                       unsigned int        *key_len,
+                       const unsigned int   max_key_len,
+                       Auth                *auth);
+
+  int get_id() const { return aes_type; };
+  const char *get_id_string() const;
+  int get_priv_params_len() const { return 8; };
+  int get_min_key_len() const { return key_bytes; };
+  void fix_key_len(unsigned int &key_len) const
+    { key_len = (key_len >= (unsigned)key_bytes ? key_bytes : 0); };
+
+ private:
+  int aes_type;
+  int key_bytes;
+  int rounds;
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+  int cipher;
+#endif
+  int need_byteswap;
+};
+#endif // _USE_LIBTOMCRYPT or _USE_OPENSSL
+
+#ifdef _USE_3DES_EDE
+/**
+ * Encryption module using TripleDES-EDE KEY
+ * 
+ *
+ * @see Priv
+ */
+#define TRIPLEDES_EDE_KEY_LEN 32
+
+
+class DLLOPT Priv3DES_EDE: public Priv
+{
+public:
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+  Priv3DES_EDE();
+ private:
+  int cipher;
+ public:
+#endif
+
+  int encrypt(const unsigned char *key,
+              const unsigned int   key_len,
+              const unsigned char *buffer,
+              const unsigned int   buffer_len,
+              unsigned char       *out_buffer,
+              unsigned int        *out_buffer_len,
+              unsigned char       *privacy_params,
+              unsigned int        *privacy_params_len,
+              const unsigned long  engine_boots,
+              const unsigned long  engine_time);
+
+  int decrypt(const unsigned char *key,
+              const unsigned int   key_len,
+              const unsigned char *buffer,
+              const unsigned int   buffer_len,
+              unsigned char       *out_buffer,
+              unsigned int        *out_buffer_len,
+              const unsigned char *privacy_params,
+              const unsigned int   privacy_params_len,
+             const unsigned long  engine_boots,
+             const unsigned long  engine_time);
+
+  int extend_short_key(const unsigned char *password,
+                       const unsigned int   password_len,
+                       const unsigned char *engine_id,
+                       const unsigned int   engine_id_len,
+                       unsigned char       *key,
+                       unsigned int        *key_len,
+                       const unsigned int   max_key_len,
+                       Auth                *auth);
+
+  int get_id() const { return SNMP_PRIVPROTOCOL_3DESEDE; };
+  const char *get_id_string() const { return "3DESEDE"; };
+  int get_priv_params_len() const { return 8; };
+  int get_min_key_len() const { return TRIPLEDES_EDE_KEY_LEN; };
+  void fix_key_len(unsigned int &key_len) const
+    { key_len = (key_len >= TRIPLEDES_EDE_KEY_LEN
+                                              ? TRIPLEDES_EDE_KEY_LEN : 0); };
+#ifdef _TEST
+  bool test();
+#endif
+};
+
+#endif // _USE_3DES_EDE
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // _SNMPv3
+
+#endif
diff --git a/3rdparty/snmp++/include/snmp_pp/collect.h b/3rdparty/snmp++/include/snmp_pp/collect.h
new file mode 100644 (file)
index 0000000..faa8b92
--- /dev/null
@@ -0,0 +1,396 @@
+/*_############################################################################
+  _## 
+  _##  collect.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++ C O L L E C T . H
+
+  COLLECTION CLASS DEFINITION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION: Simple Collection classes for SNMP++ classes.
+
+=====================================================================*/
+// $Id: collect.h 349 2008-11-17 23:23:35Z katz $
+
+#ifndef _COLLECTION_H_
+#define _COLLECTION_H_
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MAXT 25     // elements per block
+
+template <class T> class SnmpCollection
+{
+  class cBlock
+  {
+    public:
+     cBlock(cBlock *p, cBlock *n) : prev(p), next(n) {};
+     T *item[MAXT];
+     cBlock *prev;
+     cBlock *next;
+  };
+
+ public:
+
+  /**
+   * Create an empty collection.
+   */
+  SnmpCollection()
+    : count(0), data(0,0) {};
+
+  /**
+   * Create a collection using a single template object.
+   */
+  SnmpCollection(const T &t)
+    : count(1), data(0, 0)
+  {
+    data.item[0] = (T*) (t.clone());
+  };
+
+  /**
+   * Create a collection with another collection (copy constructor).
+   */
+  SnmpCollection(const SnmpCollection<T> &c)
+    : count(0), data(0, 0)
+  {
+    if (c.count == 0) return;
+
+    // load up the new collection
+    cBlock *current = &data;
+    cBlock *nextBlock;
+    int cn = 0;
+
+    while (count < c.count)
+    {
+      if (cn >= MAXT)
+      {
+       nextBlock = new cBlock(current, 0);
+       current->next = nextBlock;
+       current = nextBlock;
+       cn=0;
+      }
+      T *tmp = 0;
+      c.get_element(tmp, count);
+      current->item[cn] = (T*) (tmp->clone());
+      count++;
+      cn++;
+    }
+  };
+
+  /**
+   * Destroy the collection.
+   */
+  ~SnmpCollection()
+  {
+    clear();  // just delete the data
+  };
+
+  /**
+   * Get the size of the collection.
+   */
+  int size() const
+  {
+    return count;
+  };
+
+  /**
+   * Append an item to the collection.
+   */
+  SnmpCollection& operator +=(const T &i)
+  {
+    cBlock *current = &data;
+    int cn = (int) count % MAXT;
+    while (current->next)
+      current = current->next;
+    if ((count > 0) && ((count % MAXT) == 0))
+    {
+      cBlock *add = new cBlock(current, 0);
+      if (!add) return *this;
+      current->next = add;
+      add->item[0] = (T*) (i.clone());
+    }
+    else
+    {
+      current->item[cn] = (T*) (i.clone());
+    }
+    count++;
+
+    return *this;
+  };
+
+  /**
+   * Assign one collection to another.
+   */
+  SnmpCollection &operator =(const SnmpCollection<T> &c)
+  {
+    if (this == &c) return *this;  // check for self assignment
+
+    clear(); // delete the data
+
+    if (c.count == 0) return *this;
+
+    // load up the new collection
+    cBlock *current = &data;
+    cBlock *nextBlock;
+    int cn = 0;
+    count = 0;
+    while (count < c.count)
+    {
+      if (cn >= MAXT)
+      {
+       nextBlock = new cBlock(current, 0);
+       current->next = nextBlock;
+       current = nextBlock;
+       cn=0;
+      }
+      T *tmp = 0;
+      c.get_element(tmp, count);
+      current->item[cn] = (T*) (tmp->clone());
+      count++;
+      cn++;
+    }
+
+    return *this;
+  };
+
+  /**
+   * Access an element in the collection.
+   *
+   * @return The requestet element or an empty element if out of bounds.
+   */
+  T operator[](const int p) const
+  {
+    if ((p < count) && (p >= 0))
+    {
+      cBlock const *current = &data;
+      int bn = (int) (p / MAXT);
+      int cn = (int) p % MAXT;
+      for (int z=0; z<bn; z++)
+       current = current->next;
+      return *(current->item[cn]);
+    }
+    else
+    {
+      // return an instance of nothing!!
+      T t;
+      return t;
+    }
+  };
+
+  /**
+   * Set an element in the collection.
+   *
+   * @return 0 on success and -1 on failure.
+   */
+  int set_element( const T& i, const int p)
+  {
+    if ((p < 0) || (p > count)) return -1; // not found!
+
+    cBlock *current = &data;
+    int bn = (int) p / MAXT;
+    int cn = (int) p % MAXT;
+    for (int z=0; z<bn; z++)
+      current = current->next;
+    delete current->item[cn];
+    current->item[cn] = (T*) (i.clone());
+    return 0;
+  };
+
+  /**
+   * Get an element in the collection.
+   *
+   * @return 0 on success and -1 on failure.
+   */
+  int get_element(T &t, const int p) const
+  {
+    if ((p < 0) || (p > count)) return -1; // not found!
+
+    cBlock const *current = &data;
+    int bn = (int) p / MAXT;
+    int cn = (int) p % MAXT;
+    for (int z=0; z<bn; z++)
+      current = current->next;
+    t = *(current->item[cn]);
+    return 0;
+  };
+
+  /**
+   * Get a pointer to an element in the collection.
+   *
+   * @return 0 on success and -1 on failure.
+   */
+  int get_element(T *&t, const int p) const
+  {
+    if ((p < 0) || (p > count)) return -1; // not found!
+
+    cBlock const *current = &data;
+    int bn = (int) p / MAXT;
+    int cn = (int) p % MAXT;
+    for (int z=0; z<bn; z++)
+      current = current->next;
+    t = current->item[cn];
+    return 0;
+  };
+
+  /**
+   * Apply an function to the entire collection, iterator.
+   */
+  void apply(void f(T&))
+  {
+    T temp;
+    for ( int z=0; z<count; z++)
+    {
+      this->get_element(temp, z);
+      f(temp);
+    }
+  };
+
+  /**
+   * Looks for an element in the collection.
+   *
+   * @return TRUE if found.
+   */
+  int find(const T& i, int &pos) const
+  {
+    T temp;
+    for (int z=0; z<count; z++)
+    {
+      this->get_element(temp, z);
+      if ( temp == i) {
+       pos = z;
+       return TRUE;
+      }
+    }
+    return FALSE;
+  };
+
+  /**
+   * Delete an element in the collection.
+   */
+  int remove(const T& i)
+  {
+    // first see if we have it
+    int pos;
+    if (find(i, pos))
+    {
+      SnmpCollection<T> newCollection;
+
+      for (int z=0; z<count; z++)
+      {
+       if (z != pos)
+       {
+         T item;
+         get_element(item, z);
+         newCollection += item;
+       }
+      }
+
+      // assign new collection to 'this'
+      operator =(newCollection);
+
+      return TRUE;
+    }
+    return FALSE;   // not found thus not removed
+  };
+
+  /**
+   * Delete all elements within the collection.
+   */
+  void clear()
+  {
+    if (count == 0) return;
+
+    cBlock *current = &data;
+    int z=0;
+    int cn=0;
+    while ( z< count)
+    {
+      if (cn >= MAXT)
+      {
+       cn =0;
+       current = current->next;
+      }
+      delete current->item[cn];
+      cn++;
+      z++;
+    }
+
+    // delete the blocks
+    while (current->next)
+      current = current->next;
+    while (current->prev)
+    {
+      current = current->prev;
+      delete current->next;
+    }
+
+    count = 0;
+    data.next=0;
+    data.prev=0;
+  };
+
+ private:
+  int count;
+  cBlock data;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif  // _COLLECTION_H_
+
diff --git a/3rdparty/snmp++/include/snmp_pp/config_snmp_pp.h b/3rdparty/snmp++/include/snmp_pp/config_snmp_pp.h
new file mode 100644 (file)
index 0000000..e21567b
--- /dev/null
@@ -0,0 +1,284 @@
+/*_############################################################################
+  _## 
+  _##  config_snmp_pp.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+// $Id: config_snmp_pp.h 1823 2010-08-25 21:59:53Z fock $
+
+#ifndef _CONFIG_SNMP_PP_H_
+#define _CONFIG_SNMP_PP_H_
+
+#define SNMP_PP_VERSION_STRING "3.2.25"
+#define SNMP_PP_VERSION 3
+#define SNMP_PP_RELEASE 2
+#define SNMP_PP_PATCHLEVEL 25
+
+//! The maximum size of a message that can be sent or received.
+#define MAX_SNMP_PACKET 4096
+
+#ifndef DLLOPT
+#if defined (WIN32) && defined (SNMP_PP_DLL)
+#ifdef SNMP_PP_EXPORTS
+#define DLLOPT __declspec(dllexport)
+#define DLLOPT_TEMPL
+#else
+#define DLLOPT __declspec(dllimport)   
+#define DLLOPT_TEMPL extern
+#endif
+#else
+#define DLLOPT
+#define DLLOPT_TEMPL
+#endif
+#endif
+
+// define SNMP_PP_IPv6 if you want to use IPv6
+// #define SNMP_PP_IPv6
+
+// define SNMP_PP_NAMESPACE to enclose all library names in Snmp_pp namespace
+// #define SNMP_PP_NAMESPACE
+
+// define _NO_SNMPv3 here or in the Makefile if you do not want to use SNMPv3
+// (default is to use SNMPv3)
+// #define _NO_SNMPv3
+
+// If you have not disabled SNMPv3, snmp++ will use libdes
+// (separate package) as default.
+// define _USE_LIBTOMCRYPT if you want to use libtomcrypt instead
+// Note that _USE_OPENSSL will override libtomcrypt for SHA1, MD5, DES and AES.
+// #define _USE_LIBTOMCRYPT
+
+// If you define _USE_OPENSSL, snmp++ will use OpenSSL for SHA1,
+// MD5, DES and AES. Please note that you will have to change the Makefiles
+// of the examples: Add -lssl to the link command
+// #define _USE_OPENSSL
+
+// If you do not use SNMP++ for commercial purposes or if you
+// have licensed IDEA (read README.v3) you may define the following
+// to enable IDEA support. (note this is not defined by a rfc)
+// #define _USE_IDEA
+
+// Enable 3DES Privacy (note this is not defined by a rfc)
+// #define _USE_3DES_EDE
+
+// define _NO_THREADS here or in the Makefile if you do not want thread support
+// (default is to include thread support)
+// #define _NO_THREADS
+
+// define _NO_LOGGING if you do not want any logging output 
+// (increases performance drastically and minimizes memory consumption)
+//#define _NO_LOGGING
+
+// define _IPX_ADDRESS and/or _MAC_ADDRESS if you want to use the
+// classess IpxAddress/IpxSockAddress and/or MacAddress
+// #define _IPX_ADDRESS
+// #define _MAC_ADDRESS
+
+// define this if you want to send out broadcasts
+#define SNMP_BROADCAST
+
+
+// Not fully tested!
+//#define HAVE_POLL_SYSCALL
+
+// Some older(?) compilers need a special declaration of
+// template classes
+// #define _OLD_TEMPLATE_COLLECTION
+
+// We have inet_aton() function if not compiling with VC++ or Borland C++
+#ifndef _MSC_VER
+#ifndef __BCPLUSPLUS__
+#define HAVE_INET_ATON
+#endif
+#endif
+
+// If IPv6 is enabled assume that inet_pton() is available
+// If IPv6 and gcc then assume gethostbyname2() is available
+#ifdef SNMP_PP_IPv6
+#define HAVE_INET_PTON
+#ifdef __GNUC__
+#define HAVE_GETHOSTBYNAME2
+#endif
+#endif
+
+// can we use the reentrant version of these functions or
+// are the standard functions thread safe
+#ifdef __CYGWIN32__
+#define HAVE_LOCALTIME_R
+#define HAVE_REENTRANT_LOCALTIME
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#undef  HAVE_GETHOSTBYNAME2
+#elif __MINGW32__
+//FIXME: snmp++/src/address.cpp:865: error: `inet_ntop' was not declared in this scope
+//FIXME: snmp++/src/address.cpp:988: error: `inet_pton' was not declared in this scope
+//FIXME: snmp++/src/notifyqueue.cpp:538: error: `inet_pton' was not declared in this scope
+#undef  HAVE_INET_ATON
+#undef  HAVE_GETHOSTBYNAME2
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#define HAVE_REENTRANT_LOCALTIME
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#elif __APPLE__
+#define HAVE_LOCALTIME_R
+#define HAVE_REENTRANT_LOCALTIME
+#elif __GNUC__
+#define HAVE_GETHOSTBYNAME_R
+#define HAVE_LOCALTIME_R
+#define HAVE_GETHOSTBYADDR_R
+#elif __DECCXX
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#define HAVE_LOCALTIME_R
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#elif __sun
+#define HAVE_GETHOSTBYNAME_R
+#define HAVE_LOCALTIME_R
+#define HAVE_GETHOSTBYADDR_R
+#elif __HP_aCC
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#define HAVE_LOCALTIME_R
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#elif _MSC_VER
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#define HAVE_REENTRANT_LOCALTIME
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#elif _AIX
+#define HAVE_REENTRANT_GETHOSTBYNAME
+#define HAVE_LOCALTIME_R
+#define HAVE_REENTRANT_GETHOSTBYADDR
+#endif
+
+// Define a unsigned 64 bit integer:
+#ifdef WIN32
+#ifdef SNMP_PP_IPv6
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <windows.h>
+#include <winsock.h>
+#endif
+#ifdef __BCPLUSPLUS__
+typedef unsigned __int64 pp_uint64;
+#else
+typedef ULONGLONG pp_uint64;
+#endif
+#else // not WIN32
+typedef unsigned long long pp_uint64;
+#endif
+
+// Define a type used for sockets
+#ifdef _MSC_VER
+    typedef SOCKET SnmpSocket;
+#else
+    typedef int SnmpSocket;
+#endif
+
+#ifdef HAVE_POLL_SYSCALL
+#include <poll.h>
+#endif
+
+///////////////////////////////////////////////////////////////////////
+// Changes below this line should not be necessary
+///////////////////////////////////////////////////////////////////////
+
+
+// Make use of mutable keyword
+//#define SNMP_PP_MUTABLE mutable
+#define SNMP_PP_MUTABLE
+
+#define SAFE_INT_CAST(expr)  ((int)(expr))
+#define SAFE_UINT_CAST(expr) ((unsigned int)(expr))
+
+// Safe until 32 bit second counter wraps to zero (time functions)
+#define SAFE_LONG_CAST(expr)  ((long)(expr))
+#define SAFE_ULONG_CAST(expr) ((unsigned long)(expr))
+
+#ifndef _NO_THREADS
+
+#ifndef HAVE_REENTRANT_LOCALTIME
+#ifndef HAVE_LOCALTIME_R
+// If you see this warning, and your system has a reentrant localtime
+// or localtime_r function report your compiler, OS,... to the authors
+// of this library, so that these settings can be changed
+#warning Threads_defined_but_no_reentrant_LOCALTIME_function
+#endif
+#endif
+
+#ifndef HAVE_GETHOSTBYADDR_R
+#ifndef HAVE_REENTRANT_GETHOSTBYADDR
+// If you see this warning, and your system has a reentrant localtime
+// or localtime_r function report your compiler, OS,... to the authors
+// of this library, so that these settings can be changed
+#warning Threads_defined_but_no_reentrant_GETHOSTBYADDR_function
+#endif
+#endif
+
+#ifndef HAVE_GETHOSTBYNAME_R
+#ifndef HAVE_REENTRANT_GETHOSTBYNAME
+// If you see this warning, and your system has a reentrant localtime
+// or localtime_r function report your compiler, OS,... to the authors
+// of this library, so that these settings can be changed
+#warning Threads_defined_but_no_reentrant_GETHOSTBYNAME_function
+#endif
+#endif
+
+#endif // _NO_THREADS
+
+
+#ifndef _NO_SNMPv3
+#ifndef _SNMPv3
+#define _SNMPv3
+#endif
+#endif
+
+#ifndef _NO_THREADS
+#ifdef WIN32
+
+#ifndef _THREADS
+#define _WIN32THREADS
+#define VC_EXTRALEAN
+#define _THREADS
+#endif
+
+#else  // !WIN32
+
+#ifndef _THREADS
+#define _THREADS
+#endif
+
+#ifdef __APPLE__
+#define __unix
+#endif
+
+#ifndef POSIX_THREADS
+#ifdef __unix
+#define POSIX_THREADS
+#endif
+#endif
+
+#endif // WIN32
+#endif // !_NO_THREADS
+
+#endif // _CONFIG_SNMP_PP_H_
diff --git a/3rdparty/snmp++/include/snmp_pp/counter.h b/3rdparty/snmp++/include/snmp_pp/counter.h
new file mode 100644 (file)
index 0000000..d3719bd
--- /dev/null
@@ -0,0 +1,146 @@
+/*_############################################################################
+  _## 
+  _##  counter.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++ C O U N T E R. H
+
+  COUNTER32 CLASS DEFINITION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  Class definition for SMI Counter32 class.
+
+=====================================================================*/
+// $Id: counter.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _COUNTER
+#define _COUNTER
+
+#include "snmp_pp/integer.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//------------[ Counter32 Class ]------------------------------------------
+/**
+ * The counter class allows all the functionality of unsigned
+ * integers but is recognized as a distinct SMI type. Counter32
+ * class objects may be set or get into Vb objects.
+ */
+class DLLOPT Counter32: public SnmpUInt32
+{
+ public:
+  /**
+   * Constructor to create a Counter object with value zero.
+   */
+  Counter32() : SnmpUInt32() { smival.syntax = sNMP_SYNTAX_CNTR32; };
+
+  /**
+   * Constructor with a value.
+   *
+   * @param i - unsigned 32 bit value
+   */
+  Counter32(const unsigned long i) : SnmpUInt32(i)
+    { smival.syntax = sNMP_SYNTAX_CNTR32; };
+
+  /**
+   * Copy constructor.
+   *
+   * @param c - Object to copy from
+   */
+  Counter32(const Counter32 &c);
+
+  /**
+   * Return the syntax.
+   *
+   * @return Returns always sNMP_SYNTAX_CNTR32
+   */
+  SmiUINT32 get_syntax() const { return sNMP_SYNTAX_CNTR32; };
+
+  /**
+   * Clone operator.
+   *
+   * @return Pointer to a newly created copy of the object.
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *)new Counter32(*this); };
+
+  /**
+   * Map other SnmpSyntax objects to Counter32.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  /**
+   * Overloaded assignment for Counter32.
+   *
+   * @param uli - new value
+   * @return self reference
+   */
+  Counter32& operator=(const Counter32 &uli)
+    { smival.value.uNumber = uli.smival.value.uNumber;
+      m_changed = true; return *this;};
+
+  /**
+   * Overloaded assignment for unsigned longs.
+   *
+   * @param i - new value
+   * @return self reference
+   */
+  Counter32& operator=(const unsigned long i)
+    { smival.value.uNumber = i; m_changed = true; return *this;};
+
+  /**
+   * Casting to unsigned long.
+   *
+   * @return Current value as an unsigned long
+   */
+  operator unsigned long() { return smival.value.uNumber; };
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // _COUNTER
diff --git a/3rdparty/snmp++/include/snmp_pp/ctr64.h b/3rdparty/snmp++/include/snmp_pp/ctr64.h
new file mode 100644 (file)
index 0000000..338fe31
--- /dev/null
@@ -0,0 +1,325 @@
+/*_############################################################################
+  _## 
+  _##  ctr64.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+               
+  SNMP++ C O U N T E R 6 4 . H
+
+  COUNTER64 CLASSES DEFINITION
+
+  DESIGN + AUTHOR:    Peter E Mellquist
+
+  DESCRIPTION:        SNMP Counter64 class definition.
+
+=====================================================================*/
+// $Id: ctr64.h 1558 2009-07-03 20:16:53Z katz $
+
+#ifndef _CTR64
+#define _CTR64
+
+#include "snmp_pp/smival.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define CTR64OUTBUF 30  //!< maximum ascii string for a 64-bit counter
+
+//---------[ 64 bit Counter Class ]--------------------------------
+/**
+ * Counter64 Class encapsulates two unsigned integers into a
+ * a single entity. This type has is available in SNMPv2 but
+ * may be used anywhere where needed.
+ */
+class DLLOPT Counter64: public  SnmpSyntax
+{
+ public:
+
+  //-----------[ Constructors and Destrucotr ]----------------------
+
+  /**
+   * Constructs a valid Couter64 with value 0.
+   */
+  Counter64();
+
+  /**
+   * Constructs a valid Counter64 with the given value as the lower 32 bits.
+   *
+   * @param lo - value (0..MAX_UINT32)
+   */
+  Counter64(unsigned long lo);
+
+  /**
+   * Constructs a valid Counter64 with the given values.
+   *
+   * @param hi - value for the high 32 bits (0..MAX_UINT32)
+   * @param lo - value for the low  32 bits (0..MAX_UINT32)
+   */
+  Counter64(unsigned long hi, unsigned long lo);
+
+  /**
+   * Copy constructor.
+   *
+   * @param ctr64 - value
+   */
+  Counter64(const Counter64 &ctr64);
+
+  /**
+   * Destructor (ensure that SnmpSyntax::~SnmpSyntax() is overridden).
+   */
+  ~Counter64() {};
+
+  //-----------[ conversion from/to unsigned long long ]----------------
+
+  /**
+   * Get the value of the object as 64 bit integer.
+   *
+   * @param c64 - The Counter64 object whose value should be returned
+   * @return value as a unsigned 64 bit integer
+   */
+  static pp_uint64 c64_to_ll(const Counter64 &c64);
+
+  /**
+   * Get the value of this object as 64 bit integer.
+   *
+   * @return value as a unsigned 64 bit integer
+   */
+  pp_uint64 c64_to_ll() const;
+
+  /**
+   * Convert a 64 bit integer to a Counter64.
+   *
+   * @param ld - the value to convert
+   * @return A Counter64 object with the value of the param ld.
+   */
+  static Counter64 ll_to_c64(const pp_uint64 &ll);
+
+  //-----------[ get/set using 32 bit variables ]----------------------
+
+  /**
+   * Get the high 32 bit part.
+   *
+   * @return The high part of the Counter64
+   */
+  unsigned long high() const { return smival.value.hNumber.hipart; };
+
+  /**
+   * Get the low 32 bit part.
+   *
+   * @return The low part of the Counter64
+   */
+  unsigned long low() const { return smival.value.hNumber.lopart; };
+
+  /**
+   * Set the high 32 bit part. The low part will stay unchanged.
+   *
+   * @param h - The new high part of the Counter64
+   */
+  void set_high(const unsigned long h)
+    { smival.value.hNumber.hipart = h; m_changed = true; };
+
+  /**
+   * Set the low 32 bit part. The high part will stay unchanged.
+   *
+   * @param l - The new low part of the Counter64
+   */
+  void set_low(const unsigned long l)
+    { smival.value.hNumber.lopart = l; m_changed = true; };
+
+
+  //-----------[ SnmpSyntax methods ]----------------------
+
+  /**
+   * Get a printable ASCII string representing the current value.
+   *
+   * @note The returned string is valid as long as the object is not
+   *       modified.
+   *
+   * @return Null terminated string.
+   */
+  const char *get_printable() const;
+
+  /**
+   * Get the Syntax of the object.
+   *
+   * @return This method always returns sNMP_SYNTAX_CNTR64.
+   */
+  SmiUINT32 get_syntax() const { return sNMP_SYNTAX_CNTR64; };
+
+  /**
+   * Clone the object.
+   *
+   * @return A cloned Counter64 object allocated through new.
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *) new Counter64(*this); };
+
+  /**
+   * Overloaded assignement operator.
+   *
+   * @param val - Try to map the given value to a Counter64 and assign it
+   * @return Always *this with the new value.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  /**
+   * Return validity of the object.
+   *
+   * @return Always true
+   */
+  bool valid() const { return true; };
+
+  /**
+   * Return the space needed for serialization.
+   *
+   * @return The needed space that depends on the current value.
+   */
+  int get_asn1_length() const;
+
+  /**
+   * Reset the object.
+   */
+  void clear()
+    { smival.value.hNumber.hipart = 0; smival.value.hNumber.lopart = 0;
+      m_changed = true; };
+  
+  //-----------[ overloaded operators ]----------------------
+
+  /**
+   * Assign a Counter64 to a Counter64.
+   */
+  Counter64& operator=(const Counter64 &ctr64);
+
+  /**
+   * Assign a unsigned long to a Counter64.
+   *
+   * @param i - The new low part. The high part is cleared.
+   */
+  Counter64& operator=(const unsigned long i);
+
+  /**
+   * Add two Counter64.
+   */
+  Counter64 operator+(const Counter64 &c) const;
+
+  /**
+   * Add a unsigned long and a Counter64.
+   */
+  DLLOPT friend Counter64 operator+(unsigned long ul, const Counter64 &c64)
+    { return Counter64(ul) + c64; };
+
+  /**
+   * Subtract two Counter64.
+   */
+  Counter64 operator-(const Counter64 &c) const;
+
+  /**
+   * Subtract a unsigned long and a Counter64.
+   */
+  DLLOPT friend Counter64 operator-(unsigned long ul, const Counter64 &c64)
+    { return Counter64(ul) - c64; };
+
+  /**
+   * Multiply two Counter64.
+   */
+  Counter64 operator*(const Counter64 &c) const;
+
+  /**
+   * Multiply a unsigned long and a Counter64.
+   */
+  DLLOPT friend Counter64 operator*(unsigned long ul, const Counter64 &c64)
+    { return Counter64(ul) * c64; };
+
+  /**
+   * Divide two Counter64.
+   */
+  Counter64 operator/(const Counter64 &c) const;
+
+  /**
+   * Divide a unsigned long and a Counter64.
+   */
+  DLLOPT friend Counter64 operator/(unsigned long ul, const Counter64 &c64)
+    { return Counter64(ul) / c64; };
+
+  //-------[ overloaded comparison operators ]--------------
+
+  /**
+   * Equal operator for two Cunter64.
+   */
+  DLLOPT friend bool operator==(const Counter64 &lhs, const Counter64 &rhs);
+
+  /**
+   * Not equal operator for two Cunter64.
+   */
+  DLLOPT friend bool operator!=(const Counter64 &lhs, const Counter64 &rhs);
+
+  /**
+   * Less than operator for two Cunter64.
+   */
+  DLLOPT friend bool operator<(const Counter64 &lhs, const Counter64 &rhs);
+
+  /**
+   * Less than or equal operator for two Cunter64.
+   */
+  DLLOPT friend bool operator<=(const Counter64 &lhs, const Counter64 &rhs);
+
+  /**
+   * Greater than operator for two Cunter64.
+   */
+  DLLOPT friend bool operator>(const Counter64 &lhs, const Counter64 &rhs);
+
+  /**
+   * Greater than or equal operator for two Cunter64.
+   */
+  DLLOPT friend bool operator>=(const Counter64 &lhs, const Counter64 &rhs);
+
+ private:
+
+  SNMP_PP_MUTABLE char output_buffer[CTR64OUTBUF];
+  SNMP_PP_MUTABLE bool m_changed;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif
diff --git a/3rdparty/snmp++/include/snmp_pp/eventlist.h b/3rdparty/snmp++/include/snmp_pp/eventlist.h
new file mode 100644 (file)
index 0000000..fecaae5
--- /dev/null
@@ -0,0 +1,201 @@
+/*_############################################################################
+  _## 
+  _##  eventlist.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+      E V E N T L I S T . H
+
+      CEventList  CLASS DEFINITION
+
+      COPYRIGHT HEWLETT PACKARD COMPANY 1999
+
+      INFORMATION NETWORKS DIVISION
+
+      NETWORK MANAGEMENT SECTION
+
+      DESIGN + AUTHOR:         Tom Murray
+
+      DESCRIPTION:
+        Queue for holding all event sources (snmp messages, user
+        defined input sources, user defined timeouts, etc)
+=====================================================================*/
+// $Id: eventlist.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _EVENTLIST
+#define _EVENTLIST
+
+//----[ includes ]-----------------------------------------------------
+#include <limits.h>
+#include <sys/types.h> // NOTE: due to 10.10 bug, order is important
+                       //   in that all routines must include types.h
+                       //   and time.h in same order otherwise you
+                       //   will get conflicting definitions of
+                       //   "fd_set" resulting in link time errors.
+#ifdef WIN32
+#include <time.h>
+#else
+#if !(defined CPU && CPU == PPC603)
+#include <sys/time.h>  // time stuff and fd_set
+#endif
+#include <float.h>
+#endif
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/reentrant.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define MAX_UINT32 MAXLONG
+
+class msec;
+class Pdu;
+
+//----[ CEvents class ]------------------------------------------------
+class DLLOPT CEvents: public SnmpSynchronized {
+  public:
+
+  // allow destruction of derived classes
+  virtual ~CEvents() {};
+
+  // find the next timeout
+  virtual int GetNextTimeout(msec &sendTime) = 0;
+
+  // set up parameters for select/poll
+#ifdef HAVE_POLL_SYSCALL
+  virtual int GetFdCount() = 0;
+  virtual bool GetFdArray(struct pollfd *readfds, int &remaining) = 0;
+  virtual int HandleEvents(const struct pollfd *readfds, const int fds) = 0;
+#else
+  virtual void GetFdSets(int &maxfds, fd_set &readfds, fd_set &writefds,
+                          fd_set &exceptfds) = 0;
+  // process events pending on the active file descriptors
+  virtual int HandleEvents(const int maxfds,
+                          const fd_set &readfds,
+                          const fd_set &writefds,
+                          const fd_set &exceptfds) = 0;
+#endif
+  // return number of outstanding messages
+  virtual int GetCount() = 0;
+
+  // process any timeout events
+  virtual int DoRetries(const msec &sendtime) = 0;
+
+  // check to see if there is a termination condition
+  virtual int Done() = 0;
+};
+
+
+class DLLOPT CEventList: public SnmpSynchronized {
+  public:
+    CEventList() : m_head(0, 0, 0), m_msgCount(0), m_done(0) {};
+    ~CEventList();
+
+  // add an event source to the list
+  CEvents *AddEntry(CEvents *events);
+
+  // tell main_loop to exit after one pass
+  void SetDone() REENTRANT({ m_done += 1; });
+
+  // see if main loop should terminate
+  int GetDone()  { return m_done; };
+
+  // find the time of the next event that will timeout
+  int GetNextTimeout(msec &sendTime);
+
+#ifdef HAVE_POLL_SYSCALL
+  int GetFdCount();
+  bool GetFdArray(struct pollfd *readfds, int &remaining);
+  int HandleEvents(const struct pollfd *readfds, const int fds);
+#else
+ // set up paramters for select
+  void GetFdSets(int &maxfds, fd_set &readfds, fd_set &writefds,
+                fd_set &exceptfds);
+
+  // process events pending on the active file descriptors
+  int HandleEvents(const int maxfds,
+                  const fd_set &readfds,
+                  const fd_set &writefds,
+                  const fd_set &exceptfds);
+#endif
+
+  // return number of outstanding messages
+  int GetCount() { return m_msgCount; };
+
+
+  // process any timeout events
+  int DoRetries(const msec &sendtime);
+
+  // check to see if there is a termination condition
+  int Done();
+
+  private:
+
+   class DLLOPT CEventListElt
+   {
+    public:
+     CEventListElt(CEvents *events,
+                  CEventListElt *next,
+                  CEventListElt *previous);
+
+     ~CEventListElt();
+     CEventListElt *GetNext() { return m_Next; }
+     CEvents *GetEvents() { return m_events; }
+
+    private:
+
+     CEvents *m_events;
+     class CEventListElt *m_Next;
+     class CEventListElt *m_previous;
+   };
+
+    CEventListElt m_head;
+    int m_msgCount;
+    int m_done;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif
diff --git a/3rdparty/snmp++/include/snmp_pp/eventlistholder.h b/3rdparty/snmp++/include/snmp_pp/eventlistholder.h
new file mode 100644 (file)
index 0000000..f007573
--- /dev/null
@@ -0,0 +1,118 @@
+/*_############################################################################
+  _## 
+  _##  eventlistholder.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+#ifndef _EVENTLISTHOLDER_H_
+#define _EVENTLISTHOLDER_H_
+
+//----[ includes ]-----------------------------------------------------
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/snmperrs.h"
+#include "snmp_pp/eventlist.h"
+#include "snmp_pp/reentrant.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class CSNMPMessageQueue;
+class CNotifyEventQueue;
+class Pdu;
+class v3MP;
+class Snmp;
+
+typedef unsigned long Uint32;
+
+class DLLOPT EventListHolder
+{
+ public:
+  EventListHolder(Snmp *snmp_session);
+  ~EventListHolder() {};
+
+  CSNMPMessageQueue *&snmpEventList()   { return m_snmpMessageQueue; };
+  CNotifyEventQueue *&notifyEventList() { return m_notifyEventQueue; };
+
+  Uint32 SNMPGetNextTimeout();
+
+#ifdef HAVE_POLL_SYSCALL
+  int GetFdCount();
+  bool GetFdArray(struct pollfd *readfds, int &remaining);
+#endif
+  void SNMPGetFdSets(int &  maxfds,
+                    fd_set & readfds,
+                    fd_set & writefds,
+                    fd_set & exceptfds);
+
+  //---------[ Main Loop ]------------------------------------------
+  /**
+   * Infinite loop which blocks when there is nothing to do and handles
+   * any events.
+   *
+   * @note If no messages are outstanding, select() is called with the
+   *       given timeout, so any async messages that are sent out later
+   *       are not processed until this select call returns.
+   */
+  void SNMPMainLoop(const int max_block_milliseconds = 0 /* = infinite */);
+
+  //---------[ Exit Main Loop ]---------------------------------------
+  // Force the SNMP Main Loop to terminate immediately
+  void SNMPExitMainLoop();
+
+  /**
+   * Block until an event shows up - then handle the event(s).
+   *
+   * @note If no messages are outstanding, select() is called with the
+   *       given timeout, so any async messages that are sent out later
+   *       are not processed until this select call returns.
+   */
+  int SNMPProcessEvents(const int max_block_milliseconds = 0 /* = infinite */);
+
+  //---------[ Process Pending Events ]-------------------------------
+  // Pull all available events out of their sockets - do not block
+  int SNMPProcessPendingEvents();
+
+  //---------[ Block For Response ]-----------------------------------
+  // Wait for the completion of an outstanding SNMP event (msg).
+  // Handle any other events as they occur.
+  int SNMPBlockForResponse(const unsigned long req_id,
+                          Pdu &    pdu);
+
+ private:
+
+  CSNMPMessageQueue *m_snmpMessageQueue;  // contains all outstanding messages
+  CNotifyEventQueue *m_notifyEventQueue; // contains all sessions waiting for notifications
+  CEventList   m_eventList;  // contains all expected events
+
+  SnmpSynchronized      pevents_mutex;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // _EVENTLISTHOLDER_H_
diff --git a/3rdparty/snmp++/include/snmp_pp/gauge.h b/3rdparty/snmp++/include/snmp_pp/gauge.h
new file mode 100644 (file)
index 0000000..313c5a0
--- /dev/null
@@ -0,0 +1,150 @@
+/*_############################################################################
+  _## 
+  _##  gauge.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++ G A U G E. H
+
+  GAUGE32 CLASS DEFINITION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  Class definition for SMI Gauge32 class.
+=====================================================================*/
+// $Id: gauge.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _GAUGE_H_
+#define _GAUGE_H_
+
+#include "snmp_pp/integer.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//------------[ Gauge32 Class ]------------------------------------------
+/**
+ * The gauge class allows all the functionality of unsigned integers
+ * but is recognized as a distinct SMI type. Gauge32 objects may be
+ * set or get into Vb objects.
+ */
+class DLLOPT Gauge32: public SnmpUInt32
+{
+ public:
+
+  //-----------[ Constructors and Destrucotr ]----------------------
+
+  /**
+   * Constructs a valid Gauge32 with value 0.
+   */
+  Gauge32() : SnmpUInt32() { smival.syntax = sNMP_SYNTAX_GAUGE32; };
+
+  /**
+   * Constructs a valid Gauge32 with the given value.
+   *
+   * @param ul - value (0..MAX_UINT32)
+   */
+  Gauge32(const unsigned long ul) : SnmpUInt32(ul)
+    { smival.syntax = sNMP_SYNTAX_GAUGE32; };
+
+  /**
+   * Copy constructor.
+   *
+   * @param g32 - value
+   */
+  Gauge32(const Gauge32 &g32);
+
+  /**
+   * Destructor (ensure that SnmpUInt32::~SnmpUInt32() is overridden).
+   */
+  ~Gauge32() {};
+
+  //-----------[ SnmpSyntax methods ]----------------------
+
+  /**
+   * Get the Syntax of the object.
+   *
+   * @return This method always returns sNMP_SYNTAX_GAUGE32.
+   */
+  SmiUINT32 get_syntax() const { return sNMP_SYNTAX_GAUGE32; };
+
+  /**
+   * Clone the object.
+   *
+   * @return A cloned Gauge32 object allocated through new.
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *) new Gauge32(*this); };
+
+  //-----------[ Overload some operators ]----------------------
+
+  /**
+   * Assign a Gauge32 to a Gauge32.
+   */
+  Gauge32& operator=(const Gauge32 &uli)
+    { smival.value.uNumber = uli.smival.value.uNumber;
+      m_changed = true;  return *this;};
+
+  /**
+   * Assign a unsigned long to a Gauge32.
+   *
+   * @param ul - New value
+   */
+  Gauge32& operator=(const unsigned long ul)
+    { smival.value.uNumber = ul; m_changed = true; return *this; };
+
+  // otherwise, behave like an unsigned int
+  /**
+   * Cast a Gauge32 to unsigned long.
+   *
+   * @return Current value as unsigned long.
+   */
+  operator unsigned long() { return smival.value.uNumber; };
+
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // _GAUGE_H_
diff --git a/3rdparty/snmp++/include/snmp_pp/idea.h b/3rdparty/snmp++/include/snmp_pp/idea.h
new file mode 100644 (file)
index 0000000..f0c9df6
--- /dev/null
@@ -0,0 +1,169 @@
+/*_############################################################################
+  _## 
+  _##  idea.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+// $Id: idea.h 1791 2010-07-26 19:41:54Z katz $
+
+/*
+
+idea.h
+
+Author: Tatu Ylonen <ylo@cs.hut.fi>
+
+Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+                   All rights reserved
+
+Created: Sun Jun 25 04:44:30 1995 ylo
+
+The IDEA encryption algorithm.
+
+*/
+
+#ifndef IDEA_H
+#define IDEA_H
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifdef _USE_IDEA
+
+typedef unsigned short word16;
+typedef unsigned int word32;
+
+typedef struct
+{
+  word16 key_schedule[52];
+} IDEAContext;
+
+/* Sets idea key for encryption. */
+void idea_set_key(IDEAContext *c, const unsigned char key[16]);
+
+/* Destroys any sensitive data in the context. */
+void idea_destroy_context(IDEAContext *c);
+
+/* Performs the IDEA cipher transform on a block of data. */
+void idea_transform(IDEAContext *c, word32 l, word32 r, word32 *output);
+
+/* Encrypts len bytes from src to dest in CFB mode.  Len need not be a multiple
+   of 8; if it is not, iv at return will contain garbage.
+   Otherwise, iv will be modified at end to a value suitable for continuing
+   encryption. */
+void idea_cfb_encrypt(IDEAContext *c, unsigned char *iv, unsigned char *dest,
+                     const unsigned char *src, unsigned int len);
+
+
+/* Decrypts len bytes from src to dest in CFB mode.  Len need not be a multiple
+   of 8; if it is not, iv at return will contain garbage.
+   Otherwise, iv will be modified at end to a value suitable for continuing
+   decryption. */
+void idea_cfb_decrypt(IDEAContext *c, unsigned char *iv, unsigned char *dest,
+                     const unsigned char *src, unsigned int len);
+
+#endif /* IDEA_H */
+#endif /* _USE_IDEA */
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+/*
+
+getput.h
+
+Author: Tatu Ylonen <ylo@cs.hut.fi>
+
+Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+                   All rights reserved
+
+Created: Wed Jun 28 22:36:30 1995 ylo
+
+Macros for storing and retrieving data in msb first and lsb first order.
+
+*/
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifndef GETPUT_H
+#define GETPUT_H
+
+#ifdef _USE_IDEA
+
+/*------------ macros for storing/extracting msb first words -------------*/
+
+#define GET_32BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 24) | \
+                      ((unsigned long)(unsigned char)(cp)[1] << 16) | \
+                      ((unsigned long)(unsigned char)(cp)[2] << 8) | \
+                      ((unsigned long)(unsigned char)(cp)[3]))
+
+#define GET_16BIT(cp) (((unsigned long)(unsigned char)(cp)[0] << 8) | \
+                      ((unsigned long)(unsigned char)(cp)[1]))
+
+#define PUT_32BIT(cp, value) do { \
+  (cp)[0] = (value) >> 24; \
+  (cp)[1] = (value) >> 16; \
+  (cp)[2] = (value) >> 8; \
+  (cp)[3] = (value); } while (0)
+
+#define PUT_16BIT(cp, value) do { \
+  (cp)[0] = (value) >> 8; \
+  (cp)[1] = (value); } while (0)
+
+/*------------ macros for storing/extracting lsb first words -------------*/
+
+#define GET_32BIT_LSB_FIRST(cp) \
+  (((unsigned long)(unsigned char)(cp)[0]) | \
+  ((unsigned long)(unsigned char)(cp)[1] << 8) | \
+  ((unsigned long)(unsigned char)(cp)[2] << 16) | \
+  ((unsigned long)(unsigned char)(cp)[3] << 24))
+
+#define GET_16BIT_LSB_FIRST(cp) \
+  (((unsigned long)(unsigned char)(cp)[0]) | \
+  ((unsigned long)(unsigned char)(cp)[1] << 8))
+
+#define PUT_32BIT_LSB_FIRST(cp, value) do { \
+  (cp)[0] = (value); \
+  (cp)[1] = (value) >> 8; \
+  (cp)[2] = (value) >> 16; \
+  (cp)[3] = (value) >> 24; } while (0)
+
+#define PUT_16BIT_LSB_FIRST(cp, value) do { \
+  (cp)[0] = (value); \
+  (cp)[1] = (value) >> 8; } while (0)
+
+#endif // _USE_IDEA
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif /* GETPUT_H */
+
diff --git a/3rdparty/snmp++/include/snmp_pp/integer.h b/3rdparty/snmp++/include/snmp_pp/integer.h
new file mode 100644 (file)
index 0000000..e6e6de5
--- /dev/null
@@ -0,0 +1,286 @@
+/*_############################################################################
+  _## 
+  _##  integer.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+               
+  SNMP++ I N T E G E R. H
+
+  INTEGER CLASS DEFINITION
+
+  DESIGN + AUTHOR:  Jeff Meyer
+
+  DESCRIPTION:
+  Class definition for Integer classes.
+
+=====================================================================*/
+// $Id: integer.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _SNMPINTEGER
+#define _SNMPINTEGER
+
+#include "snmp_pp/smival.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define INTOUTBUF 15  // largest ASCII formatted integer
+
+//------------[ Integer Classes ]------------------------------------------
+
+/**
+ * 32 bit unsigned integer class.
+ *
+ * The integer class allows all the functionality of the various
+ * integers but is contained in a Value object for consistency
+ * among the various types.
+ * class objects may be set or get into Vb objects.
+ */
+class DLLOPT SnmpUInt32 : public SnmpSyntax
+{
+ public:
+
+  /**
+   * Constructor, sets value to zero.
+   */
+  SnmpUInt32();
+
+  /**
+   * Constructor with value.
+   *
+   * @param i - initial value
+   */
+  SnmpUInt32(const unsigned long i);
+
+  /**
+   * Copy constructor.
+   *
+   * @param c - initial value
+   */
+  SnmpUInt32(const SnmpUInt32 &c);
+
+  /**
+   * Destructor (ensure that SnmpSyntax::~SnmpSyntax() is overridden).
+   */
+  virtual ~SnmpUInt32() {};
+
+  /**
+   * Return the syntax.
+   *
+   * @return This method always returns sNMP_SYNTAX_UINT32.
+   */
+  virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_UINT32; };
+
+  /**
+   * Overloaded assignment for unsigned longs.
+   *
+   * @param i - new value
+   * @return self reference
+   */
+  SnmpUInt32& operator=(const unsigned long i);
+
+  /**
+   * Overloaded assignment for SnmpUInt32.
+   *
+   * @param uli - new value
+   * @return self reference
+   */
+  SnmpUInt32& operator=(const SnmpUInt32 &uli);
+
+  /**
+   * Map other SnmpSyntax objects to SnmpUInt32.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  /**
+   * Behave like an unsigned long.
+   *
+   * @return value as unsigned long
+   */
+  operator unsigned long() const { return smival.value.uNumber; };
+
+  /**
+   * Get a printable ASCII value.
+   */
+  virtual const char *get_printable() const;
+
+  /**
+   * Clone operator.
+   *
+   * @return Pointer to a newly created copy of the object.
+   */
+  virtual SnmpSyntax *clone() const
+    { return (SnmpSyntax *)new SnmpUInt32(*this); };
+
+  /**
+   * Return validity of the object.
+   * An SnmpUInt32 will only be invalid after a failed asignment
+   * of another SnmpSyntax object.
+   */
+  bool valid() const { return valid_flag; };
+
+  /**
+   * Return the space needed for serialization.
+   */
+  int get_asn1_length() const;
+
+  /**
+   * Reset the object.
+   */
+  void clear()
+    { smival.value.uNumber = 0; valid_flag = true; m_changed = true; };
+
+ protected:
+  bool valid_flag;
+  SNMP_PP_MUTABLE char output_buffer[INTOUTBUF];
+  SNMP_PP_MUTABLE bool m_changed;
+};
+
+
+/**
+ * 32 bit signed integer class.
+ */
+class DLLOPT SnmpInt32 : public SnmpSyntax
+{
+ public:
+
+  /**
+   * Constructor, sets value to zero.
+   */
+  SnmpInt32();
+
+  /**
+   * Constructor with value.
+   *
+   * @param i - initial value
+   */
+  SnmpInt32 (const long i);
+
+  /**
+   * Copy constructor.
+   *
+   * @param c - initial value
+   */
+  SnmpInt32 (const SnmpInt32 &c);
+
+  /**
+   * Destructor (ensure that SnmpSyntax::~SnmpSyntax() is overridden).
+   */
+  virtual ~SnmpInt32() {};
+
+  /**
+   * Return the syntax.
+   *
+   * @return This method always returns sNMP_SYNTAX_INT32.
+   */
+  virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_INT32; };
+
+  /**
+   * Overloaded assignment for longs.
+   *
+   * @param i - new value
+   * @return self reference
+   */
+  SnmpInt32& operator=(const long i);
+
+  /**
+   * Overloaded assignment for SnmpInt32.
+   *
+   * @param li - new value
+   * @return self reference
+   */
+  SnmpInt32& operator=(const SnmpInt32 &li);
+
+  /**
+   * Map other SnmpSyntax objects to SnmpInt32.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  /**
+   * Behave like an long.
+   *
+   * @return value as long
+   */
+  operator long() const { return (long) smival.value.sNumber; };
+
+  /**
+   * Get a printable ASCII value.
+   */
+  const char *get_printable() const;
+
+  /**
+   * Clone operator.
+   *
+   * @return Pointer to a newly created copy of the object.
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *)new SnmpInt32(*this); };
+
+  /**
+   * Return validity of the object.
+   * An SnmpUInt32 will only be invalid after a failed asignment
+   * of another SnmpSyntax object.
+   */
+  bool valid() const { return valid_flag; };
+
+  /**
+   * Return the space needed for serialization.
+   */
+  int get_asn1_length() const;
+
+  /**
+   * Reset the object.
+   */
+  void clear()
+    { smival.value.sNumber = 0; valid_flag = true; m_changed = true; };
+
+ protected:
+  bool valid_flag;
+  SNMP_PP_MUTABLE char output_buffer[INTOUTBUF];
+  SNMP_PP_MUTABLE bool m_changed;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif
diff --git a/3rdparty/snmp++/include/snmp_pp/log.h b/3rdparty/snmp++/include/snmp_pp/log.h
new file mode 100644 (file)
index 0000000..121df01
--- /dev/null
@@ -0,0 +1,560 @@
+/*_############################################################################
+  _## 
+  _##  log.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+
+
+#ifndef _log_h_
+#define _log_h_
+
+#include <snmp_pp/config_snmp_pp.h>
+#include <snmp_pp/reentrant.h>
+
+#ifndef WIN32
+#include <sys/types.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// Log entry class
+#define ERROR_LOG      0x10
+#define WARNING_LOG    0x20
+#define EVENT_LOG      0x30
+#define INFO_LOG       0x40
+#define DEBUG_LOG      0x50
+#define USER_LOG       0x60
+
+#define LOG_TYPES       6
+
+#ifdef _NO_LOGGING
+#define LOG_BEGIN(x)   
+#define LOG(x)         
+#define LOG_END                
+
+#define LOG_UNUSED(x)
+
+#else
+
+#define LOG_BEGIN(x)                                           \
+{                                                              \
+       if (DefaultLog::log()->log_needed(x))                   \
+       {                                                       \
+               DefaultLog::log()->lock();                      \
+               DefaultLog::create_log_entry(x);        
+
+#define LOG(x)         *DefaultLog::log_entry() += x
+
+#define LOG_END                                                        \
+               *DefaultLog::log() += DefaultLog::log_entry();  \
+               DefaultLog::delete_log_entry();                 \
+               DefaultLog::log()->unlock();                    \
+       }                                                       \
+}
+
+#define LOG_UNUSED(x) x
+
+#endif
+
+
+/*--------------------------- class LogEntry --------------------------*/
+
+/**
+ * The LogEntry class represents log entries. An instance of LogEntry can be
+ * added to a Log. Each LogEntry can be classified into the log classes
+ * ERROR_LOG, WARNING_LOG, EVENT_LOG, INFO_LOG, DEBUG_LOG and USER_LOG with up
+ * to 16 severity levels. A log entry consists of a descriptor string and
+ * optional several string or numeric values.
+ *
+ * The log class USER_LOG can be used for applications, it is not used
+ * within snmp++ and agent++.
+ *
+ * @note A error log of level 0 will stop program execution!
+ *
+ * @see Log
+ * 
+ * @author Frank Fock
+ * @author Marty Janzen
+ * @version 3.5f
+ */
+
+class DLLOPT LogEntry {
+public:
+       /**
+        * Constructor with log class and severity level
+        * 
+        * @param t - The type of the log entry. The type is composed 
+        *            by a logical OR of the log entry class with a level
+        *            of 0 up to 15. 
+        * @note A error log of level 0 will stop program execution!
+        */  
+       LogEntry(unsigned char t) : type(t), count(0) {}
+
+       /**
+        * Virtual destructor.
+        */  
+       virtual ~LogEntry() {}
+
+       /**
+        * Initialize a new log entry, showing timestamp, class, and level.
+        */ 
+       virtual void init(void);
+
+       /**
+        * Add a numeric value to the log entry.
+        *
+        * @param l - A numeric value.
+        */
+       virtual LogEntry& operator+=(const long);
+
+       /**
+        * Add a string value to the log entry.
+        *
+        * @param l - A numeric value.
+        */
+       virtual LogEntry& operator+=(const char*);
+
+       /**
+        * Get the contents of this log entry.
+         *
+        * @return Current contents of this log entry.
+        */ 
+       virtual const char* get_value(void) const { return ""; }
+
+       /**
+        * Get the class of this log entry.
+         *
+        * @return Log entry class.
+        */ 
+       unsigned char get_class(void) const { return type & 0xF0; }
+
+       /**
+        * Get the level of this log entry.
+         *
+        * @return Log entry level.
+        */ 
+       unsigned char get_level(void) const { return type & 0x0F; }
+
+protected:
+       /**
+        * Add a string to the log.
+        *
+        * @param s - A string value.
+        * @return TRUE if the value has been added and FALSE if the log
+        *         entry is full.
+        */
+       virtual bool    add_string(const char*) = 0;
+
+       /**
+        * Add an integer to the log.
+        *
+        * @param s - An integer value.
+        * @return TRUE if the value has been added and FALSE if the log
+        *         entry is full.
+        */
+       virtual bool    add_integer(long);
+
+       /**
+        * Add the current time to the log.
+        */
+       virtual bool add_timestamp(void);
+
+protected:
+       unsigned char   type;
+       int             count;
+};
+
+
+/*------------------------- class LogEntryImpl ------------------------*/
+
+#define MAX_LOG_SIZE   2550 // increased until debugprintf is not used!
+
+/**
+ * The LogEntryImpl class implements a log entry using a dynamically
+ * allocated, but fixed-size buffer.
+ * @see Log
+ * 
+ * @author Marty Janzen
+ * @version 3.5f
+ */
+
+class DLLOPT LogEntryImpl : public LogEntry {
+public:
+       /**
+        * Constructor with log class and severity level
+        * 
+        * @param t - The type of the log entry. The type is composed 
+        *            by logical or the log entry class with a level
+        *            of 0 up to 15. 
+        * @note A error log of level 0 will stop program execution!
+        */  
+       LogEntryImpl(unsigned char);
+
+       /**
+        * Destructor.
+        */  
+       ~LogEntryImpl();
+
+       /**
+        * Get the contents of this log entry.
+         *
+        * @return Current contents of this log entry.
+        */ 
+       virtual const char* get_value(void) const { return value; }
+
+protected:
+       /**
+        * Count the bytes left for additional values.
+        *
+        * @return The number of bytes left in this log entry.
+        */  
+       unsigned int            bytes_left() 
+           { return (unsigned int)(MAX_LOG_SIZE-(ptr-value)-1); }
+
+       /**
+        * Add a string to the log.
+        *
+        * @param s - A string value.
+        * @return TRUE if the value has been added and FALSE if the log
+        *         entry is full.
+        */
+       bool            add_string(const char*);
+
+private:
+        char*          value;
+       char*           ptr;
+       bool            output_stopped;
+};
+
+
+/*--------------------------- class AgentLog --------------------------*/
+
+/**
+ * The AgentLog class is an abstract base class representing a log for
+ * information that is generated during the run time of an AGENT++
+ * SNMP agent.  A derived class only needs to provide appropriate
+ * create_log_entry() and operator+= methods.
+ * @see LogEntry
+ *
+ * @author Frank Fock
+ * @version 3.5.14
+ */
+class DLLOPT AgentLog {
+public:
+       /**
+        * Default constructor.
+        */ 
+       AgentLog();
+
+       /**
+        * Virtual destructor.
+        */
+       virtual ~AgentLog() {}
+
+       /**
+        * Lock the receiver.  Default action is to perform no locking.
+        */
+       virtual void    lock() {}
+
+       /**
+        * Unlock the receiver.  Default action is to perform no locking.
+        */
+       virtual void    unlock() {}
+
+       /**
+        * Set a filter on a specified log class. Only log entries with
+        * a level less or equal than the specified level will be logged.
+        *
+        * @param logclass - A log entry class. @see LogEntry
+        * @param filter - A value between 0 and 15.
+        */ 
+       virtual void    set_filter(int logclass, unsigned char filter);
+
+       /**
+        * Gets the log level for the given log class.
+        * @return
+        *    a unsigned char value between 0 and 15 
+        */
+       virtual unsigned char get_filter(int logclass) const; 
+
+       /**
+        * Create a new LogEntry.
+        *
+        * @param t - The type of the log entry.
+        * @return A new instance of LogEntry (or of a derived class).
+        */
+       virtual LogEntry* create_log_entry(unsigned char) const = 0;
+
+       /**
+        * Add a LogEntry to the receiver Log.
+        *
+        * @param log - A log entry.
+        * @return The receiver log itself.
+        */
+       virtual AgentLog& operator+=(const LogEntry*) = 0;
+
+       /**
+        * Check whether a logging for the given type of LogEntry
+        * has to be done or not.
+        *
+        * @param type
+        *    the type of the log entry. The type is composed 
+        *    by logical or the log entry class with a level
+        *    of 0 up to 15.
+        * @return
+        *    TRUE if logging is needed, FALSE otherwise.
+        */
+       virtual bool    log_needed(unsigned char t) 
+         { return ((t & 0x0F) <= logfilter[(t / 16) - 1]); }
+
+       /**
+        * Return the current time as a string.
+        * 
+        * @param
+        *    a buffer (of at least 18 characters, for the default method)
+         *    into which to place a string containg the current time.
+         *    If no buffer is supplied, a static area is used.
+        * @return
+        *    a string containing the current time. Either the supplied
+        *    buffer or the static area.
+        */
+       virtual const char*     now(char* = 0);
+
+       /**
+        * Return the current time as a string, using the current
+         * default log object.  (For backward compatibility.)
+        * @note that the user is responsible for deleting the returned
+        * string, using delete [].
+        * 
+        * @return
+        *    a string containg the current time.
+        */
+       static const char*      get_current_time();
+
+protected:
+       unsigned char           logfilter[LOG_TYPES];
+       char                    static_buf[18];
+};
+
+
+/*------------------------- class AgentLogImpl ------------------------*/
+
+/**
+ * The AgentLogImpl class is an implementation of AgentLog which writes
+ * log messages to a file, or to stdout or stderr.
+ * @see LogEntry 
+ *
+ * @author Frank Fock
+ * @version 3.5f
+ */
+class DLLOPT AgentLogImpl : public AgentLog {
+public:
+       /**
+        * Default constructor, with optional pointer to an open log file.
+         * Log is directed to the file if given, otherwise to stdout
+        *
+        * @param fp - An open log file.  0 implies stdout.
+        */ 
+       AgentLogImpl(FILE* = stdout);
+
+       /**
+        * Constructor with file name of a log file. Log is directed
+        * to the given file.
+        *
+        * @param fname - The file name of a log file.
+        */ 
+       AgentLogImpl(const char*);
+
+       /**
+        * Destructor.
+        */
+       ~AgentLogImpl();
+
+       /**
+        * Set destination of logs to a given file.
+        * 
+        * @param fname - A file name. "" directs logs to stdout.
+        */
+       void            set_dest(const char*);
+
+       /**
+        * Set destination of logs to a given file.
+        * 
+        * @param fp - A pointer to an open file.  0 directs logs to stdout.
+        */
+       void            set_dest(FILE*);
+
+       /**
+        * Lock the receiver.
+        */
+       void lock()
+       {
+#ifdef _THREADS
+               logLock.lock();
+#endif
+       }
+
+       /**
+        * Unlock the receiver.
+        */
+        void unlock()
+       {
+#ifdef _THREADS
+               logLock.unlock();
+#endif
+       }
+
+       /**
+        * Create a new LogEntry.
+        *
+        * @param t - The type of the log entry.
+        * @return A new instance of LogEntry (or of a derived class).
+        */
+       virtual LogEntry* create_log_entry(unsigned char) const;
+
+       /**
+        * Add a LogEntry to the receiver Log.
+        *
+        * @param log - A log entry.
+        * @return The receiver log itself.
+        */
+       virtual AgentLog& operator+=(const LogEntry*);
+
+protected:
+       SnmpSynchronized        logLock;
+       FILE*                   logfile;
+       bool                    close_needed;
+};
+
+
+/*--------------------------- class DefaultLog --------------------------*/
+
+/**
+ * The DefaultLog class has a static Log member, that is used by the
+ * AGENT++ API for logging.
+ *
+ * @version 3.5.24
+ * @author Frank Fock (singleton pattern -> Philippe Roger)
+ */  
+
+class DLLOPT DefaultLog {
+public:
+       DefaultLog() { }
+       ~DefaultLog() { }
+
+       /**
+        * Initialize the default logger with the given logging implementation.
+        *
+        * @note Call cleanup function before the application exits
+        * @note The DefaultLog class takes ownership of the pointer. Do
+        *       not delete it yourself.
+        * @note This method is NOT THREADSAFE. It must be called in main()
+        *       before any logging takes place.
+        * 
+        * @param logger
+        *    an AgentLog instance to be used as default logger. A previously
+        *    set logger will be deleted.
+        */
+       static void init(AgentLog* logger) 
+         { if (instance) delete instance; instance = logger; }
+
+       /**
+        * Initialize the default logger with the given logging implementation
+        * if there is currently no logger instance set.
+        *
+        * @note Call cleanup function before the application exits
+        * @note The DefaultLog class takes ownership of the pointer. Do
+        *       not delete it yourself.
+        * @note This method is THREADSAFE. 
+        * 
+        * @param logger
+        *    an AgentLog instance to be used as default logger.
+        * @return
+        *    the existing logger (if there was any) or the new logger pointer.
+        * @since 3.5.24
+        */
+       static AgentLog* init_ts(AgentLog* logger);
+
+       /**
+        * Free the logging implementation.
+        * @note This method is THREADSAFE. 
+        */
+       static void cleanup();
+
+       /**
+        * Return the default logger. 
+        *
+        * @return
+        *    a pointer to an AgentLog instance.
+        */
+       static AgentLog* log(); 
+
+       /**
+        * Create a new log entry or reuse an existing one.
+        *
+        * @param type
+        *    the type of the log entry as bitwise or of log class and level. 
+        */
+       static void create_log_entry(unsigned char t)
+         { if (!entry) { entry = log()->create_log_entry(t); entry->init();} }
+
+       /**
+        * Return the current log entry. If there is none, an ERROR_LOG entry
+        * with level 1 will be created.
+        *
+        * @return
+        *    a pointer to a LogEntry instance.
+        */
+       static LogEntry* log_entry() 
+         { if (!entry) create_log_entry(ERROR_LOG | 1); return entry; } 
+
+       /**
+        * Delete current log entry.
+        */
+       static void delete_log_entry() 
+         { if (entry) delete entry; entry = 0; }
+
+protected:
+
+       static AgentLog* instance;
+       static LogEntry* entry;
+       static SnmpSynchronized mutex;
+};
+
+
+#ifdef SNMP_PP_NAMESPACE
+}
+#endif
+#endif // _log_h_
diff --git a/3rdparty/snmp++/include/snmp_pp/md5.h b/3rdparty/snmp++/include/snmp_pp/md5.h
new file mode 100644 (file)
index 0000000..67db51f
--- /dev/null
@@ -0,0 +1,128 @@
+/*_############################################################################
+  _## 
+  _##  md5.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
+/* MD5.H - header file for MD5C.C */
+
+/* Copyright (C) 1991, RSA Data Security, Inc. All rights reserved.
+
+   License to copy and use this software is granted provided that it
+   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+   Algorithm" in all material mentioning or referencing this software
+   or this function.
+
+   License is also granted to make and use derivative works provided
+   that such works are identified as "derived from the RSA Data
+   Security, Inc. MD5 Message-Digest Algorithm" in all material
+   mentioning or referencing the derived work.
+
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.
+
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.
+ */
+// $Id: md5.h 288 2007-03-22 22:37:09Z katz $
+
+#ifndef _MD5_H_
+#define _MD5_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned int UINT4; /* for alpha */
+/*typedef unsigned long int UINT4; */
+
+/* BYTE defines a unsigned character */
+typedef unsigned char BYTE;
+
+/* internal signed value */
+typedef signed int signeddigit;
+
+#ifndef NULL_PTR
+#define NULL_PTR ((POINTER)0)
+#endif
+
+#ifndef UNUSED_ARG
+#define UNUSED_ARG(x) x = *(&x);
+#endif
+
+#ifndef PROTOTYPES
+#define PROTOTYPES
+#endif
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+        If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+        returns an empty list. */
+
+#ifdef PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+/* MD5 context. */
+typedef struct {
+  UINT4 state[4];                                           /* state (ABCD) */
+  UINT4 count[2];                /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                                 /* input buffer */
+} MD5_CTX;
+
+DLLOPT void  MD5Init PROTO_LIST ((MD5_CTX *));
+DLLOPT void  MD5Update PROTO_LIST ((MD5_CTX *, const unsigned char *, const unsigned int));
+DLLOPT void  MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
diff --git a/3rdparty/snmp++/include/snmp_pp/mp_v3.h b/3rdparty/snmp++/include/snmp_pp/mp_v3.h
new file mode 100644 (file)
index 0000000..b133db5
--- /dev/null
@@ -0,0 +1,650 @@
+/*_############################################################################
+  _## 
+  _##  mp_v3.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+// $Id: mp_v3.h 320 2007-11-08 22:05:23Z katz $
+
+#ifndef _MP_V3
+#define _MP_V3
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+
+#include "snmp_pp/reentrant.h"
+#include "snmp_pp/target.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class Pdu;
+class OctetStr;
+
+#define MAX_HOST_NAME_LENGTH     128
+
+#define oidMPDGroup                  "1.3.6.1.6.3.11.2.1"
+#define oidSnmpUnknownSecurityModels "1.3.6.1.6.3.11.2.1.1.0"
+#define oidSnmpInvalidMsgs           "1.3.6.1.6.3.11.2.1.2.0"
+#define oidSnmpUnknownPDUHandlers    "1.3.6.1.6.3.11.2.1.3.0"
+
+/** @name Error codes of the v3MP */
+//@{
+#define SNMPv3_MP_ERROR                       -1400
+#define SNMPv3_MP_OK                          -1401
+#define SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL  -1402
+#define SNMPv3_MP_NOT_IN_TIME_WINDOW          -1403
+#define SNMPv3_MP_DOUBLED_MESSAGE             -1404
+#define SNMPv3_MP_INVALID_MESSAGE             -1405
+#define SNMPv3_MP_INVALID_ENGINEID            -1406
+#define SNMPv3_MP_NOT_INITIALIZED             -1407
+#define SNMPv3_MP_PARSE_ERROR                 -1408
+#define SNMPv3_MP_UNKNOWN_MSGID               -1409
+#define SNMPv3_MP_MATCH_ERROR                 -1410
+#define SNMPv3_MP_COMMUNITY_ERROR             -1411
+#define SNMPv3_MP_WRONG_USER_NAME             -1412
+#define SNMPv3_MP_BUILD_ERROR                 -1413
+#define SNMPv3_MP_USM_ERROR                   -1414
+#define SNMPv3_MP_UNKNOWN_PDU_HANDLERS        -1415
+#define SNMPv3_MP_UNAVAILABLE_CONTEXT         -1416
+#define SNMPv3_MP_UNKNOWN_CONTEXT             -1417
+#define SNMPv3_MP_REPORT_SENT                 -1418
+//@}
+
+/** @name Statistics on error codes. */
+//@{
+#define SNMPv3_MP_MAX_ERROR           SNMPv3_MP_ERROR
+#define SNMPv3_MP_MIN_ERROR           SNMPv3_MP_REPORT_SENT
+#define SNMPv3_MP_ERRORCOUNT          SNMPv3_MP_MAX_ERROR - SNMPv3_MP_MIN_ERROR
+//@}
+
+class Snmp;
+class USM;
+
+/**
+ * The SNMPv3 Message Processing Model (v3MP).
+ *
+ * If SNMPv3 is used, the application needs to create _one_ object of
+ * this class. This object will automatically create an object of the
+ * USM class. A pointer to this object is returned from the get_usm()
+ * method. See the USM documentation for a description on how to create
+ * and delete users.
+ *
+ * The only thing that may be configured after creation of the v3MP is
+ * the engine id table of the v3MP. Entries for other SNMP entities
+ * can be added through add_to_engine_id_table(). It is only required
+ * to add entries to this table if you want to disable engine id
+ * discovery and/or you don't want the delay caused by the automatic
+ * engine id discovery of SNMPv3.
+ */
+class DLLOPT v3MP
+{
+  friend class SnmpMessage;
+  friend class CSNMPMessageQueue;
+ public:
+  /**
+   * Initialize the v3MP.
+   *
+   * Set the engineID of this SNMP entity and the Snmp object used to
+   * send reports. This function creates a new USM object that can
+   * be configured after getting a pointer to it through get_usm().
+   *
+   * The user is responsible to save and restore and increment the
+   * snmpEngineBoots counter (The functions getBootCounter() and
+   * saveBootCounter() can be used to do this.).
+   *
+   * @param engine_id    - The locale engine id
+   * @param engine_boots - The new value for the snmpEngineBoots counter
+   * @param construct_status - OUT: SNMPv3_MP_OK or SNMPv3_MP_ERROR
+   *
+   */
+  v3MP(const OctetStr& engine_id,
+       unsigned int engine_boots, int &construct_status);
+
+  /**
+   * Get the engine id of this SNMP entity.
+   *
+   * @param id - OUT: The engineID of this SNMP entity
+   *
+   * @return - SNMPv3_MP_OK or SNMPv3_MP_ERROR
+   */
+  void get_local_engine_id(OctetStr &id) { id = own_engine_id_oct; };
+
+  /**
+   * Get the engine id of this SNMP entity as a OctetStr reference.
+   *
+   * @return Local engine id.
+   */
+  const OctetStr& get_local_engine_id() const
+    { return own_engine_id_oct; };
+
+  /**
+   * Get a pointer to the USM object that is used by the v3MP.
+   */
+  USM *get_usm() { return usm; };
+
+  /**
+   * Free all allocated ressources of the v3MP and leave it in an
+   * uninitialized state. After a call to this function, you can use
+   * mpInit() to reinitialize the v3MP.
+   *
+   */
+  ~v3MP();
+
+  /**
+   * Add an entry to the engine id table.
+   *
+   * In this table all known engine ids are stored. If the discovery
+   * mode of the USM is enabled, snmp++ will add entries to this table
+   * whenever a new engine id is dicovered.
+   *
+   * @param engine_id - The engine id
+   * @param host      - The numerical IP address
+   * @param port      - The port
+   *
+   * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+   */
+  int add_to_engine_id_table(const OctetStr &engine_id,
+                            const OctetStr &host, int port)
+    { return engine_id_table.add_entry(engine_id, host, port); };
+
+  /**
+   * Remove an entry from the engine id table.
+   *
+   * @param host      - The numerical IP address
+   * @param port      - The port
+   *
+   * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+   */
+  int remove_from_engine_id_table(const OctetStr &host, int port)
+    { return engine_id_table.delete_entry(host, port); };
+
+  /**
+   * Remove an entry from the engine id table.
+   *
+   * @param engine_id - The engine id
+   *
+   * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+   */
+  int remove_from_engine_id_table(const OctetStr &engine_id)
+    { return engine_id_table.delete_entry(engine_id); };
+
+  /**
+   * Get the engine id of the SNMP entity at the given host/port.
+   *
+   * @param engine_id - OUT: The engine id
+   * @param hostport  - The numerical IP address and port
+   *                    (syntax: a.b.c.d/port)
+   *
+   * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+   *           SNMPv3_MP_OK
+   */
+  int get_from_engine_id_table(OctetStr &engine_id,
+                              const OctetStr &hostport) const
+    {  return engine_id_table.get_entry(engine_id, hostport); };
+
+  /**
+   * Get the engineID of the SNMP entity at the given host/port.
+   *
+   * @param engineID - OUT: The engineID
+   * @param host     - The numerical IP address
+   * @param port     - The port
+   *
+   * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+   *           SNMPv3_MP_OK
+   */
+  int get_from_engine_id_table(OctetStr &engineID,
+                              const OctetStr &host, int port) const
+    {  return engine_id_table.get_entry(engineID, host, port); };
+
+  /**
+   * Remove all entries from the engine id table.
+   *
+   * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+   *           SNMPv3_MP_OK
+   */
+  int reset_engine_id_table()
+    {  return engine_id_table.reset(); };
+
+  /**
+   * Remove all occurences of this engine id from v3MP and USM.
+   *
+   * @param engine_id - The engine id to remove
+   *
+   * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+   *           SNMPv3_MP_OK
+   */
+  int remove_engine_id(const OctetStr &engine_id);
+
+  // ----------[ Access to status counters for agent++ ]--------------
+
+  /**
+   * Get the value of the status counter snmpUnknownSecurityModels.
+   *
+   * @return - The status counter
+   */
+  unsigned long get_stats_unknown_security_models() const
+    { return snmpUnknownSecurityModels; };
+
+  /**
+   * Get the value of the status counter snmpInvalidMsgs.
+   *
+   * @return - The status counter
+   */
+  unsigned long get_stats_invalid_msgs() const
+    { return snmpInvalidMsgs; };
+
+  /**
+   * Get the value of the status counter snmpUnknownPDUHandlers.
+   *
+   * @return - The status counter
+   */
+  unsigned long get_stats_unknown_pdu_handlers() const
+    { return snmpUnknownPDUHandlers; };
+
+  /**
+   * Increment the value of the status counter snmpUnknownSecurityModels.
+   */
+  void inc_stats_unknown_security_models()
+    { snmpUnknownSecurityModels++; };
+
+  /**
+   * Increment the value of the status counter snmpInvalidMsgs.
+   */
+  void inc_stats_invalid_msgs() { snmpInvalidMsgs++; };
+
+  /**
+   * Increment the value of the status counter snmpUnknownPDUHandlers.
+   */
+  void inc_stats_unknown_pdu_handlers() { snmpUnknownPDUHandlers++; };
+
+  // temporary pointer will be removed...
+  static v3MP *I;
+
+ protected:
+
+  /**
+   * Parse the given buffer as a SNMPv3-Message.
+   *
+   * @param snmp_session     - IN: The session used to receive the msg
+   * @param pdu              - OUT: Parsed values are put into this struct
+   * @param inBuf            - The buffer to parse
+   * @param inBufLength      - The length of the buffer
+   * @param securityEngineID - OUT: The parsed securityEngineID
+   * @param securityName     - OUT: The parsed securityName
+   * @param contextEngineID  - OUT: The parsed contextEngineID
+   * @param contextName      - OUT: The parsed contextName
+   * @param securityLevel    - OUT: The parsed security level
+   * @param msgSecurityModel - OUT: The security model used
+   * @param spp_version      - OUT: SNMP version (SNMPv3)
+   * @param from_address     - Where the message came from (used to send
+   *                           a report if neccessary)
+   *
+   * @return - SNMPv3_MP_OK or any error listed in snmperr.h
+   */
+  int snmp_parse(Snmp *snmp_session,
+                 struct snmp_pdu *pdu,
+                unsigned char *inBuf,
+                int inBufLength,
+                OctetStr &securityEngineID,
+                OctetStr &securityName,
+                OctetStr &contextEngineID,
+                OctetStr &contextName,
+                long     &securityLevel,
+                long     &msgSecurityModel,
+                snmp_version &spp_version,
+                UdpAddress from_address);
+
+  /**
+   * Tests if the given buffer contains a SNMPv3-Message. The buffer is
+   * only parsed to extract the version of the message, no other checks
+   * are made.
+   *
+   * @param buffer - The message
+   * @param length - The length of the message
+   *
+   * @return - TRUE if the version could be extracted and it
+   *           is a SNMPv3 message. On any error: FALSE.
+   *
+   */
+  static bool is_v3_msg( unsigned char *buffer, int length);
+
+  /**
+   * Do the complete process of encoding the given values into the buffer
+   * ready to send to the target.
+   *
+   * @param pdu              - The pdu structure
+   * @param packet           - The buffer to store the serialized message
+   * @param out_length       - IN: Length of the buffer,
+   *                           OUT: Length of the message
+   * @param securityEngineID - The securityEngineID
+   * @param securityNameIn   - The securityName
+   * @param securityModel    - Use this security model
+   * @param securityLevel    - Use this security level
+   * @param contextEngineID  - The contextEngineID
+   * @param contextName      - The contextName
+   *
+   * @return - SNMPv3_MP_OK or any error listed in snmperr.h
+   */
+  int snmp_build(struct snmp_pdu *pdu,
+                unsigned char *packet,
+                int *out_length,           // maximum Bytes in packet
+                const OctetStr &securityEngineID,
+                const OctetStr &securityNameIn,
+                int securityModel, int securityLevel,
+                const OctetStr &contextEngineID,
+                const OctetStr &contextName);
+
+  /**
+   * Delete the entry with the given request id from the cache.
+   * This function is used in eventlist.cpp when a request
+   * has timed out.
+   *
+   * @param requestID - The request id.
+   * @param local_request - Does the request id belong to a local or to
+   *                        a remote request?
+   */
+  void delete_from_cache(unsigned long requestID,
+                        const bool local_request = true)
+    { cache.delete_entry(requestID, local_request); };
+
+ public:
+
+  /**
+   * Delete the entry with the given request id from the cache.
+   * This function is used in agent++ RequestList.
+   *
+   * @param requestID - The request id.
+   * @param messageID - The message id.
+   * @param local_request - Does the request id belong to a local or to
+   *                        a remote request?
+   */
+  void delete_from_cache(unsigned long requestID,
+                        unsigned long messageID,
+                        const bool local_request)
+    { cache.delete_entry(requestID, messageID, local_request); };
+
+ private:
+
+  /**
+   * Send a report message.
+   *
+   * @param scopedPDU   - The scopedPDU as received. If the pdu is not
+   *                      encrypted, the request id is extracted
+   * @param scopedPDULength - The lkength of the scopedPDU
+   * @param pdu         - The pdu structure.
+   * @param errorCode   - The code of the error that occured.
+   * @param sLevel      - Send the report with this security level.
+   * @param sModel      - Use this security model.
+   * @param sName       - Use this security name
+   * @param destination - Send the report to this address.
+   * @param snmp_session - Snmp session to use for sending a report
+   *
+   * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+   */
+  int send_report(unsigned char* scopedPDU, int scopedPDULength,
+                 struct snmp_pdu *pdu, int errorCode, int sLevel,
+                 int sModel, OctetStr &sName,
+                 UdpAddress &destination, Snmp *snmp_session);
+
+
+
+  // =====================[ member classes ]==============================
+
+  /**
+   * The engine id table is used to store known engine ids with
+   * corresponding hostadress and port.
+   */
+  class DLLOPT EngineIdTable
+  {
+   public:
+
+    EngineIdTable(int initial_size = 10);
+    ~EngineIdTable();
+
+    /**
+     * Add an entry to the table.
+     *
+     * @param engine_id - The engineID
+     * @param host      - The numerical IP address
+     * @param port      - The port
+     *
+     * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+     */
+    int add_entry(const OctetStr &engine_id,
+                 const OctetStr &host, int port);
+
+    /**
+     * Get the engine_id of the SNMP entity at the given host/port.
+     *
+     * @param engine_id - OUT: The engineID
+     * @param hostport  - The numerical IP address and port
+     *                    (syntax: a.b.c.d/port)
+     *
+     * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+     *           SNMPv3_MP_OK
+     */
+    int get_entry(OctetStr &engine_id, const OctetStr &hostport) const;
+
+    /**
+     * Get the engineID of the SNMP entity at the given host/port.
+     *
+     * @param engine_id - OUT: The engineID
+     * @param host      - The numerical IP address
+     * @param port      - The port
+     *
+     * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+     *           SNMPv3_MP_OK
+     */
+    int get_entry(OctetStr &engine_id, const OctetStr &host, int port) const;
+
+    /**
+     * Remove all entries from the engine id table.
+     *
+     * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+     *           SNMPv3_MP_OK
+     */
+    int reset();
+
+    /**
+     * Remove the given engine id from the table.
+     *
+     * @param engine_id - The engine id to remove
+     *
+     * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+     *           SNMPv3_MP_OK
+     */
+    int delete_entry(const OctetStr &engine_id);
+
+    /**
+     * Remove the entry for the given address/port from the table.
+     *
+     * @param host - Numeric IP address
+     * @param port - listen port of the snmp entity
+     *
+     * @return - SNMPv3_MP_NOT_INITIALIZED, SNMPv3_MP_ERROR,
+     *           SNMPv3_MP_OK
+     */
+    int delete_entry(const OctetStr &host, int port);
+
+  private:
+    int initialize_table(const int size);
+
+    struct Entry_T
+    {
+      OctetStr engine_id;
+      OctetStr host;
+      int port;
+    };
+
+    struct Entry_T *table;
+    int max_entries;      ///< the maximum number of entries
+    int entries;          ///< the current amount of entries
+    SNMP_PP_MUTABLE SnmpSynchronized lock;
+  };
+
+
+  /**
+   * Holds cache entries for currently processed requests.
+   */
+  class DLLOPT Cache
+  {
+   public:
+    Cache();
+    ~Cache();
+
+    struct Entry_T
+    {
+      int msg_id;
+      unsigned long req_id;
+      OctetStr sec_engine_id;
+      int sec_model;
+      OctetStr sec_name;
+      int sec_level;
+      OctetStr context_engine_id;
+      OctetStr context_name;
+      struct SecurityStateReference *sec_state_ref;
+      int error_code;
+      bool local_request;
+    };
+
+    /**
+     * Add an entry to the cache.
+     *
+     * @param msg_id            - The message id of the message
+     * @param req_id        - The request id of the message
+     * @param sec_engine_id - The authoritative engineID
+     * @param sec_model    - The security model used for this message
+     * @param sec_name     - The name of the user
+     * @param sec_level    - The security level used for this message
+     * @param context_engine_id  - The context_engine_id
+     * @param context_name      - The context_name
+     * @param sec_state_ref - The reference of the USM
+     * @param error_code        - The code of the error that occured while
+     *                           parsing the received message
+     *
+     * @return - SNMPv3_MP_OK, SNMPv3_MP_ERROR or SNMPv3_DOUBLED_MESSAGE
+     *           (an entry with the given values is already in the cache)
+     */
+    int add_entry(int msg_id, unsigned long req_id,
+                 const OctetStr &sec_engine_id,
+                 int sec_model,
+                 const OctetStr &sec_name,
+                 int sec_level,
+                 const OctetStr &context_engine_id,
+                 const OctetStr &context_name,
+                 struct SecurityStateReference *sec_state_ref,
+                 int error_code, bool local_request);
+    /**
+     * Search the cache for a message id, return the error code and
+     * the sec_state_ref and delete the entry from the cache.
+     *
+     * @param msg_id     - Search for this message id
+     * @param error_code - OUT: The error code of the received message
+     * @param sec_state_ref - IN:  Pointer to a pointer of the structure
+     *                        OUT: The structure as received by the USM when
+     *                             the message was parsed.
+     *
+     * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+     */
+    int get_entry(int msg_id, bool local_request, int *error_code,
+                 struct SecurityStateReference **sec_state_ref);
+
+    /**
+     * Delete the entry with the given request id from the cache.
+     * This function is used in eventlist.cpp when a request
+     * has timed out.
+     *
+     * @param req_id - The request id.
+     */
+    void delete_entry(unsigned long req_id, bool local_request);
+
+    /**
+     * Delete the entry with the given request and message id from the cache.
+     *
+     * @param req_id - The request id.
+     * @param msg_id - The message id.
+     */
+    void delete_entry(unsigned long req_id, int msg_id,
+                     bool local_request);
+
+    /**
+     * Search the cache for a message id, return the whole entry and
+     * delete the entry from the cache.
+     *
+     * @param searchedID - Search for this message id
+     * @param res        - IN:  Pointer to an empy structure
+     *                     OUT: The filled structure
+     *
+     * @return - SNMPv3_MP_ERROR, SNMPv3_MP_OK
+     */
+    int get_entry(int searchedID, bool local_request,
+                  struct Cache::Entry_T *res);
+
+    void delete_content(struct Cache::Entry_T &ce);
+
+    void set_usm(USM *usm_to_use) { usm = usm_to_use; };
+
+   private:
+#ifdef _THREADS
+    SNMP_PP_MUTABLE SnmpSynchronized lock;
+#endif
+    struct Entry_T *table; ///< whole table
+    int max_entries;       ///< the maximum number of entries
+    int entries;           ///< the current amount of entries
+    USM *usm;
+  };
+
+
+  // =====================[ member variables ]==============================
+  EngineIdTable engine_id_table;
+  Cache cache;
+
+  // the engineID of this SNMP entity
+  unsigned char *own_engine_id;
+  int own_engine_id_len;
+  OctetStr own_engine_id_oct;
+
+  unsigned int cur_msg_id;   ///< msgID to use for next message
+  SNMP_PP_MUTABLE SnmpSynchronized cur_msg_id_lock;
+
+  USM *usm;  ///< the USM object used
+
+  // MIB Counters
+  unsigned int snmpUnknownSecurityModels;
+  unsigned int snmpInvalidMsgs;
+  unsigned int snmpUnknownPDUHandlers;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // _SNMPv3
+
+#endif
diff --git a/3rdparty/snmp++/include/snmp_pp/msec.h b/3rdparty/snmp++/include/snmp_pp/msec.h
new file mode 100644 (file)
index 0000000..0b642f0
--- /dev/null
@@ -0,0 +1,189 @@
+/*_############################################################################
+  _## 
+  _##  msec.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+*/
+// $Id: msec.h 307 2007-09-14 20:01:45Z katz $
+
+#ifndef _MSEC_H_
+#define _MSEC_H_
+
+//----[ includes ]-----------------------------------------------------
+#include <sys/types.h> /* NOTE: due to 10.10 bug, order is important
+                       * in that all routines must include types.h
+                       * and time.h in same order otherwise you will
+                       * get conflicting definitions of "fd_set"
+                       * resulting in link time errors.
+                       */
+#ifdef WIN32
+#elif defined (CPU) && CPU == PPC603
+#include <sys/times.h>
+#else
+#include <sys/time.h>
+#include <sys/param.h>
+#endif
+
+#include <time.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/smi.h"
+#include "snmp_pp/reentrant.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//----[ defines ]------------------------------------------------------
+#define MSECOUTBUF 20
+
+//----[ msec class ]---------------------------------------------------
+/**
+ * Time handling...
+ */
+class DLLOPT msec
+{
+ public:
+  /**
+   * Constructor, sets the time to the current system time.
+   */
+  msec() { refresh(); };
+
+  /**
+   * Constructor using another msec object
+   *
+   * @param in_msec - Time for this object
+   */
+  msec(const msec &in_msec) : m_time(in_msec.m_time), m_changed(true) {};
+
+  /**
+   * Constructor using seconds and milli sconds.
+   *
+   * @param sec    - Seconds
+   * @param milsec - Milli seconds
+   */
+  msec(const int sec, const int milsec) : m_changed(true)
+    { m_time.tv_sec  = sec; m_time.tv_usec = milsec; };
+
+  DLLOPT friend int operator==(const msec &t1, const msec &t2);
+  DLLOPT friend int operator!=(const msec &t1, const msec &t2);
+  DLLOPT friend int operator<(const msec &t1, const msec &t2);
+  DLLOPT friend int operator>(const msec &t1, const msec &t2);
+  DLLOPT friend int operator<=(const msec &t1, const msec &t2)
+    { return((t1 < t2) || (t1 == t2)); };
+  DLLOPT friend int operator>=(const msec &t1, const msec &t2)
+    { return((t1 > t2) || (t1 == t2)); };
+
+  msec &operator-=(const long millisec);
+  msec &operator-=(const timeval &t1);
+  msec &operator+=(const long millisec);
+  msec &operator+=(const timeval &t1);
+  msec &operator=(const msec &t)
+    { m_time = t.m_time; m_changed = true; return *this; };
+  msec &operator=(const timeval &t1);
+
+  /**
+   * Use as an unsigned long.
+   *
+   * @return Time in milli seconds
+   */
+  operator unsigned long() const
+    { return ((m_time.tv_sec * 1000) + m_time.tv_usec); };
+
+  /**
+   * Set the time to the current system time.
+   */
+  void refresh();
+
+  /**
+   * Set the object out into the future as far as possible.
+   */
+  void SetInfinite()
+    { m_time.tv_sec = (time_t) -1; m_time.tv_usec = 0; m_changed = true; };
+
+  /**
+   * Check if the time is infinite.
+   *
+   * @return True, if the time is infinite.
+   */
+  int IsInfinite() const
+    { return ((m_time.tv_sec == (time_t) -1) && (m_time.tv_usec == 0)); };
+
+  /**
+   * Get the difference between this and the given time.
+   * If future is before this objects time, "timeout" will be set to zero.
+   *
+   * @param future  - Time to compare to
+   * @param timeout - Will be filled with the difference
+   */
+  void GetDelta(const msec &future, timeval &timeout) const;
+
+  /**
+   * Get the difference between this object and the current system time.
+   * If the system time is before this objects time,
+   * "timeout" will be set to zero.
+   *
+   * @param timeout - Will be filled with the difference
+   */
+  void GetDeltaFromNow(timeval &timeout) const
+    { msec now; now.GetDelta(*this, timeout); };
+
+  /**
+   * Return the time as printable string.
+   */
+  const char *get_printable() const;
+
+private:
+  timeval m_time;
+  SNMP_PP_MUTABLE char m_output_buffer[MSECOUTBUF];
+  SNMP_PP_MUTABLE bool m_changed;
+
+#if !defined HAVE_LOCALTIME_R && !defined HAVE_REENTRANT_LOCALTIME
+#ifdef _THREADS
+  static SnmpSynchronized m_localtime_mutex;
+#endif
+#endif
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // _MSEC_H_
diff --git a/3rdparty/snmp++/include/snmp_pp/msgqueue.h b/3rdparty/snmp++/include/snmp_pp/msgqueue.h
new file mode 100644 (file)
index 0000000..7ff7d93
--- /dev/null
@@ -0,0 +1,224 @@
+/*_############################################################################
+  _## 
+  _##  msgqueue.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+      M S G Q U E U E . H
+
+      CSNMPMessageQueue CLASS DEFINITION
+
+      COPYRIGHT HEWLETT PACKARD COMPANY 1999
+
+      INFORMATION NETWORKS DIVISION
+
+      NETWORK MANAGEMENT SECTION
+
+      DESIGN + AUTHOR:     Tom Murray
+
+      DESCRIPTION:
+       Queue for holing SNMP event sources (outstanding snmp messages)
+
+=====================================================================*/
+// $Id: msgqueue.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _MSGQUEUE
+#define _MSGQUEUE
+
+//----[ includes ]-----------------------------------------------------
+#include <sys/types.h>         // NOTE:  due to 10.10 bug, order is important
+                               //   in that all routines must include types.h
+                               //   and time.h in same order otherwise you
+                               //   will get conflicting definitions of
+                               //   "fd_set" resulting in link time errors.
+#ifndef WIN32
+#if !(defined CPU && CPU == PPC603)
+#include <sys/time.h>  // time stuff and fd_set
+#endif
+#endif
+
+//----[ snmp++ includes ]----------------------------------------------
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/address.h"
+#include "snmp_pp/target.h"
+#include "snmp_pp/pdu.h"
+#include "snmp_pp/msec.h"
+#include "snmp_pp/uxsnmp.h"
+#include "snmp_pp/eventlist.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//----[ defines ]------------------------------------------------------
+
+
+
+//----[ CSNMPMessage class ]-------------------------------------------
+
+
+  /*-----------------------------------------------------------*/
+  /* CSNMPMessage                                             */
+  /*   a description of a single MIB access operation.        */
+  /*-----------------------------------------------------------*/
+class DLLOPT CSNMPMessage
+{
+ public:
+  CSNMPMessage(unsigned long id,
+              Snmp * snmp,
+              SnmpSocket socket,
+              const SnmpTarget &target,
+              Pdu &pdu,
+              unsigned char * rawPdu,
+              size_t rawPduLen,
+              const Address & address,
+              snmp_callback callBack,
+              void * callData);
+  virtual ~CSNMPMessage();
+  unsigned long GetId() const { return m_uniqueId; };
+  void ResetId(const unsigned long newId) { m_uniqueId = newId; };
+  void SetSendTime();
+  void GetSendTime(msec &sendTime) const { sendTime = m_sendTime; };
+  SnmpSocket GetSocket() const { return m_socket; };
+  int SetPdu(const int reason, const Pdu &pdu, const UdpAddress &fromaddress);
+  int GetPdu(int &reason, Pdu &pdu)
+                                 { pdu = m_pdu; reason = m_reason; return 0; };
+  int GetReceived() const { return m_received; };
+  int ResendMessage();
+  int Callback(const int reason);
+  SnmpTarget *GetTarget() { return m_target; };
+
+ protected:
+
+  unsigned long          m_uniqueId;
+  msec           m_sendTime;
+  Snmp *         m_snmp;
+  SnmpSocket     m_socket;
+  SnmpTarget *   m_target;
+  Pdu            m_pdu;
+  unsigned char * m_rawPdu;
+  size_t         m_rawPduLen;
+  Address *      m_address;
+  snmp_callback          m_callBack;
+  void *         m_callData;
+  int            m_reason;
+  int            m_received;
+};
+
+  /*-----------------------------------------------------------*/
+  /* CSNMPMessageQueue                                        */
+  /*   class describing a collection of outstanding SNMP msgs. */
+  /*-----------------------------------------------------------*/
+class DLLOPT CSNMPMessageQueue: public CEvents
+{
+ public:
+    CSNMPMessageQueue(EventListHolder *holder, Snmp *session);
+    virtual ~CSNMPMessageQueue();
+    CSNMPMessage *AddEntry(unsigned long id, Snmp *snmp, SnmpSocket socket,
+                          const SnmpTarget &target, Pdu &pdu, unsigned char * rawPdu,
+                          size_t rawPduLen, const Address & address,
+                          snmp_callback callBack, void * callData);
+    CSNMPMessage *GetEntry(const unsigned long uniqueId);
+    int DeleteEntry(const unsigned long uniqueId);
+    void DeleteSocketEntry(const SnmpSocket socket);
+  // find the next msg that will timeout
+    CSNMPMessage *GetNextTimeoutEntry();
+  // find the next timeout
+    int GetNextTimeout(msec &sendTime);
+#ifdef HAVE_POLL_SYSCALL
+    int GetFdCount();
+    bool GetFdArray(struct pollfd *readfds, int &remaining);
+    int HandleEvents(const struct pollfd *readfds, const int fds);
+#else
+  // set up parameters for select
+    void GetFdSets(int &maxfds, fd_set &readfds, fd_set &writefds,
+                 fd_set &exceptfds);
+    int HandleEvents(const int maxfds,
+                    const fd_set &readfds,
+                    const fd_set &writefds,
+                    const fd_set &exceptfds);
+#endif
+
+  // return number of outstanding messages
+    int GetCount() { return m_msgCount; };
+
+    int DoRetries(const msec &sendtime);
+
+    int Done();
+    int Done(unsigned long);
+
+ protected:
+
+    /*---------------------------------------------------------*/
+    /* CSNMPMessageQueueElt                                   */
+    /*   a container for a single item on a linked lists of    */
+    /*  CSNMPMessages.                                        */
+    /*---------------------------------------------------------*/
+    class DLLOPT CSNMPMessageQueueElt
+    {
+     public:
+      CSNMPMessageQueueElt(CSNMPMessage *message,
+                          CSNMPMessageQueueElt *next,
+                          CSNMPMessageQueueElt *previous);
+
+      ~CSNMPMessageQueueElt();
+      CSNMPMessageQueueElt *GetNext() { return m_Next; }
+      CSNMPMessage *GetMessage() { return m_message; }
+      CSNMPMessage *TestId(const unsigned long uniqueId);
+
+     private:
+
+      CSNMPMessage *m_message;
+      class CSNMPMessageQueueElt *m_Next;
+      class CSNMPMessageQueueElt *m_previous;
+    };
+
+    CSNMPMessageQueueElt m_head;
+    int m_msgCount;
+    EventListHolder *my_holder;
+    Snmp *m_snmpSession;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif
diff --git a/3rdparty/snmp++/include/snmp_pp/notifyqueue.h b/3rdparty/snmp++/include/snmp_pp/notifyqueue.h
new file mode 100644 (file)
index 0000000..125e8c9
--- /dev/null
@@ -0,0 +1,202 @@
+/*_############################################################################
+  _## 
+  _##  notifyqueue.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+      N O T I F Y Q U E U E. H
+
+      CNotifyEventQueue CLASS DEFINITION
+
+      COPYRIGHT HEWLETT PACKARD COMPANY 1999
+
+      INFORMATION NETWORKS DIVISION
+
+      NETWORK MANAGEMENT SECTION
+
+      DESIGN + AUTHOR:        Tom Murray
+
+      DESCRIPTION:
+        Queue for holding sessions waiting for notifiactions
+
+=====================================================================*/
+// $Id: notifyqueue.h 1550 2009-06-26 19:59:30Z katz $
+
+#ifndef _NOTIFYQUEUE
+#define _NOTIFYQUEUE
+
+//----[ includes ]-----------------------------------------------------
+#include <sys/types.h>          // NOTE: due to 10.10 bug, order is important
+                                //   in that all routines must include types.h
+                                //   and time.h in same order otherwise you
+                                //   will get conflicting definitions of
+                                //   "fd_set" resulting in link time errors.
+#ifndef WIN32
+#if !(defined CPU && CPU == PPC603)
+#include <sys/time.h>  // time stuff and fd_set
+#endif
+#endif
+
+//----[ snmp++ includes ]----------------------------------------------
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/oid.h"
+#include "snmp_pp/target.h"
+#include "snmp_pp/eventlist.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class Snmp; // instead of snmp_pp.h
+class msec;
+class EventListHolder;
+
+//----[ defines ]------------------------------------------------------
+
+//----[ CNotifyEvent class ]-------------------------------------------
+
+/*----------------------------------------------------------------*/
+/* CNotifyEvent                                                   */
+/*   a description of a sessions waiting for async notifiactions. */
+/*----------------------------------------------------------------*/
+class DLLOPT CNotifyEvent
+{
+ public:
+
+  CNotifyEvent(Snmp* snmp,
+              const OidCollection &trapids,
+              const TargetCollection &targets);
+  ~CNotifyEvent();
+  Snmp * GetId() { return m_snmp; };
+  int notify_filter(const Oid &trapid, SnmpTarget &target) const;
+  int Callback(SnmpTarget &target, Pdu &pdu, SnmpSocket fd, int status);
+  void get_filter(OidCollection &o, TargetCollection &t)
+    { o = *notify_ids; t = *notify_targets; };
+
+ protected:
+  Snmp              *m_snmp;
+  TargetCollection  *notify_targets;
+  OidCollection     *notify_ids;
+};
+
+  /*-----------------------------------------------------------*/
+  /* CNotifyEventQueue                                         */
+  /*   class describing a collection of outstanding SNMP msgs. */
+  /*-----------------------------------------------------------*/
+class DLLOPT CNotifyEventQueue: public CEvents
+{
+  public:
+    CNotifyEventQueue(EventListHolder *holder, Snmp *session);
+    ~CNotifyEventQueue();
+    int AddEntry(Snmp * snmp,
+                const OidCollection &trapids,
+                const TargetCollection &targets);
+    CNotifyEvent * GetEntry(Snmp * snmp);
+    void DeleteEntry(Snmp * snmp);
+
+    // find the next timeout
+    int GetNextTimeout(msec &/*timeout*/) { return 1; }; // we have no timeouts
+    // set up parameters for select
+#ifdef HAVE_POLL_SYSCALL
+    int GetFdCount();
+    bool GetFdArray(struct pollfd *readfds, int &remaining);
+    int HandleEvents(const struct pollfd *readfds, const int fds);
+#else
+    void GetFdSets(int &maxfds, fd_set &readfds, fd_set &writefds,
+                  fd_set &exceptfds);
+    int HandleEvents(const int maxfds,
+                     const fd_set &readfds,
+                     const fd_set &writefds,
+                     const fd_set &exceptfds);
+#endif
+    // return number of outstanding messages
+    int GetCount() { return m_msgCount; };
+
+    int DoRetries(const msec &/*sendtime*/) { return 0; }; // nothing to retry
+
+    int Done() { return 0; }; // we are never done
+    void set_listen_port(int port) { m_listen_port = port; };
+    int get_listen_port() { return m_listen_port; };
+    SnmpSocket get_notify_fd() const;
+
+  protected:
+
+    /*-----------------------------------------------------------*/
+    /* CNotifyEventQueueElt                                      */
+    /*   a container for a single item on a linked lists of      */
+    /*  CNotifyEvents.                                           */
+    /*-----------------------------------------------------------*/
+    class DLLOPT CNotifyEventQueueElt
+    {
+     public:
+      CNotifyEventQueueElt(CNotifyEvent *notifyevent,
+                          CNotifyEventQueueElt *next,
+                          CNotifyEventQueueElt *previous);
+
+      ~CNotifyEventQueueElt();
+      CNotifyEventQueueElt *GetNext() { return m_Next; };
+      CNotifyEvent *GetNotifyEvent() { return m_notifyevent; };
+      CNotifyEvent *TestId(Snmp *snmp);
+
+    private:
+
+      CNotifyEvent *m_notifyevent;
+      class CNotifyEventQueueElt *m_Next;
+      class CNotifyEventQueueElt *m_previous;
+    };
+
+    void cleanup();
+
+    CNotifyEventQueueElt m_head;
+    int                  m_msgCount;
+    SnmpSocket           m_notify_fd;
+    int                  m_listen_port;
+    EventListHolder *my_holder;
+    Snmp *m_snmpSession;
+    UdpAddress m_notify_addr;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // NOTIFYQUEUE
diff --git a/3rdparty/snmp++/include/snmp_pp/octet.h b/3rdparty/snmp++/include/snmp_pp/octet.h
new file mode 100644 (file)
index 0000000..06a1c14
--- /dev/null
@@ -0,0 +1,462 @@
+/*_############################################################################
+  _## 
+  _##  octet.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+               
+  SNMP++ O C T E T . H
+
+  OCTETSTR CLASS DEFINITION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  This class is fully contained and does not rely on or any other
+  SNMP libraries. This class is portable across any platform
+  which supports C++.
+=====================================================================*/
+// $Id: octet.h 1824 2010-08-29 19:47:08Z katz $
+
+#ifndef _OCTET_CLS
+#define _OCTET_CLS
+
+#include "snmp_pp/smival.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//------------[ SNMP++ OCTETSTR CLASS DEF  ]-----------------------------
+class DLLOPT OctetStr: public  SnmpSyntax
+{
+ public:
+
+  /**
+   * Enum for setting the hex output format.
+   */
+  enum OutputType
+  {
+    OutputHexAndClear,
+    OutputHex,
+    OutputClear
+  };
+
+  //-----------[ Constructors and Destrucotr ]----------------------
+
+  /**
+   * Constructs a valid OctetStr with zero length.
+   */
+  OctetStr();
+
+  /**
+   * Constructs a OctetStr with the given value.
+   * The OctetStr will be valid unless a call to new fails.
+   *
+   * @param str - Null terminated string
+   */
+  OctetStr(const char *str);
+
+  /**
+   * Constructs a OctetStr with the given value.
+   * The OctetStr will be valid unless a call to new fails.
+   *
+   * @param str - string that may contain null bytes
+   * @param len - length of the string
+   */
+  OctetStr(const unsigned char *str, unsigned long len);
+
+  /**
+   * Construct a OctetStr from another OctetStr.
+   * The OctetStr will be valid unless a call to new fails.
+   *
+   * @param octet - Value for the new object
+   */
+  OctetStr(const OctetStr &octet);
+
+  /**
+   * Destructor, frees allocated space.
+   */
+  ~OctetStr();
+
+  //-----------[ Overloaded operators ]----------------------
+
+  /**
+   * Assign a char string to a OctetStr.
+   */
+  OctetStr& operator=(const char *str);
+
+  /**
+   * Assign a OctetStr to a OctetStr.
+   */
+  OctetStr& operator=(const OctetStr &octet);
+
+  /**
+   * Equal operator for two OctetStr.
+   */
+  DLLOPT friend int operator==(const OctetStr &lhs, const OctetStr &rhs);
+
+  /**
+   * Not equal operator for two OctetStr.
+   */
+  DLLOPT friend int operator!=(const OctetStr &lhs, const OctetStr &rhs);
+
+  /**
+   * Not equal operator for two OctetStr.
+   */
+  DLLOPT friend int operator<(const OctetStr &lhs, const OctetStr &rhs);
+
+  /**
+   * Less than operator for two OctetStr.
+   */
+  DLLOPT friend int operator<=(const OctetStr &lhs,const OctetStr &rhs);
+
+  /**
+   * Greater than operator for two OctetStr.
+   */
+  DLLOPT friend int operator>(const OctetStr &lhs, const OctetStr &rhs);
+
+  /**
+   * Greater than or equal operator for two OctetStr.
+   */
+  DLLOPT friend int operator>=(const OctetStr &lhs, const OctetStr &rhs);
+
+  /**
+   * Equal operator for OctetStr and char string.
+   */
+  DLLOPT friend int operator==(const OctetStr &lhs, const char *rhs);
+
+  /**
+   * Not equal operator for OctetStr and char string.
+   */
+  DLLOPT friend int operator!=(const OctetStr &lhs, const char *rhs);
+
+  /**
+   * Less than operator for OctetStr and char string.
+   */
+  DLLOPT friend int operator<(const OctetStr &lhs, const char *rhs);
+
+  /**
+   * Less than or equal operator for OctetStr and char string.
+   */
+  DLLOPT friend int operator<=(const OctetStr &lhs, const char *rhs);
+
+  /**
+   * Greater than operator for OctetStr and char string.
+   */
+  DLLOPT friend int operator>(const OctetStr &lhs, const char *rhs);
+
+  /**
+   * Greater than or equal operator for OctetStr and char string.
+   */
+  DLLOPT friend int operator>=(const OctetStr &lhs, const char *rhs);
+
+  /**
+   * Append a char string to this OctetStr.
+   */
+  OctetStr& operator+=(const char *a);
+
+  /**
+   * Append a single char to this OctetStr.
+   */
+  OctetStr& operator+=(const unsigned char c);
+
+  /**
+   * Append another OctetStr to this OctetStr.
+   */
+  OctetStr& operator+=(const OctetStr& octet);
+
+  /**
+   * Allow access as if it was an array.
+   *
+   * @note The given param is not checked for validity.
+   */
+  unsigned char &operator[](int i)
+    { m_changed = true; return smival.value.string.ptr[i]; };
+
+  /**
+   * Allow access as if it was an array for const OctetStr objects.
+   *
+   * @note The given param is not checked for validity.
+   */
+  unsigned char operator[](int i) const { return smival.value.string.ptr[i]; };
+
+  /**
+   * Return the syntax.
+   *
+   * @return This method always returns sNMP_SYNTAX_OCTETS.
+   */
+  SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OCTETS; };
+
+  /**
+   * Return the space needed for serialization.
+   */
+  int get_asn1_length() const;
+
+  /**
+   * Return validity of the object.
+   */
+  bool valid() const { return validity; };
+
+  /**
+   * Clone this object.
+   *
+   * @return Pointer to the newly created object (allocated through new).
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *) new OctetStr(*this); };
+
+  /**
+   * Map other SnmpSyntax objects to OctetStr.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  /**
+   * Get a printable ASCII value of the string.
+   *
+   * @note Depending on the selected output format, this method will
+   *       return get_printable_hex() or get_printable_clear() if the
+   *       string contains not printable characters.
+   *
+   * @return Printable, null terminated string
+   */
+  const char *get_printable() const;
+
+  /**
+   * Get an ASCII formatted hex dump of the contents.
+   * If the output format was set to OctetStr::OutputHexAndClear,
+   * the produced string of this method will look like this:
+   *                                                                     <pre>
+   * 09 4F 63 74 65 74 53 74 72 3A 3A 67 65 74 5F 70    .OctetStr::get_p
+   * 72 69 6E 74 61 62 6C 65 5F 68 65 78 28 29          rintable_hex()
+   *                                                                     </pre>
+   * If the output format was set to OctetStr::OutputHex the
+   * produced string will look like this:
+   *                                                                     <pre>
+   * 09 4F 63 74 65 74 53 74 72 3A 3A 67 65 74 5F 70
+   * 72 69 6E 74 61 62 6C 65 5F 68 65 78 28 29
+   *                                                                     </pre>
+   * @return Printable, null terminated string.
+   */
+  const char *get_printable_hex() const;
+
+  /**
+   * Get the contents with all non printable characters replaced.
+   *
+   * @return Printable, null terminated string.
+   */
+  const char *get_printable_clear() const;
+
+  /**
+   * Set the output format for get_pritable_hex().
+   */
+  static void set_hex_output_type(const enum OutputType ot)
+    { hex_output_type = ot; };
+
+  /**
+   * Set the char get_printable_hex() and get_printable_clear()
+   * will use for non printable characters.
+   */
+  static void set_np_char(const char np) { nonprintable_char = np; };
+
+  /**
+   * Set the data on an already constructed OctetStr.
+   * The given string is copied to an internal member var, so the
+   * params can be destroyed afterwards.
+   *
+   * @param str - The new string value
+   * @param len - Length of the given string
+   */
+  void set_data(const unsigned char *str, unsigned long len);
+
+  /**
+   * Get the length of the string.
+   */
+  unsigned long len() const { return smival.value.string.len; };
+
+  /**
+   * Get a pointer to internal data.
+   */
+  unsigned char *data() const { return smival.value.string.ptr; };
+
+  // compare n elements of an octet
+  int nCompare(const unsigned long n, const OctetStr &o) const;
+
+  /**
+   * Build an OctetStr from a hex string.
+   * Called with "5465  737469 6e672074686973206D657468 6f 64 21"
+   * the returned value will be "Testing this method!"
+   *
+   * @param hex_string - The hex string (may contain spaces)
+   * @return created string
+   */
+  static OctetStr from_hex_string(const OctetStr &hex_string);
+
+  /**
+   * Set the character for linefeeds in get_printable() functions.
+   *
+   * The default linefeeds are \n for Unix and \r\n on other systems.
+   *
+   * @param lf_chars - string less than 3 bytes
+   * @return true on success
+   */
+  static bool set_linefeed_chars(const char* lf_chars);
+
+  /**
+   * Null out the contents of the string. The string will be empty
+   * after calling this method
+   */
+  void clear();
+
+  /**
+   * Append or shorten the internal data buffer.
+   *
+   * The buffer will either be shortened or extended. In the second case
+   * zeroes are added to the end of the string.
+   *
+   * @param new_len - The new length for the string
+   * @return true on success
+   */
+  bool set_len(const unsigned long new_len);
+
+ protected:
+
+  enum OutputFunction
+  {
+      OutputFunctionDefault,
+      OutputFunctionHex,
+      OutputFunctionClear
+  };
+
+  SNMP_PP_MUTABLE char *output_buffer;  // formatted Octet value
+  SNMP_PP_MUTABLE unsigned int output_buffer_len; // allocated space for string
+  SNMP_PP_MUTABLE bool m_changed;
+  SNMP_PP_MUTABLE enum OutputType output_last_type;
+  SNMP_PP_MUTABLE char output_last_np_char;
+  SNMP_PP_MUTABLE enum OutputFunction output_last_function;
+
+
+  bool validity;                        // validity boolean
+
+  static enum OutputType hex_output_type;
+  static char nonprintable_char;
+  static char linefeed_chars[3];
+};
+
+//-----------[ End OctetStr Class ]-------------------------------------
+
+/**
+ * The OpaqueStr class represents the Opaque SNMP type. It is derived from
+ * the SNMP++ class OctetStr and has the same interfaces and behavior,
+ * except that its syntax is sNMP_SYNTAX_OPAQUE.
+ */
+class OpaqueStr: public OctetStr
+{
+ public:
+  /**
+   * Constructor creating a valid zero length OpaqueStr.
+   */
+  OpaqueStr(): OctetStr()
+    { smival.syntax = sNMP_SYNTAX_OPAQUE; };
+
+  /**
+   * Constructs a OpaqueStr with the given value.
+   * The OpaqueStr will be valid unless a call to new fails.
+   *
+   * @param str - Null terminated string
+   */
+  OpaqueStr(const char *str) : OctetStr(str)
+    { smival.syntax = sNMP_SYNTAX_OPAQUE; };
+
+  /**
+   * Constructs a OpaqueStr with the given value.
+   * The OpaqueStr will be valid unless a call to new fails.
+   *
+   * @param str - string that may contain null bytes
+   * @param len - length of the string
+   */
+  OpaqueStr(const unsigned char *str, unsigned long length)
+    : OctetStr(str, length) { smival.syntax = sNMP_SYNTAX_OPAQUE; };
+
+  /**
+   * Construct a OpaqueStr from an OctetStr.
+   * The OpaqueStr will be valid unless a call to new fails.
+   *
+   * @param octet - Value for the new object
+   */
+  OpaqueStr(const OctetStr &octet) : OctetStr(octet)
+    { smival.syntax = sNMP_SYNTAX_OPAQUE; };
+
+  /**
+   * Construct a OpaqueStr from another OpaqueStr.
+   * The OpaqueStr will be valid unless a call to new fails.
+   *
+   * @param opaque - Value for the new object
+   */
+  OpaqueStr(const OpaqueStr& opaque) : OctetStr(opaque)
+    { smival.syntax = sNMP_SYNTAX_OPAQUE; };
+
+  /**
+   * Clone this object.
+   *
+   * @return Pointer to the newly created object (allocated through new).
+   */
+  virtual SnmpSyntax *clone() const { return new OpaqueStr(*this); }
+
+  /**
+   * Return the syntax.
+   *
+   * @return This method always returns sNMP_SYNTAX_OPAQUE.
+   */
+  virtual SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OPAQUE; };
+  
+  /**
+   * Map other SnmpSyntax objects to OpaqueStr.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val) 
+   { return OctetStr::operator=(val); }
+
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // _OCTET_CLS
diff --git a/3rdparty/snmp++/include/snmp_pp/oid.h b/3rdparty/snmp++/include/snmp_pp/oid.h
new file mode 100644 (file)
index 0000000..2767eb7
--- /dev/null
@@ -0,0 +1,457 @@
+/*_############################################################################
+  _## 
+  _##  oid.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+               
+  SNMP++ O I D. H
+
+  OID CLASS DEFINITION
+
+  DESIGN + AUTHOR:   Peter E Mellquist
+
+  DESCRIPTION:
+  This class is fully contained and does not rely on or any other
+  SNMP libraries. This class is portable across any platform
+  which supports C++.
+
+=====================================================================*/
+// $Id: oid.h 1775 2010-07-11 09:59:28Z katz $
+
+#ifndef _OID_H_
+#define _OID_H_
+
+//------------------------------------------------------------------------
+
+#include "snmp_pp/smival.h"                // derived class for all values
+#include "snmp_pp/collect.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+/**
+ * The Object Identifier Class.
+ *
+ * The Object Identification (Oid) class is the encapsulation of an
+ * SMI object identifier. The SMI object is a data identifier for a
+ * data element found in a Management Information Base (MIB), as
+ * defined by a MIB definition. The SMI Oid, its related structures
+ * and functions, are a natural fit for object orientation. In fact,
+ * the Oid class shares many common features to the C++ String
+ * class. For those of you familiar with the C++ String class or
+ * Microsoft's Foundation Classes (MFC) CString class, the Oid class
+ * will be familiar and easy to use. The Oid class is designed to be
+ * efficient and fast. The Oid class allows definition and
+ * manipulation of object identifiers. 
+ *
+ * @note Oid holds two internal buffers for get_printable() functions.
+ *       The buffer returned by get_printable() is valid until the
+ *       Oid object is modified. The functions get_printable(len) and
+ *       get_printable(start, len) share the same buffer which is
+ *       freed and newly allocated for each call.
+ */
+class DLLOPT Oid : public SnmpSyntax
+{
+ public:
+
+  /**
+   * Construct an invalid Oid.
+   */
+  Oid();
+
+  /**
+   * Construct an Oid from a string.
+   *
+   * Depending on the second param, the oid_string can either be
+   * - a dotted oid string (like "1.3.6.1.6"). An arbitrary part
+   *   of the oid can be given as a string value enclosed in
+   *   '$' characters. For example the oid string
+   *   "1.3.6.1.6.1.12.1.3.$public0$" will result to the oid
+   *   1.3.6.1.6.1.12.1.3.112.117.98.108.105.99.95.48
+   * - a normal string (like "public"). The Oid will have the
+   *   ASCII values of the string characters. So "public" will
+   *   result to the oid 112.117.98.108.105.99
+   * 
+   * @param oid_string - for example "1.3.1.6.1.10"
+   * @param is_dotted_oid_string - Select format within oid_string
+   */
+  Oid(const char *oid_string, const bool is_dotted_oid_string = true);
+
+  /**
+   * Constructor using another oid object (copy constructor).
+   *
+   * @param oid - Source Oid
+   */
+  Oid(const Oid &oid);
+
+  /**
+   * Constructor from array.
+   *
+   * @param raw_oid - array of oid values
+   * @param oid_len - length of array
+   */
+  Oid(const unsigned long *raw_oid, int oid_len);
+
+  /**
+   * Destructor.
+   */
+  virtual ~Oid();
+
+  /**
+   * Return the current syntax.
+   *
+   * @return always sNMP_SYNTAX_OID
+   */
+  SmiUINT32 get_syntax() const { return sNMP_SYNTAX_OID; };
+
+  /**
+   * Assignment from a string.
+   *
+   * @param dotted_oid_string - New value (for example "1.3.6.1.6.0");
+   */
+  virtual Oid& operator=(const char *dotted_oid_string);
+
+  /**
+   * Assign one Oid to another.
+   */
+  virtual Oid& operator=(const Oid &oid);
+
+  /**
+   * Return the space needed for serialization.
+   */
+  int get_asn1_length() const;
+
+  /**
+   * Overloaded equal operator.
+   */
+  DLLOPT friend int operator==(const Oid &lhs, const Oid &rhs);
+
+  /**
+   * Overloaded not equal operator.
+   */
+  DLLOPT friend int operator!=(const Oid &lhs, const Oid &rhs)
+      { return (!(lhs == rhs)); };  // just invert ==
+
+  /**
+   * Overloaded less than < operator.
+   */
+  DLLOPT friend int operator<(const Oid &lhs, const Oid &rhs);
+
+  /**
+   * Overloaded less than <= operator.
+   */
+  DLLOPT friend int operator<=(const Oid &lhs, const Oid &rhs)
+      { return ((lhs < rhs) || (lhs == rhs)); };
+
+  /**
+   * Overloaded greater than > operator.
+   */
+  DLLOPT friend int operator>(const Oid &lhs, const Oid &rhs)
+      { return (!(lhs <= rhs)); };  // just invert existing <=
+
+  /**
+   * Overloaded greater than >= operator.
+   */
+  DLLOPT friend int operator>=(const Oid &lhs, const Oid &rhs)
+      { return (!(lhs < rhs)); };  // just invert existing <
+
+  /**
+   * Overloaded equal operator operator.
+   */
+  DLLOPT friend int operator==(const Oid &lhs, const char *rhs);
+
+  /**
+   * Overloaded not equal operator.
+   */
+  DLLOPT friend int operator!=(const Oid &lhs, const char *rhs);
+
+  /**
+   * Overloaded less than < operator.
+   */
+  DLLOPT friend int operator<(const Oid &lhs, const char *rhs);
+
+  /**
+   * Overloaded less than <= operator.
+   */
+  DLLOPT friend int operator<=(const Oid &lhs, char *rhs);
+
+  /**
+   * Overloaded greater than > operator.
+   */
+  DLLOPT friend int operator>(const Oid &lhs, const char *rhs);
+
+  /**
+   * Overloaded greater than >= operator.
+   */
+  DLLOPT friend int operator>=(const Oid &lhs, const char *rhs);
+
+  /**
+   * Overloaded operator +, Concatenate two Oids.
+   */
+  DLLOPT friend Oid operator +(const Oid &lhs, const Oid &rhs)
+    { Oid tmp(lhs); tmp += rhs; return tmp;};
+
+  /**
+   * Append operator, appends the dotted oid string.
+   *
+   * @param a - dotted oid string, for example "5.192.14.6"
+   */
+  Oid& operator+=(const char *a);
+
+  /**
+   * Appends an int.
+   *
+   * @param i - Value to add at the end of the Oid
+   */
+  Oid& operator+=(const unsigned long i);
+
+  /**
+   * Appends an Oid.
+   *
+   * @param o - Oid to add at the end
+   */
+  Oid& operator+=(const Oid &o);
+
+  /**
+   * Allows element access as an array.
+   * This method behaves like real array: if your index
+   * is out of bounds, you're lost!
+   *
+   * @param index - valid index -- 0 to (len() - 1)
+   *
+   * @return Value on the given index
+   */
+  unsigned long &operator[](const unsigned int index)
+    { m_changed = true; return smival.value.oid.ptr[index]; };
+
+  /**
+   * Allows element access as an array for const objects.
+   * This method behaves like real array: if your index
+   * is out of bounds, you're lost!
+   *
+   * @param index - valid index -- 0 to (len() - 1)
+   *
+   * @return Value on the given position
+   */
+  unsigned long operator[](const unsigned int index) const
+    { return (index >= len()) ? 0 : smival.value.oid.ptr[index]; };
+
+  /**
+   * Get the WinSnmp oid part.
+   * @note This method returns a pointer to internal data.
+   *       If it is modified, the Oid changes too.
+   *
+   * @return pointer to the internal oid structure.
+   */
+  SmiLPOID oidval() { return (SmiLPOID) &smival.value.oid; };
+
+  /**
+   * Set the data from raw form.
+   *
+   * @param raw_oid - Array of new values
+   * @param oid_len - Length of the array raw_oid
+   */
+  void set_data(const unsigned long *raw_oid, const unsigned int oid_len);
+
+  /**
+   * Set the data from raw form.
+   *
+   * @param str     - Array of new values (a string)
+   * @param str_len - Length of the array raw_oid
+   */
+  void set_data(const char *str, const unsigned int str_len);
+
+  /**
+   * Get the length of the oid.
+   */
+  unsigned long len() const { return smival.value.oid.len; };
+
+  /**
+   * Trim off the rightmost values of an oid.
+   *
+   * @param n - Trim off n values from the right (default is one)
+   */
+  void trim(const unsigned long n = 1);
+
+  /**
+   * Compare two Oids from the left in direction left-to-right.
+   *
+   * @param n - Subvalues to compare
+   * @param o - The Oid to compare with
+   *
+   * @return 0 if equal / -1 if less / 1 if greater
+   */
+  int nCompare(const unsigned long n, const Oid &o) const;
+
+  /**
+   * Return validity of the object.
+   */
+  bool valid() const { return (smival.value.oid.ptr ? true : false); };
+
+  /**
+   * Get a printable ASCII string of the whole value.
+   *
+   * @return Dotted oid string (for example "1.3.6.1.6.0")
+   */
+  const char *get_printable() const
+    { return get_printable(1, smival.value.oid.len, (char*&)iv_str); };
+
+  /**
+   * Get a printable ASCII string of the right part of the value.
+   *
+   * @param n - positions to print, counted from right.
+   *
+   * @return Dotted oid string (for example "6.0")
+   */
+  const char *get_printable(const unsigned long n) const
+    { return get_printable(smival.value.oid.len - n + 1, n, (char*&)iv_part_str); };
+
+  /**
+   * Get a printable ASCII string of a part of the value.
+   *
+   * @param start - First position to print, starting with 1 (not zero!)
+   * @param n - positions to print.
+   * @param buffer - pointer to the returned buffer
+   *
+   * @note If buffer is not NULL, this function calls "delete [] buffer",
+   *       a new buffer is allocated using "new" and the caller has
+   *       to delete it.
+   *
+   * @return Dotted oid string (for example "3.6.1.6")
+   */
+  const char *get_printable(const unsigned long start,
+                           const unsigned long n,
+                           char *&buffer) const;
+
+  /**
+   * Get a printable ASCII string of a part of the value.
+   *
+   * @param start - First position to print, starting with 1 (not zero!)
+   * @param n - positions to print.
+   *
+   * @return Dotted oid string (for example "3.6.1.6")
+   */
+  const char *get_printable(const unsigned long start,
+                           const unsigned long n) const
+    { return get_printable(start, n, (char*&)iv_part_str); };
+
+  /**
+   * Clone this object.
+   *
+   * @return Pointer to the newly created object (allocated through new).
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *) new Oid(*this); };
+
+  /**
+   * Map other SnmpSyntax objects to Oid.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  /**
+   * Clear the Oid.
+   */
+  void clear() { delete_oid_ptr(); };
+
+ protected:
+  /**
+   * Convert a string to an smi oid.
+   *
+   * @param string - input string
+   * @param dstOid - destination oid
+   */
+  virtual int StrToOid(const char *string, SmiLPOID dstOid) const;
+
+  /**
+   * Clone an smi oid.
+   *
+   * @param srcOid - source oid
+   * @param dstOid - destination oid
+   */
+  virtual int OidCopy(SmiLPOID srcOid, SmiLPOID dstOid) const;
+
+  /**
+   * Convert an smi oid to its string representation.
+   *
+   * @param srcOid - source oid
+   * @param size   - size of string
+   * @param string - pointer to string
+   */
+  virtual int OidToStr(const SmiOID *srcOid,
+                      SmiUINT32 size,
+                      char *string) const;
+
+  /**
+   * Free the internal oid pointer and set the pointer and the length to zero.
+   */
+  inline void delete_oid_ptr();
+
+  //----[ instance variables ]
+
+  SNMP_PP_MUTABLE char *iv_str;      // used for returning complete oid string
+  SNMP_PP_MUTABLE char *iv_part_str; // used for returning part oid string
+  SNMP_PP_MUTABLE bool m_changed;
+};
+
+//-----------[ End Oid Class ]-------------------------------------
+
+// create OidCollection type
+typedef SnmpCollection <Oid> OidCollection;
+
+inline void Oid::delete_oid_ptr()
+{
+  // delete the old value
+  if (smival.value.oid.ptr)
+  {
+    delete [] smival.value.oid.ptr;
+    smival.value.oid.ptr = 0;
+  }
+  smival.value.oid.len = 0;
+  m_changed = true;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif //_OID_H_
diff --git a/3rdparty/snmp++/include/snmp_pp/oid_def.h b/3rdparty/snmp++/include/snmp_pp/oid_def.h
new file mode 100644 (file)
index 0000000..49ed3fb
--- /dev/null
@@ -0,0 +1,118 @@
+/*_############################################################################
+  _## 
+  _##  oid_def.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+      SNMP++ O I D _ D E F . H
+
+      OID_DEF DEFINITIONS
+
+      DESCRIPTION:
+        Some common Oid definitions.
+
+      DESIGN + AUTHOR:        Peter E Mellquist
+=====================================================================*/
+// $Id: oid_def.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _OID_DEF
+#define _OID_DEF
+
+#include "snmp_pp/oid.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+/** SMI trap oid def */
+class snmpTrapsOid: public Oid {
+ public:
+  DLLOPT snmpTrapsOid() : Oid("1.3.6.1.6.3.1.1.5") {};
+};
+
+/** SMI Enterprose Oid */
+class snmpTrapEnterpriseOid: public Oid {
+ public:
+  DLLOPT snmpTrapEnterpriseOid() : Oid("1.3.6.1.6.3.1.1.4.3.0") {};
+};
+
+/** SMI Cold Start Oid */
+class coldStartOid: public snmpTrapsOid {
+   public:
+   DLLOPT coldStartOid() { *this+=".1"; };
+};
+
+/** SMI WarmStart Oid */
+class warmStartOid: public snmpTrapsOid {
+   public:
+   DLLOPT warmStartOid() { *this+=".2"; };
+};
+
+/** SMI LinkDown Oid */
+class linkDownOid: public snmpTrapsOid {
+   public:
+   DLLOPT linkDownOid() { *this+=".3"; };
+};
+
+/** SMI LinkUp Oid */
+class linkUpOid: public snmpTrapsOid {
+   public:
+   DLLOPT linkUpOid() { *this+=".4"; };
+};
+
+/** SMI Authentication Failure Oid */
+class authenticationFailureOid: public snmpTrapsOid {
+   public:
+   DLLOPT authenticationFailureOid() { *this+=".5"; };
+};
+
+/** SMI egpneighborloss Oid */
+class egpNeighborLossOid: public snmpTrapsOid {
+ public:
+  DLLOPT egpNeighborLossOid() { *this+=".6"; };
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // _OID_DEF
diff --git a/3rdparty/snmp++/include/snmp_pp/pdu.h b/3rdparty/snmp++/include/snmp_pp/pdu.h
new file mode 100644 (file)
index 0000000..fd7ec6f
--- /dev/null
@@ -0,0 +1,527 @@
+/*_############################################################################
+  _## 
+  _##  pdu.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+               
+  SNMP++ P D U . H
+
+  PDU CLASS DEFINITION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  Pdu class definition. Encapsulation of an SMI Protocol
+  Data Unit (PDU) in C++.
+
+=====================================================================*/
+// $Id: pdu.h 288 2007-03-22 22:37:09Z katz $
+
+#ifndef _PDU_CLS
+#define _PDU_CLS
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/address.h"
+#include "snmp_pp/timetick.h"
+#include "snmp_pp/octet.h"
+#include "snmp_pp/oid.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class Vb;
+
+#define PDU_MAX_RID 32767         ///< max request id to use
+#define PDU_MIN_RID 1000          ///< min request id to use
+
+//=======================================================================
+//                  Pdu Class
+//=======================================================================
+/**
+ * Pdu class...
+ */
+class DLLOPT Pdu
+{
+ public:
+
+  /**
+   * Constructor no args.
+   *
+   * This constructor creates a valid empty Pdu object.
+   */
+  Pdu();
+
+  /**
+   * Constructor with vbs.
+   *
+   * The Pdu class does not take ownership of the array and the Vb
+   * objects, so if these were allocated with new, they must be freed
+   * by te user with delete.
+   *
+   * @param pvbs      - Array of pointers to Vb objects
+   * @param pvb_count - Length of the array
+   */
+  Pdu(Vb* pvbs, const int pvb_count);
+
+  /**
+   * Constructor with another Pdu instance.
+   *
+   * @param pdu - source pdu object
+   */
+  Pdu(const Pdu &pdu) : vbs(0), vbs_size(0), vb_count(0) { *this = pdu; };
+
+  /**
+   * Destructor
+   */
+  virtual ~Pdu();
+
+  /**
+   * Overloaded assignment operator.
+   *
+   * @param pdu - Pdu that should be assigned to this object
+   */
+  Pdu& operator=(const Pdu &pdu);
+
+  /**
+   * Append a vb to the pdu.
+   *
+   * @param vb - The Vb that should be added (as last vb) to the pdu
+   */
+  Pdu& operator+=(const Vb &vb);
+
+  /**
+   * Clone a Pdu object.
+   *
+   * @return Pointer to a newly created Pdu object, that is identical to this
+   */
+  Pdu *clone() const { return new Pdu(*this); };
+
+  /**
+   * Get Pointers to all Vbs from Pdu.
+   *
+   * The caller has to allocate the array. The returned pointers point
+   * to the Vb objects that are internally used by the pdu. So any
+   * changes to the returned Vb objects will change the pdu. If the
+   * pdu is modified (e.g. through Pdu::trim()) afterwards, the
+   * returned array will contain invalid pointers.
+   *
+   * @param pvbs - Array of empty pointers of size pvb_count
+   * @param pvb_count - Amount of Vb pointers to get
+   *
+   * @return TRUE on success
+   */
+  int get_vblist(Vb* pvbs, const int pvb_count) const;
+
+  /**
+   * Deposit all Vbs to Pdu.
+   *
+   * The vb objects of the pdu will be freed and the objects from the
+   * array will be cloned and added to the pdu. If this method returns
+   * FALSE, the pdu will not conatin any Vb objects.
+   *
+   * @param pvbs - Array of valid pointers of size pvb_count
+   * @param pvb_count - Amount of Vb pointers i the array
+   *
+   * @return TRUE on success
+   */
+  int set_vblist(Vb* pvbs, const int pvb_count);
+
+  /**
+   * Get a particular Vb.
+   *
+   * @param vb - Object to store the vb
+   * @param index - The vb to get (zero is the first vb)
+   *
+   * @return TRUE on success
+   */
+  int get_vb(Vb &vb, const int index) const;
+
+  /**
+   * Return a reference to a particular Vb.
+   *
+   * @note Before calling this method, make sure that there
+   *       is a Vb using get_vb_count().
+   *
+   * @param index - The Vb to return starting with 0.
+   * @return A const reference to the Vb
+   */
+  const Vb &get_vb(const int index) const { return *vbs[index]; };
+
+  /**
+   * Set a particular vb.
+   *
+   * If this method returns FALSE, the pdu has not been modified.
+   *
+   * @param vb - Source vb
+   * @param index - The vb to set (zero is the first vb)
+   *
+   * @return TRUE on success
+   */
+  int set_vb(Vb &vb, const int index);
+
+  /**
+   * Get the number of vbs.
+   *
+   * @return The number of Vb objects within the pdu.
+   */
+  int get_vb_count() const { return vb_count; };
+
+  /**
+   * Get a Vb.
+   *
+   * @note The index has to be checked by the caller.
+   *
+   * @param i zero based index
+   */
+  Vb& operator[](const int i) { return *vbs[i]; };
+
+  /**
+   * Get the error status.
+   *
+   * @return The SNMP error status
+   */
+  int get_error_status() const { return error_status; };
+
+  /**
+   * Set the error status.
+   *
+   * @param err - The new SNMP error status.
+   */
+  void set_error_status(const int err) {  error_status = err; };
+
+  /**
+   * Clear the error status.
+   */
+  void clear_error_status() { error_status = 0; };
+
+  /**
+   * Get the error index.
+   *
+   * @return The SNMP error index
+   */
+  int get_error_index() const { return error_index; };
+
+  /**
+   * Set the error index.
+   *
+   * @param err - The new SNMP error index.
+   */
+  void set_error_index(const int index) { error_index = index; };
+
+  /**
+   * Clear the error index.
+   */
+  void clear_error_index() { error_index = 0; };
+
+  /**
+   * Clear error status and error index.
+   */
+  void clear_error() { set_error_status(0); set_error_index(0); }
+
+  /**
+   * Get the request id.
+   *
+   * @return The SNMP request id
+   */
+  unsigned long get_request_id() const { return request_id; };
+
+  /**
+   * Set the request id.
+   *
+   * @param rid - The new SNMP request id
+   */
+  void set_request_id(const unsigned long rid) { request_id = rid; };
+
+  /**
+   * Get the pdu type.
+   */
+  unsigned short get_type() const { return pdu_type; };
+
+  /**
+   * Set the pdu type.
+   */
+  void set_type(unsigned short type) { pdu_type = type; };
+
+  /**
+   * Returns validity of Pdu instance.
+   */
+  bool valid() const { return validity; };
+
+  /**
+   * Trim off vbs.
+   *
+   * @param count - number of vbs to trim of, starting with the last
+   * @return TRUE on success, FALSE if nothing was done
+   */
+  int trim(const int count=1);
+
+  /**
+   * Delete a Vb anywhere within the Pdu.
+   *
+   * @param position - Delete the Vb at this position (starting with 0)
+   * @return TRUE on success
+   */
+  int delete_vb(const int position);
+
+  /**
+   * Set notify timestamp.
+   */
+  void set_notify_timestamp(const TimeTicks &ts) { notify_timestamp = ts; };
+
+  /**
+   * Get notify timestamp.
+   */
+  void get_notify_timestamp(TimeTicks &ts) const { ts = notify_timestamp; };
+
+  /**
+   * Set the notify id.
+   *
+   * @return true if the set succeeded.
+   */
+  bool set_notify_id(const Oid &id)
+    { notify_id = id; return (notify_id.len() == id.len()); };
+
+  /**
+   * Get the notify id.
+   *
+   * @return true if the get succeeded.
+   */
+  bool get_notify_id(Oid &id) const
+    { id = notify_id; return (notify_id.len() == id.len()); };
+
+  /**
+   * Set the notify enterprise.
+   *
+   * @return true if the set succeeded.
+   */
+  bool set_notify_enterprise(const Oid &e)
+    { notify_enterprise = e; return (notify_enterprise.len() == e.len()); };
+
+  /**
+   * Get the notify enterprise.
+   *
+   * @return true if the get succeeded.
+   */
+  bool get_notify_enterprise(Oid & e) const
+    { e = notify_enterprise;  return (notify_enterprise.len() == e.len()); };
+
+#ifdef _SNMPv3
+  /**
+   * Set the security level that should be used when this Pdu is sent.
+   * The default security level of a Pdu is SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV.
+   *
+   * @param level - One of SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV,
+   *                SNMP_SECURITY_LEVEL_AUTH_NOPRIV,
+   *                SNMP_SECURITY_LEVEL_AUTH_PRIV
+   */
+  void set_security_level(const int level) { security_level = level; };
+
+  /**
+   * Return the security level of the Pdu.
+   *
+   * @return - the security level
+   */
+  int get_security_level() const { return security_level; };
+
+  /**
+   * Set the context name of the Pdu.
+   *
+   * @param name - The context name
+   */
+  bool set_context_name(const OctetStr &name)
+    { context_name = name; return (context_name.valid() && name.valid()); };
+
+  /**
+   * Set the context name of the Pdu.
+   *
+   * @param name - The context name
+   */
+  bool set_context_name(const char *name)
+    { context_name = name; return context_name.valid(); };
+
+  /**
+   * Get the context name of the Pdu.
+   *
+   * @param name - Object fot the context name
+   */
+  bool get_context_name(OctetStr &name) const
+    { name = context_name; return (context_name.valid() && name.valid()); };
+
+  /**
+   * Get the context name of the Pdu.
+   *
+   * @return - Return the context name as an OctetStr
+   */
+  const OctetStr& get_context_name() const { return context_name; };
+
+  /**
+   * Set the context engine id of the Pdu.
+   *
+   * @param id - The new context engine id
+   */
+  bool set_context_engine_id(const OctetStr &id) { context_engine_id = id;
+    return (context_engine_id.valid() && id.valid()); };
+
+  /**
+   * Set the context engine id of the Pdu.
+   *
+   * @param id - The new context engine id
+   */
+  bool set_context_engine_id(const char *id)
+    { context_engine_id = id; return context_engine_id.valid(); };
+
+  /**
+   * Get the context engine id of the Pdu.
+   *
+   * @param id - Object for the context engine
+   */
+  bool get_context_engine_id(OctetStr &id) const { id = context_engine_id;
+    return (context_engine_id.valid() && id.valid()); };
+
+  /**
+   * Get the context engine id of the Pdu.
+   *
+   * @return - Return the context engine id as an OctetStr
+   */
+  const OctetStr& get_context_engine_id() const { return context_engine_id; };
+
+  /**
+   * Set the SNMPv3 message id (msgID)
+   *
+   * @param msg_id - the message id of the received message
+   */
+  void set_message_id(const unsigned long msg_id) { message_id = msg_id; }
+
+  /**
+   * Get the SNMPv3 message id (msgID)
+   *
+   * @return - the message id of the received message
+   */
+  unsigned long get_message_id() const { return message_id; }
+
+  /**
+   * Set the maximum size of the scoped pdu to be included in a
+   * possible response message.
+   *
+   * @param l - the maximum size
+   */
+  void set_maxsize_scopedpdu(unsigned long l) { maxsize_scopedpdu = l; };
+
+  /**
+   * Get the maximum size of the scoped pdu to be included in a
+   * possible response message.
+   *
+   * @return - the maximum size
+   */
+  unsigned long get_maxsize_scopedpdu() const { return maxsize_scopedpdu; };
+
+#endif // _SNMPv3
+
+  /**
+   * Get the SNMPv1 trap address
+   */
+  int get_v1_trap_address(GenAddress &address) const;
+
+  /**
+   * Set the SNMPv1 trap address
+   */
+  int set_v1_trap_address(const Address &address);
+
+  /**
+   * Return the length of the encoded vbs with pdu header.
+   *
+   * @note this method wll not work for v1 traps.
+   */
+  int get_asn1_length() const;
+
+  /**
+   * Clear the Pdu contents (destruct and construct in one go)
+   */
+  void clear();
+
+  /**
+   * Does the type of response match the type of request.
+   */
+  static bool match_type(const int request, const int response);
+
+  //-------------[ protected members ]--------------------------
+ protected:
+
+  /**
+   * Extend the vbs array.
+   *
+   * @return true on success
+   */
+  bool extend_vbs();
+
+  Vb **vbs;                    // pointer to array of Vbs
+  int vbs_size;                // Size of array
+  int vb_count;                // count of Vbs
+  int error_status;            // SMI error status
+  int error_index;             // SMI error index
+  bool validity;               // valid boolean
+  unsigned long request_id;     // SMI request id
+  unsigned short pdu_type;      // derived at run time based on request type
+  // for notify Pdu objects only
+  // traps & notifies
+  TimeTicks notify_timestamp;      // a timestamp associated with an infor
+  Oid notify_id;                   // an id
+  Oid notify_enterprise;
+  GenAddress v1_trap_address;      // address object
+  int        v1_trap_address_set;
+#ifdef _SNMPv3
+  // specific Objects for SNMPv3
+  int security_level;            // the securityLevel with which this Pdu
+                                 // should be sent or was received
+  unsigned long message_id;
+  unsigned long maxsize_scopedpdu;
+  OctetStr context_name;
+  OctetStr context_engine_id;
+#endif // _SNMPv3
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif //_PDU_CLS
diff --git a/3rdparty/snmp++/include/snmp_pp/reentrant.h b/3rdparty/snmp++/include/snmp_pp/reentrant.h
new file mode 100644 (file)
index 0000000..6f35454
--- /dev/null
@@ -0,0 +1,87 @@
+/*_############################################################################
+  _## 
+  _##  reentrant.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+// $Id: reentrant.h 307 2007-09-14 20:01:45Z katz $
+
+#ifndef _reentrant_h_
+#define _reentrant_h_
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/smi.h"
+
+#ifdef _THREADS
+#ifdef WIN32
+#include <process.h>
+#elif defined (CPU) && CPU == PPC603
+#include <semLib.h> 
+#else
+#include <pthread.h>
+#endif
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class DLLOPT SnmpSynchronized {
+
+ public:
+  SnmpSynchronized();
+  virtual ~SnmpSynchronized();
+#ifdef _THREADS
+#ifdef WIN32
+  CRITICAL_SECTION      _mutex;
+#elif defined (CPU) && CPU == PPC603
+  SEM_ID               _mutex;
+#else
+  pthread_mutex_t              _mutex;
+#endif
+#endif
+  void lock();
+  void unlock();
+};
+
+class DLLOPT SnmpSynchronize {
+
+ public:
+  SnmpSynchronize(SnmpSynchronized& sync) : s(sync) { s.lock(); };
+  ~SnmpSynchronize() { s.unlock(); }
+
+ protected:
+  SnmpSynchronized& s;
+
+};
+
+#define REENTRANT(x) { SnmpSynchronize _synchronize(*this); x }
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif
+
diff --git a/3rdparty/snmp++/include/snmp_pp/sha.h b/3rdparty/snmp++/include/snmp_pp/sha.h
new file mode 100644 (file)
index 0000000..2e8d289
--- /dev/null
@@ -0,0 +1,70 @@
+/*_############################################################################
+  _## 
+  _##  sha.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
+// $Id: sha.h 288 2007-03-22 22:37:09Z katz $
+/****************************************************************
+ * SHS.h  -  Secure Hash Standard (draft) FIPS 180-1            *
+ *                                                              *
+ * Copyright (C) 1994  Uri Blumenthal, uri@watson.ibm.com       *
+ * Copyright (C) 1994  IBM T. J. Watson esearch Center          *
+ *                                                              *
+ * Feel free to use this code, as long as you acknowledge the   *
+ * ownership by U. Blumenthal and IBM Corp. and agree to hold   *
+ * both harmless in case of ANY problem you may have with this  *
+ * code.                                                        *
+ ****************************************************************/
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+typedef struct {
+  /* Message Digest words */
+  unsigned long int h[5];
+  /* Message length in bits */
+  unsigned long int count[2];
+  /* Current byte position in not-full-yet buf */
+  int index;
+  /* Buffer for the remainder of bytes mod 64 */
+  unsigned char X[64];
+} SHA_CTX;
+
+DLLOPT void SHAInit(SHA_CTX *ctx);
+DLLOPT void SHAUpdate(SHA_CTX *ctx, const unsigned char *buf, unsigned int lenBuf);
+DLLOPT void SHAFinal(unsigned char *digest, SHA_CTX *ctx);
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
diff --git a/3rdparty/snmp++/include/snmp_pp/smi.h b/3rdparty/snmp++/include/snmp_pp/smi.h
new file mode 100644 (file)
index 0000000..8f076e9
--- /dev/null
@@ -0,0 +1,212 @@
+/*_############################################################################
+  _## 
+  _##  smi.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++ S M I . H
+
+  SMI DEFINITIONS
+
+  AUTHOR:           Peter E Mellquist
+=====================================================================*/
+// $Id: smi.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _SMIDEF
+#define _SMIDEF
+
+// make sure configuration is included first
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define WINFAR
+#define STRCAT strcat
+#define STRLEN strlen
+#define MEMCPY memcpy
+#define STRCPY strcpy
+#define MEMCMP memcmp
+#define XPORT
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+//----------[ ASN/BER Base Types ]-----------------------------------------
+/** @name ASN/BER Base Types
+ *
+ * Basic Encoding Rules (BER) (used in forming SYNTAXes and certain
+ * SNMP types/values).
+ */
+//@{
+#define aSN_UNIVERSAL    (0x00)
+#define aSN_APPLICATION  (0x40)
+#define aSN_CONTEXT      (0x80)
+#define aSN_PRIVATE      (0xC0)
+#define aSN_PRIMITIVE    (0x00)
+#define aSN_CONSTRUCTOR  (0x20)
+//@}
+
+//------[ SNMP ObjectSyntax Values ]---------------------------------------
+#define sNMP_SYNTAX_SEQUENCE  (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x10)
+
+/** @name Syntax Types
+ *
+ * These values are used in the "syntax" member of the smiVALUE
+ * structure which follows.
+ *
+ * The get_syntax() method of any class derived from SnmpSyntax returns
+ * one of these values.
+ *
+ * @note UInt32 is indistinguishable from Gauge32 per SNMPv2 Draft Standard
+ * @note NsapAddr is obsoleted as unique SMI type per SNMPv2 Draft Standard
+ */
+//@{
+#define sNMP_SYNTAX_INT                (aSN_UNIVERSAL | aSN_PRIMITIVE | 0x02)
+#define sNMP_SYNTAX_BITS       (aSN_UNIVERSAL | aSN_PRIMITIVE | 0x03)
+#define sNMP_SYNTAX_OCTETS     (aSN_UNIVERSAL | aSN_PRIMITIVE | 0x04)
+#define sNMP_SYNTAX_NULL       (aSN_UNIVERSAL | aSN_PRIMITIVE | 0x05)
+#define sNMP_SYNTAX_OID                (aSN_UNIVERSAL | aSN_PRIMITIVE | 0x06)
+#define sNMP_SYNTAX_INT32      sNMP_SYNTAX_INT
+#define sNMP_SYNTAX_IPADDR     (aSN_APPLICATION | aSN_PRIMITIVE | 0x00)
+#define sNMP_SYNTAX_CNTR32     (aSN_APPLICATION | aSN_PRIMITIVE | 0x01)
+#define sNMP_SYNTAX_GAUGE32    (aSN_APPLICATION | aSN_PRIMITIVE | 0x02)
+#define sNMP_SYNTAX_TIMETICKS  (aSN_APPLICATION | aSN_PRIMITIVE | 0x03)
+#define sNMP_SYNTAX_OPAQUE     (aSN_APPLICATION | aSN_PRIMITIVE | 0x04)
+#define sNMP_SYNTAX_CNTR64     (aSN_APPLICATION | aSN_PRIMITIVE | 0x06)
+#define sNMP_SYNTAX_UINT32     sNMP_SYNTAX_GAUGE32
+//@}
+
+//-------------------------------------------------------------------------
+
+//---------------[ Exception conditions for SNMPv2 ]-----------------------
+/** @name Exception conditions for SNMPv2 */
+//@{
+#define sNMP_SYNTAX_NOSUCHOBJECT    (aSN_CONTEXT | aSN_PRIMITIVE | 0x00)
+#define sNMP_SYNTAX_NOSUCHINSTANCE  (aSN_CONTEXT | aSN_PRIMITIVE | 0x01)
+#define sNMP_SYNTAX_ENDOFMIBVIEW    (aSN_CONTEXT | aSN_PRIMITIVE | 0x02)
+//@}
+
+//--------------[ different types of PDU's ]-------------------------------
+/** @name Pdu types */
+//@{
+#define sNMP_PDU_GET       (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x0)
+#define sNMP_PDU_GETNEXT    (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x1)
+#define sNMP_PDU_RESPONSE   (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x2)
+#define sNMP_PDU_SET       (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x3)
+#define sNMP_PDU_V1TRAP     (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x4)
+#define sNMP_PDU_GETBULK    (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x5)
+#define sNMP_PDU_INFORM     (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x6)
+#define sNMP_PDU_TRAP       (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x7)
+#define sNMP_PDU_REPORT     (aSN_CONTEXT | aSN_CONSTRUCTOR | 0x8)
+//@}
+
+
+//------[ smi typedefs ]---------------------------------------------------
+/** @name SMI typedefs
+ *
+ * SNMP-related types from RFC1442 (SMI).
+ */
+//@{
+
+// byte
+typedef unsigned char    SmiBYTE,       WINFAR *SmiLPBYTE;
+
+// int
+typedef long             SmiINT,        WINFAR *SmiLPINT;
+
+// int 32
+typedef SmiINT           SmiINT32,      WINFAR *SmiLPINT32;
+
+// unit32
+typedef unsigned long    SmiUINT32,     WINFAR *SmiLPUINT32;
+
+// octet struct
+typedef struct {
+     SmiUINT32 len;
+     SmiLPBYTE ptr;}     SmiOCTETS,     WINFAR *SmiLPOCTETS;
+
+// bits
+typedef SmiOCTETS        SmiBITS,       WINFAR *SmiLPBITS;
+
+// SMI oid struct
+typedef struct {
+     SmiUINT32   len;
+     SmiLPUINT32 ptr;}   SmiOID,        WINFAR *SmiLPOID;
+
+// ipaddr
+typedef SmiOCTETS        SmiIPADDR,     WINFAR *SmiLPIPADDR;
+
+// 32bit counter
+typedef SmiUINT32        SmiCNTR32,     WINFAR *SmiLPCNTR32;
+
+// gauge
+typedef SmiUINT32        SmiGAUGE32,    WINFAR *SmiLPGAUGE32;
+
+// timeticks
+typedef SmiUINT32        SmiTIMETICKS,  WINFAR *SmiLPTIMETICKS;
+
+// opaque
+typedef SmiOCTETS        SmiOPAQUE,     WINFAR *SmiLPOPAQUE;
+
+// nsapaddr
+typedef SmiOCTETS        SmiNSAPADDR,   WINFAR *SmiLPNSAPADDR;
+
+// 64 bit counter
+typedef struct {
+        SmiUINT32 hipart;
+        SmiUINT32 lopart;} SmiCNTR64,   WINFAR *SmiLPCNTR64;
+//@}
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif
+
+
diff --git a/3rdparty/snmp++/include/snmp_pp/smival.h b/3rdparty/snmp++/include/snmp_pp/smival.h
new file mode 100644 (file)
index 0000000..c0807cc
--- /dev/null
@@ -0,0 +1,178 @@
+/*_############################################################################
+  _## 
+  _##  smival.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++ S M I V A L . H
+
+  SMIVALUE CLASS DEFINITION
+
+  DESIGN + AUTHOR: Jeff Meyer
+
+  DESCRIPTION:
+  SMIValue class definition. Superclass for the various types
+  of SNMP values (Address, Oid, Octet, etc.).  Provides
+  only a few functions, most info is in subclass.
+
+=====================================================================*/
+// $Id: smival.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _SMIVALUE
+#define _SMIVALUE
+
+//----[ includes ]-----------------------------------------------------
+#include "snmp_pp/smi.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+//----[ macros ]-------------------------------------------------------
+#if defined(USE_CPP_CASTS)
+#define PP_CONST_CAST(___type, ___ptr)    const_cast< ___type >(___ptr)
+#else
+#define PP_CONST_CAST(___type, ___ptr)    ((___type)(___ptr))
+#endif
+
+//======================================================================
+// SMI value structure conforming with SMI RFC
+//
+typedef struct {               /* smiVALUE portion of VarBind */
+         SmiUINT32 syntax;     /* Insert SNMP_SYNTAX_<type> */
+        union  {
+          SmiINT    sNumber;    /* SNMP_SYNTAX_INT
+                                   SNMP_SYNTAX_INT32 */
+          SmiUINT32 uNumber;    /* SNMP_SYNTAX_UINT32
+                                   SNMP_SYNTAX_CNTR32
+                                   SNMP_SYNTAX_GAUGE32
+                                   SNMP_SYNTAX_TIMETICKS */
+          SmiCNTR64 hNumber;    /* SNMP_SYNTAX_CNTR64 */
+          SmiOCTETS string;     /* SNMP_SYNTAX_OCTETS
+                                   SNMP_SYNTAX_BITS
+                                   SNMP_SYNTAX_OPAQUE
+                                   SNMP_SYNTAX_IPADDR
+                                   SNMP_SYNTAX_NSAPADDR */
+          SmiOID    oid;        /* SNMP_SYNTAX_OID */
+          SmiBYTE   empty;      /* SNMP_SYNTAX_NULL
+                                   SNMP_SYNTAX_NOSUCHOBJECT
+                                   SNMP_SYNTAX_NOSUCHINSTANCE
+                                   SNMP_SYNTAX_ENDOFMIBVIEW */
+                 }   value;
+               }    SmiVALUE, *SmiLPVALUE;
+//=================================================================
+
+//--------------------------------------------------------------------
+//----[ SnmpSyntax class ]--------------------------------------------
+//--------------------------------------------------------------------
+
+/**
+ * An "abstract" (pure virtual) class that serves as the base class
+ * for all specific SNMP syntax types.
+ */
+class DLLOPT SnmpSyntax {
+
+public:
+
+  /**
+   * Virtual function for getting a printable ASCII value for any SNMP
+   * value. 
+   *
+   * @note The returned string is valid as long as the object is not
+   *       modified.
+   * @note This function is NOT thread safe.
+   */
+  virtual const char *get_printable() const = 0;
+
+  /**
+   * Return the current syntax.
+   */
+  virtual SmiUINT32 get_syntax() const = 0;
+
+  /**
+   * Virtual clone operation for creating a new Value from an existing
+   * value. 
+   * 
+   * @note The caller MUST use the delete operation on the return
+   *       value when done.
+   */
+  virtual  SnmpSyntax * clone() const = 0;
+
+  /**
+   * Virtual destructor to ensure deletion of derived classes...
+   */
+  virtual ~SnmpSyntax() {};
+
+  /**
+   * Overloaded assignment operator.
+   *
+   * @note This should be pure virtual, but buggy VC++ compiler
+   *       complains about unresolved reference at link time.
+   */
+  virtual SnmpSyntax& operator=(const SnmpSyntax &/*val*/) { return *this; };
+
+  /**
+   * Return validity of the object.
+   */
+  virtual bool valid() const = 0;
+
+  /**
+   * Return the space needed for serialization.
+   */
+  virtual int get_asn1_length() const = 0;
+
+  /**
+   * Reset the object.
+   */
+  virtual void clear() = 0;
+
+protected:
+
+  SmiVALUE smival;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif  // _SMIVALUE
diff --git a/3rdparty/snmp++/include/snmp_pp/snmp_pp.h b/3rdparty/snmp++/include/snmp_pp/snmp_pp.h
new file mode 100644 (file)
index 0000000..e0f8340
--- /dev/null
@@ -0,0 +1,78 @@
+/*_############################################################################
+  _## 
+  _##  snmp_pp.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+   Copyright (c) 1999
+   Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+   SNMP++ S N M P_PP . H
+
+   SNMP CLASS DEFINITION
+
+  DESIGN + AUTHOR:   Peter E Mellquist
+=====================================================================*/
+// $Id: snmp_pp.h 1685 2009-11-24 13:45:38Z katz $
+
+#ifndef _SNMP_PP_H_
+#define _SNMP_PP_H_
+
+// this is snmp++v3
+#define SNMP_PP_V3
+
+//-----[ snmp++ classes ]------------------------------------------------
+#include "snmp_pp/config_snmp_pp.h"     // config file (SNMPv3)
+#include "snmp_pp/oid.h"                // snmp++ oid class
+#include "snmp_pp/vb.h"                 // snbmp++ vb class
+#include "snmp_pp/target.h"             // snmp++ target class
+#include "snmp_pp/pdu.h"                // snmp++ pdu class
+#include "snmp_pp/snmperrs.h"           // error macros and strings
+#include "snmp_pp/address.h"            // snmp++ address class defs
+#include "snmp_pp/v3.h"                 // SNMPv3
+#include "snmp_pp/mp_v3.h"              // SNMPv3
+#include "snmp_pp/usm_v3.h"             // SNMPv3
+#include "snmp_pp/reentrant.h"
+#include "snmp_pp/uxsnmp.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/msec.h"
+#include "snmp_pp/eventlist.h"
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/log.h"
+
+#endif //_SNMP_PP_H_
diff --git a/3rdparty/snmp++/include/snmp_pp/snmperrs.h b/3rdparty/snmp++/include/snmp_pp/snmperrs.h
new file mode 100644 (file)
index 0000000..bfe4064
--- /dev/null
@@ -0,0 +1,274 @@
+/*_############################################################################
+  _## 
+  _##  snmperrs.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++ S N M P E R R S. H
+
+  SNMP++ ERROR CODE AND STRING DEFINITIONS
+
+  DESCRIPTION:
+  Definition of error macros and error strings
+
+  DESIGN + AUTHOR:  Jeff Meyer
+============================================================================*/
+// $Id: snmperrs.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _SNMPERRS_H
+#define _SNMPERRS_H
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//-------[ Positive SNMP ++ Error Return Codes ]------------------------------
+/** @name Pdu error codes
+ * These values are error status values from RFC 1905
+ *
+ * The values can be returned via Pdu::get_error_status()
+ */
+//@{
+#define SNMP_ERROR_SUCCESS           0 //!< Success Status
+#define SNMP_ERROR_TOO_BIG           1 //!< Pdu encoding too big
+#define SNMP_ERROR_NO_SUCH_NAME             2 //!< No such VB name, see error index
+#define SNMP_ERROR_BAD_VALUE         3 //!< Bad Vb
+#define SNMP_ERROR_READ_ONLY        4 //!< VB is read only, see error index
+#define SNMP_ERROR_GENERAL_VB_ERR    5 //!< General VB error, see error index
+#define SNMP_ERROR_NO_ACCESS         6 //!< No access to MIBs data
+#define SNMP_ERROR_WRONG_TYPE        7 //!< Requested type was incorrect
+#define SNMP_ERROR_WRONG_LENGTH      8 //!< Request Pdu has inccorect length
+#define SNMP_ERROR_WRONG_ENCODING    9 //!< Request Pdu has wrong encoding
+#define SNMP_ERROR_WRONG_VALUE      10 //!< Request Pdu has wrong value
+#define SNMP_ERROR_NO_CREATION      11 //!< Unable to create object specified
+#define SNMP_ERROR_INCONSIST_VAL    12 //!< Inconsistent value in request
+#define SNMP_ERROR_RESOURCE_UNAVAIL 13 //!< Resources unavailable
+#define SNMP_ERROR_COMITFAIL        14 //!< Unable to comit
+#define SNMP_ERROR_UNDO_FAIL        15 //!< Unable to undo
+#define SNMP_ERROR_AUTH_ERR         16 //!< Authorization error
+#define SNMP_ERROR_NOT_WRITEABLE    17 //!< Mib Object not writeable
+#define SNMP_ERROR_INCONSIS_NAME    18 //!< Inconsistent naming used
+//@}
+
+//-------[ Negative SNMP ++ Result/Error Return Codes ]-------------------
+
+/** @name Snmp class return codes
+ */
+//@{
+
+// General
+#define SNMP_CLASS_SUCCESS             0 //!< success
+#define SNMP_CLASS_ERROR              -1 //!< general error
+#define SNMP_CLASS_RESOURCE_UNAVAIL   -2 //!< e.g., malloc failed
+#define SNMP_CLASS_INTERNAL_ERROR     -3 //!< unexpected / internal error
+#define SNMP_CLASS_UNSUPPORTED        -4 //!< unsupported function
+
+// Callback reasons:
+#define SNMP_CLASS_TIMEOUT           -5 //!< outstanding request timed out
+#define SNMP_CLASS_ASYNC_RESPONSE    -6 //!< received response for outstd request
+#define SNMP_CLASS_NOTIFICATION      -7 //!< received notification (trap/inform)
+#define SNMP_CLASS_SESSION_DESTROYED -8 //!< snmp::destroyed with oustanding reqs pending
+                                       
+// Snmp Class:
+#define SNMP_CLASS_INVALID           -10 //!< snmp::mf called on invalid instance
+#define SNMP_CLASS_INVALID_PDU       -11 //!< invalid pdu passed to mf
+#define SNMP_CLASS_INVALID_TARGET    -12 //!< invalid target passed to mf
+#define SNMP_CLASS_INVALID_CALLBACK  -13 //!< invalid callback to mf
+#define SNMP_CLASS_INVALID_REQID     -14 //!< invalid request id to cancel
+#define SNMP_CLASS_INVALID_NOTIFYID  -15 //!< missing trap/inform oid
+#define SNMP_CLASS_INVALID_OPERATION -16 //!< snmp operation not allowed for specified target
+#define SNMP_CLASS_INVALID_OID      -17 //!< invalid oid passed to mf
+#define SNMP_CLASS_INVALID_ADDRESS   -18 //!< invalid address passed to mf
+#define SNMP_CLASS_ERR_STATUS_SET    -19 //!< agent returned response pdu with error_status set
+
+// Transport Errors:
+#define SNMP_CLASS_TL_UNSUPPORTED    -20 //!< transport unsupported
+#define SNMP_CLASS_TL_IN_USE         -21 //!< transport in use
+#define SNMP_CLASS_TL_FAILED         -22 //!< transport operation failed
+#define SNMP_CLASS_TL_ACCESS_DENIED  -23 //!< transport missing rights
+
+// extras
+#define SNMP_CLASS_SHUTDOWN          -24 //!< used for back door shutdown
+
+// ASN.1 parse errors
+#define SNMP_CLASS_BADVERSION        -50 //!< unsupported version
+#define SNMP_CLASS_ASN1ERROR         -51 //!< used for ASN.1 parse errors
+//@}
+
+#define MAX_POS_ERROR                    SNMP_ERROR_INCONSIS_NAME
+#define MAX_NEG_ERROR                    SNMP_CLASS_SHUTDOWN
+
+
+#ifdef _INCLUDE_SNMP_ERR_STRINGS
+
+/**
+ * ASCII strings returned through Snmp::error() function.
+ *
+ * @note altering the strings in this header file will not affect the
+ *       return values of Snmp::error(), unless you rebuild the SNMP++
+ *       library from source.
+ */
+//@{
+static const char * pErrs[] = {
+  "Success",                                                  // 0
+  "SNMP: Response PDU Too Big",                               // 1
+  "SNMP: Variable does not exist",                           // 2
+  "SNMP: Cannot modify variable: Bad Value",                  // 3
+  "SNMP: Cannot modify object, Read Only",                   // 4
+  "SNMP: Cannot perform operation, General Error",            // 5
+  "SNMP: Cannot access variable, No Access",                  // 6
+  "SNMP: Cannot create/modify variable, Wrong Type",          // 7
+  "SNMP: Cannot create/set variable, Wrong Length",           // 8
+  "SNMP: Cannot create/set variable, Wrong Encoding",         // 9
+  "SNMP: Cannot create/set variable, Wrong Value",            // 10
+  "SNMP: Cannot create variable, Creation Not Allowed",       // 11
+  "SNMP: Cannot create/set variable, Inconsistent Value",     // 12
+  "SNMP: Cannot create/set variable, Resource Unavailable",   // 13
+  "SNMP: Cannot create/set variable, Commit Failed",          // 14
+  "SNMP: Cannot create/set variable, Undo Failed",            // 15
+  "SNMP: Cannot perform operation, Authorization Error",      // 16
+  "SNMP: Cannot create/set variable, Not Writable",           // 17
+  "SNMP: Cannot create variable, Inconsistent Name",          // 18
+  "SNMP: Unknown Error Status"                                // 19
+};
+
+#ifdef _SNMPv3
+static const char * nv3Errs[] = {
+  "SNMPv3: v3MP error",                 // -1400
+  "SNMPv3: v3MP ok",                    // -1401
+  "SNMPv3: Unsupported Security Model", // -1402
+  "SNMPv3: Message not in Time Window", // -1403
+  "SNMPv3: received same Message twice",// -1404
+  "SNMPv3: Invalid Message",            // -1405
+  "SNMPv3: Invalid EngineID",           // -1406
+  "SNMPv3: v3MP not initialized",       // -1407
+  "SNMPv3: Parse Error",                // -1408
+  "SNMPv3: Received Message with unknown MsgID",  // -1409
+  "SNMPv3: Message does not match known message", // -1410
+  "SNMPv3: Community format error",     // -1411
+  "SNMPv3: Unknown UserName",           //-1412
+  "SNMPv3: Build error",                //-1413
+  "SNMPv3: USM: error",                 //-1414
+  "SNMPv3: Unknown pdu handlers",       //-1415
+  "SNMPv3: Unavailable Context",        //-1416
+  "SNMPv3: Unknown Context",            //-1417
+  "SNMPv3: Report sent",                //-1418
+  "SNMPv3: Unknown errorcode"
+};
+
+static const char * pv3Errs[] = {
+  "SNMPv3: USM: ok",                          // 1400
+  "SNMPv3: USM: error",                       // 1401
+  "SNMPv3: USM: Configfile write error",      // 1402
+  "SNMPv3: USM: Unsupported SecurityLevel",   // 1403
+  "SNMPv3: USM: Unknown SecurityName",        // 1404
+  "SNMPv3: USM: Encryption error",            // 1405
+  "SNMPv3: USM: Decryption error",            // 1406
+  "SNMPv3: USM: Authentication error",        // 1407
+  "SNMPv3: USM: Authentication failure",      // 1408
+  "SNMPv3: USM: Parse error",                 // 1409
+  "SNMPv3: USM: Unknown EngineID",            // 1410
+  "SNMPv3: USM: Message not in TimeWindow",   // 1411
+  "SNMPv3: USM: Unsupported AuthProtocol",    // 1412
+  "SNMPv3: USM: Unsupported PrivProtocol",    // 1413
+  "SNMPv3: USM: Address error",               // 1414
+  "SNMPv3: USM: Could not create file",       // 1415
+  "SNMPv3: USM: Could not open file",         // 1416
+  "SNMPv3: USM: Could not rename file",       // 1417
+  "SNMPv3: USM: Could not delete file",       // 1418
+  "SNMPv3: USM: Could not write into file",   // 1419
+  "SNMPv3: USM: Could not read from file",    // 1420
+  "SNMPv3: USM: unknown errorcode"
+};
+#endif
+
+static const char * nErrs[] =
+{
+  // General:
+  "SNMP++: Success",                 // 0  SNMP_CLASS_SUCCESS
+  "SNMP++: Operation failed",        // 1  SNMP_CLASS_ERROR
+  "SNMP++: Resource unavailable",    // 2  SNMP_CLASS_RESOURCE_UNAVAIL
+  "SNMP++: Internal error",          // 3  SNMP_CLASS_INTERNAL_ERROR
+  "SNMP++: Unsupported function",    // 4  SNMP_CLASS_UNSUPPORTED
+
+  // Callback reasons:
+  "SNMP++: SNMP request timed out",  // 5  SNMP_CLASS_TIMEOUT
+  "SNMP++: Received SNMP Response",  // 6  SNMP_CLASS_ASYNC_RESPONSE
+                                     // 7  SNMP_CLASS_NOTIFICATION     
+  "SNMP++: Received SNMP Notification (trap or inform)",
+                                     // 8  SNMP_CLASS_SESSION_DESTROYED
+  "SNMP++: Closing session with outstanding requests",
+  "Unknown error code",              // 9  reserved for future
+
+  // Snmp Class errors:
+  "SNMP++: Class not valid",           // 10 SNMP_CLASS_INVALID
+  "SNMP++: Invalid Pdu",               // 11 SNMP_CLASS_INVALID_PDU
+  "SNMP++: Invalid Target",            // 12 SNMP_CLASS_INVALID_TARGET
+  "SNMP++: Invalid (null) Callback Function", // 13 SNMP_CLASS_INVALID_CALLBACK
+  "SNMP++: Invalid Request Id",        // 14 SNMP_CLASS_INVALID_REQID
+  "SNMP++: Invalid Notification Id",   // 15 SNMP_CLASS_INVALID_NOTIFYID
+                                       // 16 SNMP_CLASS_INVALID_OPERATION
+  "SNMP++: SNMP Operation not supported on specified Target",
+  "SNMP++: Invalid Object Identifier", // 17 SNMP_CLASS_INVALID_OID
+  "SNMP++: Invalid Address",           // 18 SNMP_CLASS_INVALID_ADDRESS
+                                       // 19 SNMP_CLASS_ERR_STATUS_SET
+  "SNMP++: Agent indicates error in SNMP request",
+
+  // Transport Errors:
+  "SNMP++: Transport is not supported",  // 20 SNMP_CLASS_TL_UNSUPPORTED
+  "SNMP++: Transport is in use",         // 21 SNMP_CLASS_TL_IN_USE
+  "SNMP++: Transport operation failed",  // 22 SNMP_CLASS_TL_FAILED
+  "SNMP++: Transport access denied",     // 23 SNMP_CLASS_TL_ACCESS_DENIED
+  "SNMP++: Blocked Mode Shutdown",       // 24 SNMP_CLASS_SHUTDOWN
+
+  "Unknown error code",  // unknown error code
+};
+//@}
+#endif //_INCLUDE_SNMP_ERR_STRINGS
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif //_SNMPERRS_H
diff --git a/3rdparty/snmp++/include/snmp_pp/snmpmsg.h b/3rdparty/snmp++/include/snmp_pp/snmpmsg.h
new file mode 100644 (file)
index 0000000..897f253
--- /dev/null
@@ -0,0 +1,170 @@
+/*_############################################################################
+  _## 
+  _##  snmpmsg.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++ S N M P M E S S A G E . H
+
+  SNMPMESSAGE CLASS DEFINITION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  ASN.1        encoding / decoding class
+               
+=====================================================================*/
+// $Id: snmpmsg.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _SNMPMSG
+#define _SNMPMSG
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#include "snmp_pp/smival.h"
+#include "snmp_pp/pdu.h"
+#include "snmp_pp/target.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/mp_v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+DLLOPT void freeSmivalDescriptor( SmiVALUE* );
+DLLOPT int convertVbToSmival( const Vb&, SmiVALUE* );
+
+#define SNMP_MSG_OID_SYSUPTIME "1.3.6.1.2.1.1.3.0"
+#define SNMP_MSG_OID_TRAPID    "1.3.6.1.6.3.1.1.4.1.0"
+
+class Snmp;
+
+// SnmpMessage Class
+class DLLOPT SnmpMessage
+{
+ public:
+
+  // construct a SnmpMessage object
+  SnmpMessage() : bufflen(MAX_SNMP_PACKET), valid_flag(false) {};
+       // load up using a Pdu, community and SNMP version
+       // performs ASN.1 serialization
+       // result status returned
+ private:
+       int load( const Pdu &pdu,                // Pdu to serialize
+                  const OctetStr &community,     // community name to use
+                  const snmp_version version,    // SNMP version, v1 or v2
+                  const OctetStr *engine_id,     // optional v3
+                  const OctetStr *security_name, // optional v3
+                  const int security_model);     // optional v3
+ public:
+       int load( const Pdu &pdu,              // Pdu to serialize
+                  const OctetStr &community,   // community name to use
+                  const snmp_version version)  // SNMP version, v1 or v2
+         { return load(pdu, community, version, 0, 0, 0); };
+
+       // load up message using ASN.1 data stream
+       // status is returned
+       int load( unsigned char *data,         // data to be loaded
+                 unsigned long len);          // len of data to be loaded
+
+       // unload ( unserialize ) into SNMP++ Pdu, community and version
+       // status is returned
+ private:
+       int unload( Pdu &pdu,                    // Pdu returned
+                    OctetStr &community,         // community name
+                    snmp_version &version,       // version
+                    OctetStr *engine_id,         // optional v3
+                    OctetStr *security_name, // optional v3
+                    long int *security_model,
+                   UdpAddress *from_addr,
+                    Snmp *snmp_session);
+ public:
+       int unload( Pdu &pdu,                    // Pdu returned
+                    OctetStr &community,         // community name
+                    snmp_version &version)       // version
+         { return unload(pdu, community, version, 0, 0, 0, 0, 0); };
+
+
+#ifdef _SNMPv3
+       int loadv3( const Pdu &pdu,               // Pdu to serialize
+                    const OctetStr &engine_id,    // engine_id to use
+                    const OctetStr &sec_name,     // securit_name to use
+                    const int sec_model,          // security_model to use
+                    const snmp_version version)   // SNMP version, v3
+       { return load(pdu, "", version, &engine_id, &sec_name, sec_model); }
+
+       int unloadv3( Pdu &pdu,                  // Pdu returned
+                      snmp_version &version,     // version
+                      OctetStr &engine_id,       // optional v3
+                      OctetStr &security_name,   // optional v3
+                      long int &security_model,
+                     UdpAddress &from_addr,
+                      Snmp &snmp_session);
+
+        // returns TRUE if the message in the buffer is a v3 message
+        bool is_v3_message() {return v3MP::is_v3_msg(databuff, (int)bufflen);};
+
+#endif
+
+       // return the validity of the message
+       bool valid() const         { return valid_flag;};
+
+       // return raw data
+       // check validity
+       unsigned char *data()     { return databuff; };
+
+       // returns len
+       // check validity
+       unsigned long len() const { return bufflen; };
+
+protected:
+
+       unsigned char databuff[MAX_SNMP_PACKET];
+       unsigned int bufflen;
+       bool valid_flag;
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif  // _SNMPMSG
diff --git a/3rdparty/snmp++/include/snmp_pp/target.h b/3rdparty/snmp++/include/snmp_pp/target.h
new file mode 100644 (file)
index 0000000..6c72c20
--- /dev/null
@@ -0,0 +1,668 @@
+/*_############################################################################
+  _## 
+  _##  target.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++  T A R G E T . H
+
+  TARGET CLASS DEFINITION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  Target class defines target SNMP agents.
+
+=====================================================================*/
+// $Id: target.h 1539 2009-05-27 22:12:53Z katz $
+
+#ifndef _TARGET
+#define _TARGET
+
+//----[ includes ]-----------------------------------------------------
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/address.h"
+#include "snmp_pp/octet.h"
+#include "snmp_pp/collect.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+//----[ enumerated types for SNMP versions ]---------------------------
+/**
+ * The SNMP version to use is passed with this enum.
+ */
+enum snmp_version
+{
+  version1,         ///< (0) SNMPv1 
+  version2c         ///< (1) SNMPv2c
+#ifdef _SNMPv3
+  ,version2stern,   ///< (2) Dont use this!
+  version3          ///< (3) SNMPv3
+#endif
+};
+
+//----[ Target class ]-------------------------------------------------
+/**
+ * Abstract class used to provide a virtual interface into Targets.
+ *
+ * @note Although it is possible to create an object of this class,
+ *       you won't be happy with that...
+ */
+class DLLOPT SnmpTarget
+{
+ public:
+
+  /**
+   * Enum to identify a target object through SnmpTarget::get_type() method.
+   */
+  enum target_type
+  {
+    type_base,    ///< It is a SnmpTarget object
+    type_ctarget, ///< It is a CTarget object
+    type_utarget  ///< It is a Utarget object
+  };
+
+  /**
+   * Create a SnmpTarget object with default values.
+   * The validity of the target will be false.
+   */
+  SnmpTarget()
+    : validity(false), timeout(default_timeout), retries(default_retries),
+      version(version1), ttype(type_base) {};
+
+  /**
+   * Create a SnmpTarget object with the given Address.
+   */
+  SnmpTarget(const Address &address)
+    : validity(false), timeout(default_timeout), retries(default_retries),
+      version(version1), ttype(type_base), my_address(address)
+    { if (my_address.valid()) validity = true; };
+
+  /**
+   * Destructor that has nothing to do.
+   */
+  virtual ~SnmpTarget() {};
+
+  /**
+   * Return the type of the target object.
+   *
+   * If a SNMP message is received through a callback (that only
+   * passes a SnmpTarget pointer to the callback function), this
+   * method can be used to check the type of the object before doing a
+   * cast to CTarget or UTarget.
+   */
+  target_type get_type() const { return ttype; };
+
+  /**
+   * Returns the validity of the target object.
+   *
+   * @return true, if the target is valid.
+   */
+  bool valid() const { return validity;};
+
+  /**
+   * Set the retry value.
+   *
+   * @param r - The number of retries if no response is received.
+   */
+  void set_retry(const int r) { retries = r; };
+
+  /**
+   * Get the retry value.
+   *
+   * @return The number of retries on timeout.
+   */
+  int get_retry() const { return retries; };
+
+
+  /**
+   * Set the timeout for requests.
+   *
+   * The default timeout for requests is 1 second (100).
+   *
+   * @param t - Timeout in 10ms, so 100 will set the timeout to 1 second.
+   */
+  void set_timeout(const unsigned long t) { timeout = t; };
+
+  /**
+   * Get the timeout.
+   *
+   * @return The timeout for requests sent using this target object.
+   */
+  unsigned long get_timeout() const { return timeout; };
+
+  /**
+   * Change the default timeout.
+   *
+   * Changing the default timeout value will only have an effect for
+   * target objects that are created after setting this value.
+   *
+   * @param t - The new default timeout value
+   */
+  static void set_default_timeout(const unsigned long t)
+    { default_timeout = t; };
+
+  /**
+   * Change the default retries vlaue.
+   *
+   * Changing the default retries value will only have an effect for
+   * target objects that are created after setting this value.
+   *
+   * @param r - The new retries value
+   */
+  static void set_default_retries(const int r) { default_retries = r; };
+
+  /**
+   * Clone operator.
+   *
+   * Virtual clone operation for creating a new SnmpTarget from an existing
+   * SnmpTarget.
+   *
+   * @note The caller MUST use the delete operation on the return
+   *       value when done.
+   *
+   * @return A pointer to the new object on success, 0 on failure.
+   */
+  virtual SnmpTarget *clone() const;
+
+  /**
+   * Get the address object.
+   *
+   * @param address - GenAddress object to store the target address.
+   * @return TRUE on success.
+   */
+  int get_address(GenAddress &address) const;
+
+  /**
+   * Get the address object.
+   *
+   * @return The target address.
+   */
+  const GenAddress &get_address() const { return my_address; };
+
+  /**
+   * Set the address object.
+   *
+   * @param address - The address that this target should use.
+   * @return TRUE on success.
+   */
+  virtual int set_address(const Address &address);
+
+  /**
+   * Get the SNMP version for this target.
+   *
+   * @return The SNMP version of this target object.
+   * @see enum snmp_version
+   */
+  snmp_version get_version() const { return version;};
+
+  /**
+   * Set the SNMP version of this target.
+   *
+   * @param v - The SNMP version that should be used for sending messages.
+   */
+  void set_version(const snmp_version v) { version = v; };
+
+  /**
+   * Overloeaded compare operator.
+   *
+   * Two SnmpTarget objects are considered equal, if all member
+   * variables are equal.
+   *
+   * @return 1 if targets are equal, 0 if not.
+   */
+  int operator==(const SnmpTarget &rhs) const;
+
+  /**
+   * Reset the object.
+   */
+  virtual void clear();
+
+ protected:
+  bool validity;         ///< Validity of the object
+  unsigned long timeout; ///< xmit timeout in 10 milli secs
+  int retries;           ///< number of retries
+  snmp_version version;  ///< SNMP version to use
+  target_type ttype;     ///< Type of the target
+  GenAddress my_address; ///< Address object
+
+  static unsigned long default_timeout; ///< default timeout for new objects
+  static int default_retries;           ///< default retries for new objects
+};
+
+//----[  CTarget class ]----------------------------------------------
+/**
+ * Community based target object.
+ * This target can be used for SNMPv1 and SNMPv2c messages.
+ */
+class DLLOPT CTarget: public SnmpTarget
+{
+ public:
+  /**
+   * Constructor with no args.
+   * The validity of the target will be false.
+   */
+  CTarget();
+
+  /**
+   * Constructor with all args.
+   *
+   * @param address - Address of the target host (cann be any address object)
+   * @param read_community_name - Community for get requests
+   * @param write_community_name - Community for set requests
+   */
+  CTarget(const Address &address,
+         const char *read_community_name,
+         const char *write_community_name);
+
+  /**
+   * Constructor with all args.
+   *
+   * @param address - Address of the target host (cann be any address object)
+   * @param read_community_name - Community for get requests
+   * @param write_community_name - Community for set requests
+   */
+  CTarget(const Address &address,
+         const OctetStr &read_community_name,
+         const OctetStr &write_community_name);
+
+  /**
+   * Constructor with only address.
+   *
+   * The read and write community names will be set to "public".
+   *
+   * @param address - Address of the target host (cann be any address object)
+   */
+  CTarget(const Address &address);
+
+  /**
+   * Constructor from existing CTarget.
+   */
+  CTarget(const CTarget &target);
+
+  /**
+   * Destructor, that has nothing to do.
+   */
+  ~CTarget() {};
+
+  /**
+   * Clone operator.
+   *
+   * Clone operation for creating a new CTarget from an existing
+   * CTarget.
+   *
+   * @note The caller MUST use the delete operation on the return
+   *       value when done.
+   *
+   * @return A pointer to the new object on success, 0 on failure.
+   */
+  SnmpTarget *clone() const { return (SnmpTarget *) new CTarget(*this); };
+
+  /**
+   * Get the read community name.
+   *
+   * @return C string of the read community.
+   */
+  const char * get_readcommunity() const
+    { return (const char *) read_community.get_printable(); };
+
+  /**
+   * Get the read community name.
+   *
+   * @param oct - OctetStr that will be filled with the read community name.
+   */
+  void get_readcommunity(OctetStr& oct) const { oct = read_community; };
+
+  /**
+   * Set the read community name.
+   *
+   * @param str - The new read community name
+   */
+  void set_readcommunity(const char * str) { read_community = str; };
+
+  /**
+   * Set the read community name.
+   *
+   * @param oct - The new read community name
+   */
+  void set_readcommunity(const OctetStr& oct) { read_community = oct; };
+
+  /**
+   * Get the write community name.
+   *
+   * @return C string of the write community.
+   */
+  const char * get_writecommunity() const
+    { return (const char *) write_community.get_printable(); };
+
+  /**
+   * Get the write community name.
+   *
+   * @param oct - OctetStr that will be filled with the write community name.
+   */
+  void get_writecommunity(OctetStr &oct) const { oct = write_community; };
+
+  /**
+   * Set the write community name.
+   *
+   * @param str - The new write community name
+   */
+  void set_writecommunity(const char *str) { write_community = str; };
+
+  /**
+   * Set the write community name.
+   *
+   * @param oct - The new write community name
+   */
+  void set_writecommunity(const OctetStr &oct) { write_community = oct; };
+
+  /**
+   * Overloaded assignment operator.
+   */
+  CTarget& operator=(const CTarget& target);
+
+  /**
+   * Overloeaded compare operator.
+   *
+   * Two CTarget objects are considered equal, if all member variables
+   * and the base classes are equal.
+   *
+   * @return 1 if targets are equal, 0 if not.
+   */
+  int operator==(const CTarget &rhs) const;
+
+  /**
+   * Get all values of a CTarget object.
+   *
+   * @param read_comm  - Read community name
+   * @param write_comm - Write community name
+   * @param address    - Address of the target
+   * @param t          - Timeout value
+   * @param r          - Retries value
+   * @param v          - The SNMP version of this target
+   *
+   * @return TRUE on success and FALSE on failure.
+   */
+  int resolve_to_C(OctetStr& read_comm,
+                  OctetStr& write_comm,
+                  GenAddress &address,
+                  unsigned long &t,
+                  int &r,
+                  unsigned char &v) const;
+
+  /**
+   * Reset the object.
+   */
+  void clear();
+
+ protected:
+  OctetStr read_community;        //  get community
+  OctetStr write_community;       //  set community
+};
+
+// create OidCollection type
+typedef SnmpCollection<SnmpTarget> TargetCollection;
+
+#ifdef _SNMPv3
+#define INITIAL_USER "initial"
+#else
+#define INITIAL_USER "public"
+#endif
+
+//----[  UTarget class ]----------------------------------------------
+/**
+ * User based Target.
+ *
+ * This class is used for SNMPv3 targets.
+ */
+class DLLOPT UTarget: public SnmpTarget
+{
+ public:
+  /**
+   * Constructor with no args.
+   * The validity of the target will be false.
+   */
+  UTarget();
+
+  /**
+   * Constructor with all args.
+   *
+   * @param address   - Address of the target host (cann be any address object)
+   * @param sec_name   - The security name
+   * @param sec_model - The security model to use
+   */
+  UTarget(const Address &address,
+         const char *sec_name,
+         const int sec_model);
+
+  /**
+   * Constructor with all args.
+   *
+   * @param address   - Address of the target host (cann be any address object)
+   * @param sec_name  - The security name
+   * @param sec_model - The security model to use
+   */
+  UTarget(const Address &address,
+         const OctetStr &sec_name,
+         const int sec_model);
+
+  /**
+   * Constructor with only address.
+   *
+   * Assumes the following defaults: security_name: initial, version: SNMPv3,
+   * security_model: v3MP.
+   *
+   * @param address - Address of the target host (cann be any address object)
+   */
+  UTarget(const Address &address);
+
+  /**
+   * Constructor from existing UTarget.
+   */
+  UTarget(const UTarget &target);
+
+  /**
+   * Destructor, that has nothing to do.
+   */
+  ~UTarget() {};
+
+  /**
+   * Clone operator.
+   *
+   * Clone operation for creating a new UTarget from an existing
+   * UTarget.
+   *
+   * @note The caller MUST use the delete operation on the return
+   *       value when done.
+   *
+   * @return A pointer to the new object on success, 0 on failure.
+   */
+  SnmpTarget *clone() const { return (SnmpTarget *) new UTarget(*this); };
+
+  /**
+   * Set the address object.
+   *
+   * This method is the same as in SnmpTarget, but it deletes engine_id.
+   *
+   * @param address - The address that this target should use.
+   * @return TRUE on success.
+   */
+  int set_address(const Address &address);
+
+  /**
+   * Get the security name.
+   *
+   * @return A const reference to the security name.
+   */
+  const OctetStr& get_security_name() const { return security_name;} ;
+
+  /**
+   * Get the security name.
+   *
+   * @param oct - OctetStr that will be filled with the security name.
+   */
+  void get_security_name(OctetStr& oct) const { oct = security_name; };
+
+  /**
+   * Set the security name.
+   *
+   * @param str - The new security name
+   */
+  void set_security_name(const char * str) { security_name = str; };
+
+  /**
+   * Set the security name.
+   *
+   * @param oct - The new security name
+   */
+  void set_security_name(const OctetStr& oct) { security_name = oct; };
+
+#ifdef _SNMPv3
+  /**
+   * Set the engine id.
+   *
+   * In most cases it is not necessary for the user to set the engine
+   * id as snmp++ performs engine id discovery. If the engine id is
+   * set by the user, no engine_id discovery is made, even if the
+   * engine id set by the user is wrong.
+   *
+   * @param str - The engine id to use
+   */
+  void set_engine_id(const char * str) { engine_id = str; };
+
+  /**
+   * Set the engine id.
+   *
+   * In most cases it is not necessary for the user to set the engine
+   * id as snmp++ performs engine id discovery. If the engine id is
+   * set by the user, no engine_id discovery is made, even if the
+   * engine id set by the user is wrong.
+   *
+   * @param oct - The engine id to use
+   */
+  void set_engine_id(const OctetStr &oct) { engine_id = oct; };
+
+  /**
+   * Get the engine id.
+   *
+   * @return A const reference to the enigne id of this target.
+   */
+  const OctetStr& get_engine_id() const { return engine_id; };
+
+  /**
+   * Get the engine id.
+   *
+   * @param oct - OctetStr that will be filled with the engine id
+   */
+  void get_engine_id(OctetStr& oct) const { oct = engine_id; };
+#endif
+
+  /**
+   * Get the security_model.
+   *
+   * @return An integer representing the security_model of this target.
+   */
+  int get_security_model() const { return security_model; };
+
+  /**
+   * Set the security_model.
+   *
+   * @param sec_model - The security model to use.
+   */
+  void set_security_model(int sec_model) { security_model = sec_model; };
+
+  /**
+   * Overloaded assignment operator.
+   */
+  UTarget& operator=(const UTarget& target);
+
+  /**
+   * Overloeaded compare operator.
+   *
+   * Two UTarget objects are considered equal, if all member variables
+   * (beside the engine id) and the base classes are equal.
+   *
+   * @return 1 if targets are equal, 0 if not.
+   */
+  virtual int operator==(const UTarget &rhs) const;
+
+  /**
+   * Get all values of a UTarget object.
+   *
+   * @param sec_name   - security name
+   * @param sec_model  - security model
+   * @param address    - Address of the target
+   * @param t          - Timeout value
+   * @param r          - Retries value
+   * @param v          - The SNMP version of this target
+   *
+   * @return TRUE on success and FALSE on failure.
+   */
+  int resolve_to_U(OctetStr&  sec_name,
+                  int &sec_model,
+                  GenAddress &address,
+                  unsigned long &t,
+                  int &r,
+                  unsigned char &v) const;
+
+  /**
+   * Reset the object.
+   */
+  void clear();
+
+ protected:
+  OctetStr security_name;
+  int security_model;
+#ifdef _SNMPv3
+  OctetStr engine_id;
+#endif
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif //_TARGET
diff --git a/3rdparty/snmp++/include/snmp_pp/timetick.h b/3rdparty/snmp++/include/snmp_pp/timetick.h
new file mode 100644 (file)
index 0000000..b7770b4
--- /dev/null
@@ -0,0 +1,168 @@
+/*_############################################################################
+  _## 
+  _##  timetick.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++ T I M E T I C K. H
+
+  TIMETICK CLASS DEFINITION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  Class definition for SMI Timeticks class.
+
+=====================================================================*/
+// $Id: timetick.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _TIMETICKS
+#define _TIMETICKS
+
+#include "snmp_pp/integer.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define TICKOUTBUF 30 // max formatted time string
+
+//------------[ TimeTicks Class ]-----------------------------------
+/**
+ * The timeticks class allows all the functionality of unsigned
+ * integers but is recognized as a distinct SMI type. TimeTicks
+ * objects may be get or set into Vb objects.
+ */
+class DLLOPT TimeTicks : public SnmpUInt32
+{
+ public:
+  /**
+   * Constructs a zero TimeTicks object.
+   */
+  TimeTicks() : SnmpUInt32()
+    { smival.syntax = sNMP_SYNTAX_TIMETICKS; };
+
+  /**
+   * Constructs a TimeTicks object with the given value.
+   *
+   * @param val - time in hundredths of seconds.
+   */
+  TimeTicks(const unsigned long val) : SnmpUInt32(val)
+    { smival.syntax = sNMP_SYNTAX_TIMETICKS; };
+
+  /**
+   * Copy constructor.
+   *
+   * @param t - Time for the new object.
+   */
+  TimeTicks(const TimeTicks &t);
+
+  /**
+   * Destructor.
+   */
+  ~TimeTicks() {};
+
+  /**
+   * Return the syntax.
+   *
+   * @return Always returns sNMP_SYNTAX_TIMETICKS.
+   */
+  SmiUINT32 get_syntax() const { return sNMP_SYNTAX_TIMETICKS; };
+
+  /**
+   * Get a printable ASCII value.
+   */
+  const char *get_printable() const;
+
+  /**
+   * Clone operator.
+   *
+   * @return Pointer to a newly created copy of the object.
+   */
+  SnmpSyntax *clone() const { return (SnmpSyntax *) new TimeTicks(*this); };
+
+  /**
+   * Map other SnmpSyntax objects to TimeTicks.
+   */
+  SnmpSyntax& operator=(const SnmpSyntax &val);
+
+  /**
+   * Overloaded assignment for TimeTicks.
+   *
+   * @param uli - new value
+   * @return self reference
+   */
+  TimeTicks& operator=(const TimeTicks &uli)
+    { smival.value.uNumber = uli.smival.value.uNumber;
+      m_changed = true; return *this; };
+
+  /**
+   * Overloaded assignment for unsigned longs.
+   *
+   * @param i - new value in hundrets of seconds
+   * @return self reference
+   */
+  TimeTicks& operator=(const unsigned long i)
+    { smival.value.uNumber = i; m_changed = true; return *this; };
+
+  /**
+   * Casting to unsigned long.
+   *
+   * @return Current value as hundrets of seconds
+   */
+  operator unsigned long() { return smival.value.uNumber; };
+
+  /**
+   * Reset the object.
+   */
+  void clear()
+    { smival.value.uNumber = 0; m_changed = true; };
+
+ protected:
+  SNMP_PP_MUTABLE char output_buffer[TICKOUTBUF];  // for storing printed form
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif
diff --git a/3rdparty/snmp++/include/snmp_pp/usm_v3.h b/3rdparty/snmp++/include/snmp_pp/usm_v3.h
new file mode 100644 (file)
index 0000000..cec9367
--- /dev/null
@@ -0,0 +1,1114 @@
+/*_############################################################################
+  _## 
+  _##  usm_v3.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+// $Id: usm_v3.h 1825 2010-08-29 20:10:54Z katz $
+
+#ifndef _USM_V3
+#define _USM_V3
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+
+#include "snmp_pp/smi.h"
+#include "snmp_pp/octet.h"
+#include "snmp_pp/address.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifndef MAXUINT32
+#define MAXUINT32 4294967295u
+#endif
+
+// the maximum allowed length of the username
+#define MAXLEN_USMUSERNAME 32
+#define MAXLEN_USMSECURITYNAME MAXLEN_USMUSERNAME
+
+#define SNMPv3_AUTHFLAG       0x01
+#define SNMPv3_PRIVFLAG       0x02
+#define SNMPv3_REPORTABLEFLAG 0x04
+
+#define NOKEY      0
+#define AUTHKEY    1
+#define PRIVKEY    2
+#define OWNAUTHKEY 3
+#define OWNPRIVKEY 4
+
+/** @name SecurityLevels
+ *
+ * When sending a SNMPv3 message, one of these security levels can be
+ * set on the Pdu object.
+ */
+//@{
+#define SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV  1 ///< noAuthNoPriv
+#define SNMP_SECURITY_LEVEL_AUTH_NOPRIV    2 ///< authNoPriv
+#define SNMP_SECURITY_LEVEL_AUTH_PRIV      3 ///< authPriv
+//@}
+
+/** @name AuthProtocols
+ *
+ * Each user of the USM must use one authentication protocol (which
+ * may be none.
+ */
+//@{
+#define SNMP_AUTHPROTOCOL_NONE    1 ///< None
+#define SNMP_AUTHPROTOCOL_HMACMD5 2 ///< HMAC-MD5
+#define SNMP_AUTHPROTOCOL_HMACSHA 3 ///< HMAC-SHA
+//@}
+
+/** @name PrivProtocols
+ *
+ * Each user of the USM must use one privacy protocol (which may be
+ * none.
+ */
+//@{
+#define SNMP_PRIVPROTOCOL_NONE     1 ///< None
+#define SNMP_PRIVPROTOCOL_DES      2 ///< DES
+#define SNMP_PRIVPROTOCOL_AES128   4 ///< AES128 (RFC 3826)
+
+#define SNMP_PRIVPROTOCOL_IDEA     9 ///< IDEA (non standard)
+#define SNMP_PRIVPROTOCOL_AES192  20 ///< AES192 (non standard)
+#define SNMP_PRIVPROTOCOL_AES256  21 ///< AES256 (non standard)
+#define SNMP_PRIVPROTOCOL_3DESEDE  3 ///< 3DES (expired draft standard)
+//@}
+
+/** @name USM-ErrorCodes
+ *
+ * Each method of the class USM may return one of the following
+ * error codes.
+ */
+//@{
+#define SNMPv3_USM_OK                          1400
+#define SNMPv3_USM_ERROR                       1401
+#define SNMPv3_USM_ERROR_CONFIGFILE            1402
+#define SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL  1403
+#define SNMPv3_USM_UNKNOWN_SECURITY_NAME       1404
+#define SNMPv3_USM_ENCRYPTION_ERROR            1405
+#define SNMPv3_USM_DECRYPTION_ERROR            1406
+#define SNMPv3_USM_AUTHENTICATION_ERROR        1407
+#define SNMPv3_USM_AUTHENTICATION_FAILURE      1408
+#define SNMPv3_USM_PARSE_ERROR                 1409
+#define SNMPv3_USM_UNKNOWN_ENGINEID            1410
+#define SNMPv3_USM_NOT_IN_TIME_WINDOW          1411
+#define SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL    1412
+#define SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL    1413
+#define SNMPv3_USM_ADDRESS_ERROR               1414
+#define SNMPv3_USM_FILECREATE_ERROR            1415
+#define SNMPv3_USM_FILEOPEN_ERROR              1416
+#define SNMPv3_USM_FILERENAME_ERROR            1417
+#define SNMPv3_USM_FILEDELETE_ERROR            1418
+#define SNMPv3_USM_FILEWRITE_ERROR             1419
+#define SNMPv3_USM_FILEREAD_ERROR              1420
+//@}
+
+/** @name Statistics on error codes. */
+//@{
+#define SNMPv3_USM_MAX_ERROR                   SNMPv3_USM_FILEREAD_ERROR
+#define SNMPv3_USM_MIN_ERROR                   SNMPv3_USM_OK
+#define SNMPv3_USM_ERRORCOUNT                  SNMPv3_USM_MAX_ERROR - SNMPv3_USM_MIN_ERROR
+//@}
+
+#define oidUsmStats                        "1.3.6.1.6.3.15.1.1"
+#define oidUsmStatsUnsupportedSecLevels    "1.3.6.1.6.3.15.1.1.1.0"
+#define oidUsmStatsNotInTimeWindows        "1.3.6.1.6.3.15.1.1.2.0"
+#define oidUsmStatsUnknownUserNames        "1.3.6.1.6.3.15.1.1.3.0"
+#define oidUsmStatsUnknownEngineIDs        "1.3.6.1.6.3.15.1.1.4.0"
+#define oidUsmStatsWrongDigests            "1.3.6.1.6.3.15.1.1.5.0"
+#define oidUsmStatsDecryptionErrors        "1.3.6.1.6.3.15.1.1.6.0"
+
+#define oidUsmUserTable                    "1.3.6.1.6.3.15.1.2.2"
+#define oidUsmUserEntry                    "1.3.6.1.6.3.15.1.2.2.1"
+
+#define oidUsmAuthProtocolBase             "1.3.6.1.6.3.10.1.1"
+#define oidUsmNoAuthProtocol               "1.3.6.1.6.3.10.1.1.1"
+#define oidUsmHMACMD5AuthProtocol          "1.3.6.1.6.3.10.1.1.2"
+#define oidUsmHMACSHAAuthProtocol          "1.3.6.1.6.3.10.1.1.3"
+
+#define oidUsmPrivProtocolBase             "1.3.6.1.6.3.10.1.2"
+#define oidUsmNoPrivProtocol               "1.3.6.1.6.3.10.1.2.1"
+#define oidUsmDESPrivProtocol              "1.3.6.1.6.3.10.1.2.2"
+#define oidUsmIDEAPrivProtocol             "1.3.6.1.6.3.10.1.2.9"
+#define oidUsmAES128PrivProtocol           "1.3.6.1.6.3.10.1.2.4"
+#define oidUsmAES192PrivProtocol           "1.3.6.1.6.3.10.1.2.20"
+#define oidUsmAES256PrivProtocol           "1.3.6.1.6.3.10.1.2.21"
+#define oidUsm3DESEDEPrivProtocol          "1.3.6.1.6.3.10.1.2.3"
+
+
+#define USM_KeyUpdate            1
+#define USM_PasswordUpdate       2
+#define USM_PasswordKeyUpdate    3
+#define USM_PasswordAllKeyUpdate 4
+
+class SnmpTarget;
+class Pdu;
+
+struct UsmKeyUpdate;
+
+struct UsmUserTableEntry {
+  unsigned char *usmUserEngineID;     long int usmUserEngineIDLength;
+  unsigned char *usmUserName;         long int usmUserNameLength;
+  unsigned char *usmUserSecurityName; long int usmUserSecurityNameLength;
+  long int  usmUserAuthProtocol;
+  unsigned char *usmUserAuthKey;      long int usmUserAuthKeyLength;
+  long int  usmUserPrivProtocol;
+  unsigned char *usmUserPrivKey;      long int usmUserPrivKeyLength;
+};
+
+struct UsmUser {
+  unsigned char *engineID;     long int engineIDLength;
+  unsigned char *usmUserName;  long int usmUserNameLength;
+  unsigned char *securityName; long int securityNameLength;
+  long int  authProtocol;
+  unsigned char *authKey;      long int authKeyLength;
+  long int  privProtocol;
+  unsigned char *privKey;      long int privKeyLength;
+};
+
+struct UsmUserNameTableEntry {
+  OctetStr usmUserName;
+  OctetStr usmUserSecurityName;
+  long int  usmUserAuthProtocol;
+  long int  usmUserPrivProtocol;
+  unsigned char *authPassword;        long int authPasswordLength;
+  unsigned char *privPassword;        long int privPasswordLength;
+};
+
+//-----------[ async methods callback ]-----------------------------------
+typedef void (*usm_add_user_callback)(const OctetStr &engine_id,
+                                      const OctetStr &usm_user_name,
+                                      const OctetStr &usm_user_security_name,
+                                      const int auth_protocol,
+                                      const OctetStr &auth_key,
+                                      const int priv_protocol,
+                                      const OctetStr &priv_key);
+
+struct SecurityStateReference;
+
+class AuthPriv;
+class USMTimeTable;
+class USMUserNameTable;
+class USMUserTable;
+class v3MP;
+
+/**
+ * This is the class for the User Based Security Model.
+ *
+ * To add or delete users, the methods add_usm_user() and delete_usm_user()
+ * should be used.
+ *
+ * USM distinguishes between userName and securityName. The following is
+ * from section 2.1 of RFC3414:
+ *
+ * "userName: A string representing the name of the user.
+ *
+ *  securityName: A human-readable string representing the user in a format
+ *  that is Security Model independent. There is a one-to-one relationship *
+ *  between userName and securityName."
+ */
+class DLLOPT USM
+{
+  friend class v3MP;
+
+public:
+
+  /**
+   * Create an instance of the USM.
+   *
+   * @param engine_boots - The new value for the snmpEngineBoots counter
+   * @param engine_id    - The local snmp engine id
+   * @param v3_mp        - Pointer to the parent v3MP object.
+   * @param msg_id       - OUT: The initial value for the msgID
+   * @param result       - OUT: construct status, should be SNMPv3_USM_OK
+   */
+  USM(unsigned int engine_boots, const OctetStr &engine_id, const v3MP *v3_mp,
+      unsigned int *msg_id, int &result);
+
+  /**
+   * Destructor.
+   */
+  ~USM();
+
+  /**
+   * Enables the discovery mode of the USM, i.e. the USM accepts all messages
+   * with unknown engine ids and adds these engine ids to its tables.
+   */
+  void set_discovery_mode() { discovery_mode = true; };
+
+  /**
+   * Disables the discovery mode of the USM, i.e. the USM will not accept any
+   * message with an unknown engine id.
+   */
+  void unset_discovery_mode() { discovery_mode = false; };
+
+  /**
+   * Return TRUE if the USM discovery mode is enabled, FALSE else.
+   */
+  bool is_discovery_enabled() const { return discovery_mode; };
+
+  /**
+   * Add a new user to the usmUserNameTable. If the User is already known
+   * to the USM, the old entry is replaced.
+   * The USM will compute a userName for the given securityName, which
+   * will be the same as securityName (recommended).
+   *
+   * If discovery mode is enabled, localized user entries are
+   * automatically created for new engine ids.
+   *
+   * @param security_name - Unique securityName
+   * @param auth_protocol - Possible values are:
+   *                              SNMP_AUTHPROTOCOL_NONE,
+   *                              SNMP_AUTHPROTOCOL_HMACMD5,
+   *                              SNMP_AUTHPROTOCOL_HMACSHA
+   * @param priv_protocol - Possible values are:
+   *                              SNMP_PRIVPROTOCOL_NONE,
+   *                              SNMP_PRIVPROTOCOL_DES,
+   *                              SNMP_PRIVPROTOCOL_IDEA
+   * @param auth_password - Secret password for authentication
+   * @param priv_password - Secret password for privacy
+   *
+   * @return - SNMPv3_USM_OK or
+   *           SNMP_v3_USM_ERROR (memory error, not initialized)
+   */
+  int add_usm_user(const OctetStr& security_name,
+                  const long int  auth_protocol,
+                  const long int  priv_protocol,
+                  const OctetStr& auth_password,
+                  const OctetStr& priv_password);
+
+  /**
+   * Add a new user to the usmUserNameTable. If the userName is already known
+   * to the USM, the old entry is replaced.
+   *
+   * It is not recommended to add users with userName != securityName.
+   *
+   * @param  user_name     - Unique userName
+   * @param  security_name - Unique securityName
+   * @param  auth_protocol - Possible values are:
+   *                              SNMP_AUTHPROTOCOL_NONE,
+   *                              SNMP_AUTHPROTOCOL_HMACMD5,
+   *                              SNMP_AUTHPROTOCOL_HMACSHA
+   * @param  priv_protocol - Possible values are:
+   *                              SNMP_PRIVPROTOCOL_NONE,
+   *                              SNMP_PRIVPROTOCOL_DES,
+   *                              SNMP_PRIVPROTOCOL_IDEA
+   * @param  auth_password - Secret password for authentication
+   * @param  priv_password - Secret password for privacy
+   *
+   * @return - SNMPv3_USM_OK or
+   *           SNMP_v3_USM_ERROR (memory error, not initialized)
+   */
+  int add_usm_user(const OctetStr& user_name,
+                  const OctetStr& security_name,
+                  const long int  auth_protocol,
+                  const long int  priv_protocol,
+                  const OctetStr& auth_password,
+                  const OctetStr& priv_password);
+
+
+  /**
+   * Add or replace a localized user in the USM table.
+   *
+   * This function uses build_localized_keys() to generate localized
+   * keys for the given passwords. Then it calls add_localized_user()
+   * to add/replace the localized entry for the user.
+   *
+   * The passwords are not stored, so no additonal engine id discovery
+   * is possible.
+   *
+   * @param user_name         - The name of the user (in the USM)
+   * @param security_name     - The securityName of the user, this name
+   *                                is the same for all securityModels
+   * @param auth_protocol     - Possible values are:
+   *                                SNMP_AUTHPROTOCOL_NONE,
+   *                                SNMP_AUTHPROTOCOL_HMACMD5,
+   *                                SNMP_AUTHPROTOCOL_HMACSHA,...
+   * @param priv_protocol     - Possible values are:
+   *                                SNMP_PRIVPROTOCOL_NONE,
+   *                                SNMP_PRIVPROTOCOL_DES,
+   *                                SNMP_PRIVPROTOCOL_IDEA,...
+   * @param  auth_password - Secret password for authentication
+   * @param  priv_password - Secret password for privacy
+   * @param engine_id         - The engineID, the key was localized with
+   *
+   * @return - SNMPv3_USM_OK
+   *           SNMP_v3_USM_ERROR (not initialized, no memory)
+   */
+  int add_usm_user(const OctetStr& user_name,
+                  const OctetStr& security_name,
+                  const long int  auth_protocol,
+                  const long int  priv_protocol,
+                  const OctetStr& auth_password,
+                  const OctetStr& priv_password,
+                  const OctetStr& engine_id);
+
+  int add_usm_user(const OctetStr& security_name,
+                  const long int  auth_protocol,
+                  const long int  priv_protocol,
+                  const OctetStr& auth_password,
+                  const OctetStr& priv_password,
+                  const OctetStr& engine_id)
+    { return add_usm_user(security_name, security_name, auth_protocol,
+                         priv_protocol, auth_password, priv_password,
+                         engine_id); };
+
+
+  /**
+   * Delete all occurences of the user with the given security name
+   * from the USM.
+   *
+   * @param security_name - the securityName of the user
+   */
+  void delete_usm_user(const OctetStr& security_name);
+
+
+  /**
+   * Save all localized users into a file.
+   *
+   * @param file - filename including path
+   *
+   * @return SNMPv3_USM_ERROR, SNMPv3_USM_FILECREATE_ERROR,
+   *         SNMPv3_USM_FILERENAME_ERROR or SNMPv3_USM_OK
+   */
+  int save_localized_users(const char *file);
+
+  /**
+   * Load localized users from a file.
+   *
+   * @param file - filename including path
+   *
+   * @return SNMPv3_USM_ERROR, SNMPv3_USM_FILEOPEN_ERROR,
+   *         SNMPv3_USM_FILEREAD_ERROR or SNMPv3_USM_OK
+   */
+  int load_localized_users(const char *file);
+
+  /**
+   * Save all users with their passwords into a file.
+   *
+   * @param file - filename including path
+   *
+   * @return SNMPv3_USM_ERROR, SNMPv3_USM_FILECREATE_ERROR,
+   *         SNMPv3_USM_FILERENAME_ERROR or SNMPv3_USM_OK
+   */
+  int save_users(const char *file);
+
+  /**
+   * Load users with their passwords from a file.
+   *
+   * @param file - filename including path
+   *
+   * @return SNMPv3_USM_ERROR, SNMPv3_USM_FILEOPEN_ERROR,
+   *         SNMPv3_USM_FILEREAD_ERROR or SNMPv3_USM_OK
+   */
+  int load_users(const char *file);
+
+  /**
+   * Add or replace a localized user in the USM table. Use this method
+   * only, if you know what you are doing.
+   *
+   * @param engine_id         - The engineID, the key was localized with
+   * @param user_name         - The name of the user (in the USM)
+   * @param security_name     - The securityName of the user, this name
+   *                                is the same for all securityModels
+   * @param auth_protocol     - Possible values are:
+   *                                SNMP_AUTHPROTOCOL_NONE,
+   *                                SNMP_AUTHPROTOCOL_HMACMD5,
+   *                                SNMP_AUTHPROTOCOL_HMACSHA,...
+   * @param auth_key          - The key used for authentications
+   * @param priv_protocol     - Possible values are:
+   *                                SNMP_PRIVPROTOCOL_NONE,
+   *                                SNMP_PRIVPROTOCOL_DES,
+   *                                SNMP_PRIVPROTOCOL_IDEA,...
+   * @param priv_key          - The key used for privacy
+   *
+   * @return - SNMPv3_USM_OK
+   *           SNMP_v3_USM_ERROR (not initialized, no memory)
+   */
+  int add_localized_user(const OctetStr &engine_id,
+                        const OctetStr &user_name,
+                        const OctetStr &security_name,
+                        const long auth_protocol,
+                        const OctetStr &auth_key,
+                        const long priv_protocol,
+                        const OctetStr &priv_key);
+
+  /**
+   * Generate localized keys for the given params.
+   *
+   * The buffers for the keys should be of size SNMPv3_USM_MAX_KEY_LEN.
+   *
+   * @param engine_id - 
+   * @param auth_prot -
+   * @param priv_prot -
+   * @param auth_password     -
+   * @param auth_password_len -
+   * @param priv_password     -
+   * @param priv_password_len -
+   * @param auth_key     - allocated space for the authentication key
+   * @param auth_key_len - IN: length of the buffer, OUT: key length
+   * @param priv_key     - allocated space for the privacy key
+   * @param priv_key_len - IN: length of the buffer, OUT: key length
+   * @return SNMPv3_USM_OK, or USM error codes
+   */
+  int build_localized_keys(const OctetStr      &engine_id,
+                          const int            auth_prot,
+                          const int            priv_prot,
+                          const unsigned char *auth_password,
+                          const unsigned int   auth_password_len,
+                          const unsigned char *priv_password,
+                          const unsigned int   priv_password_len,
+                          unsigned char *auth_key,
+                          unsigned int  *auth_key_len,
+                          unsigned char *priv_key,
+                          unsigned int  *priv_key_len);
+
+  /**
+   * Delete all localized entries of this user from the usmUserTable.
+   *
+   * @param user_name - The userName that should be deleted
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (user deleted or not in table)
+   */
+  int delete_localized_user(const OctetStr& user_name);
+
+
+  /**
+   * Delete the entry with the given userName and engineID
+   * from the usmUserTable
+   *
+   * @param engine_id - The engineID
+   * @param user_name - The userName that should be deleted
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (user deleted or not in table)
+   */
+  int delete_localized_user(const OctetStr& engine_id,
+                           const OctetStr& user_name);
+
+
+  /**
+   * Delete this engine id form all USM tables (users and engine time).
+   *
+   * @param engine_id - the engine id
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (entries deleted or not in table)
+   */
+  int remove_engine_id(const OctetStr &engine_id);
+
+  /**
+   * Delete the time information for the given engine id.
+   *
+   * @param engine_id - the engine id
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (entry deleted or not in table)
+   */
+  int remove_time_information(const OctetStr &engine_id);
+
+  /**
+   * Replace a localized key of the user and engineID in the
+   * usmUserTable.
+   *
+   * @param user_name     - The name of the user in the USM
+   * @param user_name_len - The length of the user name
+   * @param engine_id     - Change the localized key for the SNMP
+   *                        entity with this engine id
+   * @param engine_id_len - The length of the engine id
+   * @param new_key       - The new key
+   * @param new_key_len   - The length of the new key
+   * @param type_of_key   - AUTHKEY, OWNAUTHKEY, PRIVKEY or OWNPRIVKEY
+   *
+   * @return - SNMPv3_USM_ERROR (no such entry or not initialized),
+   *           SNMPv3_USM_OK
+   */
+   int update_key(const unsigned char* user_name, const long user_name_len,
+                 const unsigned char* engine_id, const long engine_id_len,
+                 const unsigned char* new_key,   const long new_key_len,
+                 const int type_of_key);
+
+  /**
+   * Search for a user with the given securityName and engineID
+   * in the usmUserTable and return the entry. If no entry
+   * could be found, the usmUserNameTable is searched for the given
+   * securityName. If this table has an entry of this user, a
+   * localized entry is generated, added to the usmUserTable and
+   * returned to the caller.
+   *
+   * The caller has to call free_user() with the returned struct.
+   *
+   * @param engine_id         -
+   * @param security_name     -
+   *
+   * @return - a pointer to the structure if an entry could be found
+   *           or was generated, NULL for all errors
+   */
+  struct UsmUser *get_user(const OctetStr &engine_id,
+                          const OctetStr &security_name);
+
+  /**
+   * Free the structure returned from get_user(OctetStr,OctetStr).
+   */
+  void free_user(struct UsmUser *&user);
+
+  /**
+   * Get the security name from a user name.
+   *
+   * @param user_name         -
+   * @param user_name_len     -
+   * @param security_name     - Buffer for the securityName
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+   *           SNMPv3_USM_OK
+   */
+  int get_security_name(const unsigned char *user_name,
+                       const long int user_name_len,
+                       OctetStr &security_name);
+
+  /**
+   * Get the user name from a security name.
+   *
+   * @param user_name         - Buffer for the userName
+   * @param user_name_len     - Has to be set to the max length of the
+   *                            buffer. Is set to the length of the found
+   *                            securityName or to 0 if not found.
+   * @param security_name     -
+   * @param security_name_len -
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+   *           SNMPv3_USM_OK
+   */
+  int get_user_name(unsigned char *user_name,
+                   long int *user_name_len,
+                   const unsigned char *security_name,
+                   const long int security_name_len);
+
+
+  /**
+   * Prepare a key update in the USM. The following procedure is used: To
+   * prepare the key update, this function adds the neccessary variable
+   * bindings to the Pdu to do the key update on the target SNMP entity.
+   * The Pdu has to be sent to the target. If the key update on the target
+   * is successful, usmCommitKeyUpdate() has to be called to do the local key
+   * update. On failure usmAbortKeyUpdate() has to be called to free
+   * temporary ressources.
+   *
+   * @param securityName - The name of the user
+   * @param target       - A target to identify the SNMP entity on which the
+   *                       key will be updated
+   * @param newPassword  - The new password for the user
+   * @param pdu          - A PDU into which this funktion adds the VBs needed
+   *                       to change the keys on the target
+   * @param type         - Indicates how and which key should be chaned:
+   *                       possilbe values are: AUTHKEY, PRIVKEY and
+   *                       OWNAUTHKEY, OWNPRIVKEY.
+   * @param status       - The return status: SNMPv3_USM_OK or one of the
+   *                       error codes
+   *
+   * @return - A structure, that is needed to commit/abort the key update.
+   *           If an error occurs, the return value is NULL
+   */
+  struct UsmKeyUpdate* key_update_prepare(const OctetStr& securityName,
+                                         SnmpTarget& target,
+                                         const OctetStr& newPassword,
+                                         Pdu& pdu, int type,
+                                         int &status,
+                                         const OctetStr& oldpass = "",
+                                         const OctetStr& oldengid= "",
+                                         const OctetStr& newengid= "");
+
+  /**
+   * Abort the local key update.
+   *
+   * @param uku - The pointer returned by usmPrepareKeyUpdate()
+   */
+  void key_update_abort(struct UsmKeyUpdate *uku);
+
+
+  /**
+   * Commit the local key update.
+   *
+   * @param uku - The pointer returned by usmPrepareKeyUpdate()
+   * @param update_type - One of USM_KeyUpdate, USM_PasswordKeyUpdate,
+   *                      USM_PasswordAllKeyUpdate
+   *
+   * @return - SNMPv3_USM_ERROR, SNMPv3_USM_OK
+   */
+  int key_update_commit(struct UsmKeyUpdate *uku, int update_type);
+
+
+  /**
+   * Get a pointer to the AuthPriv object used by the USM.
+   *
+   */
+  AuthPriv *get_auth_priv();
+
+
+  /**
+   * Return engineBoots and engineTime for a given engineID
+   *
+   * @param  engine_id    - The engineID of the SNMP entity
+   * @param  engine_boots - OUT: boot counter (0 if not found)
+   * @param  engine_time  - OUT: engine time (0 if not found)
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (entry found, values are filled)
+   *           SNMPv3_USM_UNKNOWN_ENGINEID ( not found)
+   */
+  int get_time(const OctetStr &engine_id,
+              long int *engine_boots, long int *engine_time);
+
+
+
+  /**
+   * Return engineBoots and engineTime of the local snmp entity
+   *
+   * @param engine_boots - OUT: boot counter (0 if not found)
+   * @param engine_time  - OUT: engine time (0 if not found)
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (entry found, values are filled)
+   */
+  int get_local_time(long int *engine_boots, long int *engine_time) const;
+
+
+  /**
+   * Return the local snmp engine id.
+   */
+  const OctetStr& get_local_engine_id() const { return local_snmp_engine_id; };
+
+  /**
+   * Get the number of received messages with an unsupported securityLevel
+   *
+   * @return - usmStatsUnsupportedSecLevels
+   */
+  unsigned long get_stats_unsupported_sec_levels() const
+    { return usmStatsUnsupportedSecLevels; };
+
+  /**
+   * Get the number of received messages outside time window
+   *
+   * @return - usmStatsNotInTimeWindows
+   */
+  unsigned long get_stats_not_in_time_windows() const
+    { return usmStatsNotInTimeWindows; };
+
+  /**
+   * Get the number of received messages with a unknown userName
+   *
+   * @return - usmStatsUnknownUserNames
+   */
+  unsigned long get_stats_unknown_user_names() const
+    { return usmStatsUnknownUserNames; };
+
+  /**
+   * Get the number of received messages with a unknown engineID
+   *
+   * @return - usmStatsUnknownEngineIDs
+   */
+  unsigned long get_stats_unknown_engine_ids() const
+    { return usmStatsUnknownEngineIDs; };
+
+  /**
+   * Get the number of received messages with a wrong digest
+   *
+   * @return - usmStatsWrongDigests
+   */
+  unsigned long get_stats_wrong_digests() const
+    { return usmStatsWrongDigests; };
+
+  /**
+   * Get the number of received messages with decryption errors
+   *
+   * @return - usmStatsDecryptionErrors
+   */
+  unsigned long get_stats_decryption_errors() const
+    { return usmStatsDecryptionErrors; };
+
+  //@{
+  /**
+   * Increase the stats counter. Should only be used by agent++.
+   */
+  void inc_stats_unsupported_sec_levels();
+  void inc_stats_not_in_time_windows();
+  void inc_stats_unknown_user_names();
+  void inc_stats_unknown_engine_ids();
+  void inc_stats_wrong_digests();
+  void inc_stats_decryption_errors();
+  //@}
+
+  /**
+   * Lock the UsmUserNameTable for access through peek_first_user()
+   * and peek_next_user().
+   */
+  void lock_user_name_table();
+
+  /**
+   * Get a const pointer to the first entry of the UsmUserNameTable.
+   *
+   * @note Use lock_user_name_table() and unlock_user_name_table()
+   *       for thread safety.
+   */
+  const UsmUserNameTableEntry *peek_first_user();
+
+  /**
+   * Get a const pointer to the next entry of the UsmUserNameTable.
+   *
+   * @note Use lock_user_name_table() and unlock_user_name_table()
+   *       for thread safety.
+   */
+  const UsmUserNameTableEntry *peek_next_user(const UsmUserNameTableEntry *e);
+
+  /**
+   * Unlock the UsmUserNameTable after access through peek_first_user()
+   * and peek_next_user().
+   */
+  void unlock_user_name_table();
+
+  /**
+   * Lock the UsmUserTable for access through peek_first_luser()
+   * and peek_next_luser().
+   */
+  void lock_user_table();
+
+  /**
+   * Get a const pointer to the first entry of the UsmUserTable.
+   *
+   * @note Use lock_user_table() and unlock_user_table()
+   *       for thread safety.
+   */
+  const UsmUserTableEntry *peek_first_luser();
+
+  /**
+   * Get a const pointer to the next entry of the UsmUserTable.
+   *
+   * @note Use lock_user_table() and unlock_user_table()
+   *       for thread safety.
+   */
+  const UsmUserTableEntry *peek_next_luser(const UsmUserTableEntry *e);
+
+  /**
+   * Unlock the UsmUserTable after access through peek_first_luser()
+   * and peek_next_luser().
+   */
+  void unlock_user_table();
+
+  /**
+   * for v3MP:
+   *
+   * Delete the pointers within the structure and the structure
+   * itself.
+   *
+   * @param ssr - The structure that should be deleted.
+   */
+  void delete_sec_state_reference(struct SecurityStateReference *ssr);
+
+  /**
+   * Protected (for agent++):
+   *
+   * Get the user at the specified position of the usmUserTable.
+   *
+   * The returned pointer must NOT be deleted!
+   *
+   * @note lock_user_table() and unlock_user_table() must be used
+   *       for thread synchronization.
+   *
+   * @param number - get the entry at position number (1...)
+   *
+   * @return - a pointer to the structure or NULL if number is out
+   *           of range
+   */
+  const struct UsmUserTableEntry *get_user(int number);
+
+  /**
+   * Get the properties of the specified user.
+   *
+   * The returned pointer must NOT be deleted!
+   *
+   * @note lock_user_table() and unlock_user_table() must be used
+   *       for thread synchronization.
+   *
+   * @param security_name - The security name of the user
+   *
+   * @return - a pointer to the structure or NULL if number is out
+   *           of range
+   */
+  const struct UsmUserNameTableEntry *get_user(const OctetStr &security_name);
+
+  /**
+   * Protected (for agent++):
+   *
+   * Get the number of elements in the usmUserTable
+   *
+   * @note lock_user_table() and unlock_user_table() must be used
+   *       for thread synchronization.
+   *
+   * @return - number of elements
+   */
+  int get_user_count() const;
+
+
+  /**
+   * Protected (for agent++)
+   *
+   * Register a callback function that is called if a new localized user
+   * has been added to the usm user table
+   */
+  void add_user_added_callback(const usm_add_user_callback cb);
+
+
+ protected:
+
+  /**
+   * Get a new security state reference (for v3MP).
+   *
+   * @return - A newly created security state reference.
+   */
+  struct SecurityStateReference *get_new_sec_state_reference();
+
+  /**
+   * Generate a complete message that is ready to send to the target.
+   *
+   * @param globalData       - Buffer containing the serialized globalData,
+   *                           ready to be copied into the wholeMsg
+   * @param globalDataLength - The length of this buffer
+   * @param maxMessageSize   - The maximum message size
+   * @param securityEngineID - The engineID of the authoritative SNMP entity
+   * @param securityName     - The name of the user
+   * @param securityLevel    - The security Level for this Message
+   * @param scopedPDU        - Buffer containing the serialized scopedPDU,
+   *                           ready to be copied into the wholeMsg
+   * @param scopedPDULength  - The length of this Buffer
+   * @param securityStateReference - The reference that was generated when
+   *                                 the request was parsed. For request, this
+   *                                 param has to be NULL. The reference
+   *                                 is deleted by this function.
+   * @param wholeMsg         - OUT: the buffer for the whole message
+   * @param wholeMsgLength   - IN:  lenght of the buffer.
+   *                           OUT: length of the generated message
+   *
+   * @return - SNMPv3_USM_OK on success. See snmperrs.h for the error codes
+   *           of the USM.
+   */
+  int generate_msg(
+             unsigned char *globalData,       // message header, admin data
+             int globalDataLength,
+             int maxMessageSize,              // of the sending SNMP entity
+             const OctetStr &securityEngineID,// authoritative SNMP entity
+             const OctetStr &securityName,    // on behalf of this principal
+             int  securityLevel,              // Level of Security requested
+             unsigned char  *scopedPDU,       // message (plaintext) payload
+             int scopedPDULength,
+             struct SecurityStateReference *securityStateReference,
+             unsigned char *wholeMsg,         // OUT complete generated message
+             int *wholeMsgLength);            // OUT length of generated message
+
+
+
+  /**
+   * Parse a received message.
+   *
+   * @param maxMessageSize         - The maximum message size of the snding
+   *                                 SNMP entity.
+   * @param securityParameters     - The security parameters as received
+   * @param securityParametersLength - The length of the security parameters
+   * @param securityParametersPosition - The position of the security
+   *                                     parameters in the message
+   * @param securityLevel          - The securityLevel of the message
+   * @param wholeMsg               - The buffer with the whole message
+   * @param wholeMsgLength         - The length of the whole message
+   * @param msgData                - The buffer with the messageData
+   * @param msgDataLength          - The length of the messageData buffer
+   * @param security_engine_id     - OUT: the authoritative engineID
+   * @param security_name          - OUT: the name of the user
+   * @param scopedPDU              - OUT: buffer containing the scopedPDU
+   * @param scopedPDULength        - IN: length of the buffer
+   *                                 OUT: length of the scopedPDU
+   * @param maxSizeResponseScopedPDU - OUT: maximum size for a scopedPDU in a
+   *                                        response message
+   * @param securityStateReference - OUT: the securityStateReference
+   * @param fromAddress            - IN: Address of the sender
+   *
+   * @return - SNMPv3_USM_OK on success. See snmperrs.h for the error codes
+   *           of the USM.
+   */
+  int process_msg(
+           int maxMessageSize,                // of the sending SNMP entity
+           unsigned char *securityParameters, // for the received message
+           int securityParametersLength,
+           int securityParametersPosition,
+           long int securityLevel,            // Level of Security
+           unsigned char *wholeMsg,           // as received on the wire
+           int wholeMsgLength,                // length as received on the wire
+           unsigned char *msgData,
+           int msgDataLength,
+          OctetStr &security_engine_id,      // authoritative SNMP entity
+          OctetStr &security_name,           //identification of the principal
+           unsigned char *scopedPDU,          // message (plaintext) payload
+           int *scopedPDULength,
+           long *maxSizeResponseScopedPDU,// maximum size of the Response PDU
+           struct SecurityStateReference *securityStateReference,
+                                            // reference to security state
+                                            // information, needed for response
+           const UdpAddress &fromAddress);  // Address of the sender
+
+private:
+
+  /**
+   * Delete the pointers in the structure and set all values to 0/NULL.
+   *
+   * @param usp - The structure that should be deleted
+   */
+  void delete_sec_parameters( struct UsmSecurityParameters *usp);
+
+
+  /**
+   * Serialize the given values into the buffer according to the BER.
+   *
+   *  UsmSecurityParameters ::=
+   *      SEQUENCE {
+   *      -- global User-based security parameters
+   *          msgAuthoritativeEngineID     OCTET STRING (5..32)
+   *          msgAuthoritativeEngineBoots  INTEGER (0..2147483647),
+   *          msgAuthoritativeEngineTime   INTEGER (0..2147483647),
+   *          msgUserName                  OCTET STRING (SIZE(0..32)),
+   *       -- authentication protocol specific parameters
+   *          msgAuthenticationParameters  OCTET STRING,
+   *       -- privacy protocol specific parameters
+   *          msgPrivacyParameters         OCTET STRING
+   *      }
+   *
+   * @param outBuf    - buffer for the serialized values
+   * @param maxLength - before call: length of the buffer
+   *                    after call: bytes left in the buffer
+   * @param sp        - the values to serialize
+   * @param position  - after call: points to the first byte of the
+   *                    field for the authentication parameter
+   *
+   * @return - a pointer to the first free byte in the buffer,
+   *           NULL on error
+   */
+  unsigned char *build_sec_params(unsigned char *outBuf, int *maxLength,
+                                  struct UsmSecurityParameters sp,
+                                  int *position);
+
+  /**
+   * Serialize the given values acording to the BER into the
+   * buffer. On success, the buffer contains a valid SNMPv3 message.
+   *
+   * @param outBuf             - buffer for the serialized values
+   * @param maxLength          - before call: length of the buffer
+   *                             after call: bytes left in the buffer
+   * @param globalData         - Buffer that contains the serialized globalData
+   * @param globalDataLength   - The length of this buffer
+   * @param positionAuthPar    - after call: points to the first byte of the
+   *                             field for the authentication parameter
+   * @param securityParameters - The security parameters
+   * @param msgData            - Buffer that contains the serialized msgData
+   * @param msgDataLength      - The length of this buffer
+   *
+   * @return - a pointer to the first free byte in the buffer,
+   * NULL on error
+   */
+  unsigned char *build_whole_msg(
+                      unsigned char *outBuf, int *maxLength,
+                      unsigned char *globalData, long int globalDataLength,
+                      int *positionAuthPar,
+                      struct UsmSecurityParameters  securityParameters,
+                      unsigned char *msgData, long int msgDataLength);
+
+
+  /**
+   * Delete the pointers in the structure
+   *
+   * @param user - The structure that should be deleted
+   */
+  inline void delete_user_ptr(struct UsmUser *user);
+
+
+ private:
+
+  OctetStr local_snmp_engine_id; ///< local snmp engine id
+  const v3MP *v3mp;          ///< Pointer to the v3MP that created this object
+
+  // 0: don't accept messages from hosts with a unknown engine id
+  bool discovery_mode;
+
+   // MIB Counters
+   unsigned int usmStatsUnsupportedSecLevels;
+   unsigned int usmStatsNotInTimeWindows;
+   unsigned int usmStatsUnknownUserNames;
+   unsigned int usmStatsUnknownEngineIDs;
+   unsigned int usmStatsWrongDigests;
+   unsigned int usmStatsDecryptionErrors;
+
+   // the instance of AuthPriv
+   AuthPriv *auth_priv;
+
+   // this table contains time values of contacted snmp entities
+   USMTimeTable *usm_time_table;
+
+   // Users that are known but not localized to a engine ID
+   USMUserNameTable *usm_user_name_table;
+
+   // Table containing localized Users ready to use
+   USMUserTable *usm_user_table;
+
+   // Callback for agent++ to indicate new users in usm tables
+   usm_add_user_callback usm_add_user_cb;
+
+};
+
+
+// only for compatibility do not use these values and functions:
+// =============================================================
+
+#define SecurityLevel_noAuthNoPriv    SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV
+#define SecurityLevel_authNoPriv      SNMP_SECURITY_LEVEL_AUTH_NOPRIV
+#define SecurityLevel_authPriv        SNMP_SECURITY_LEVEL_AUTH_PRIV
+
+#define SNMPv3_usmNoAuthProtocol      SNMP_AUTHPROTOCOL_NONE
+#define SNMPv3_usmHMACMD5AuthProtocol SNMP_AUTHPROTOCOL_HMACMD5
+#define SNMPv3_usmHMACSHAAuthProtocol SNMP_AUTHPROTOCOL_HMACSHA
+
+#define SNMPv3_usmNoPrivProtocol     SNMP_PRIVPROTOCOL_NONE
+#define SNMPv3_usmDESPrivProtocol    SNMP_PRIVPROTOCOL_DES
+#define SNMPv3_usmIDEAPrivProtocol   SNMP_PRIVPROTOCOL_IDEA
+#define SNMPv3_usmAES128PrivProtocol SNMP_PRIVPROTOCOL_AES128
+#define SNMPv3_usmAES192PrivProtocol SNMP_PRIVPROTOCOL_AES192
+#define SNMPv3_usmAES256PrivProtocol SNMP_PRIVPROTOCOL_AES256
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // _SNMPv3
+
+#endif
diff --git a/3rdparty/snmp++/include/snmp_pp/uxsnmp.h b/3rdparty/snmp++/include/snmp_pp/uxsnmp.h
new file mode 100644 (file)
index 0000000..467f1cb
--- /dev/null
@@ -0,0 +1,665 @@
+/*_############################################################################
+  _## 
+  _##  uxsnmp.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+#ifndef _UXSNMP_H_
+#define _UXSNMP_H_
+
+#include "snmp_pp/reentrant.h"
+#include "snmp_pp/target.h"
+#include "snmp_pp/oid.h"
+#include "snmp_pp/address.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define SNMP_PP_WITH_UDPADDR // Snmp class has constructor with UdpAddress
+
+//-----[ internally used defines ]----------------------------------------
+#define MAXNAME 80                   // maximum name length
+#define MAX_ADDR_LEN 10              // maximum address len, ipx is 4+6
+#define SNMP_SHUTDOWN_MSG 0x0400+177 // shut down msg for stoping a blocked message
+#ifndef INVALID_SOCKET 
+#define INVALID_SOCKET ((SnmpSocket)(~0)) // value for invalid socket
+#endif
+
+//-----[ async defines for engine ]---------------------------------------
+#define sNMP_PDU_GET_ASYNC       21
+#define sNMP_PDU_GETNEXT_ASYNC   22
+#define sNMP_PDU_SET_ASYNC       23
+#define sNMP_PDU_GETBULK_ASYNC   24
+#define sNMP_PDU_INFORM_ASYNC    25
+
+//-----[ trap / notify macros ]-------------------------------------------
+#define IP_NOTIFY  162     // IP notification
+#define IPX_NOTIFY 0x2121  // IPX notification
+
+//------[ forward declaration of Snmp class ]-----------------------------
+class Snmp;
+class EventListHolder;
+class Pdu;
+class v3MP;
+
+//-----------[ async methods callback ]-----------------------------------
+/**
+ * Async methods of the class Snmp require the caller to provide a
+ * callback address of a function with this typedef.
+ *
+ * @note It is not allowed to call any synchronous Snmp methods within the
+ *       callback. Async methods are allowed.
+ *
+ * @param reason  - Reason for callback (see snmperrs.h)
+ * @param session - Pointer to Snmp object that was used to send the request
+ * @param pdu     - The received Pdu if reason indicates a received message
+ * @param target  - source target
+ * @param data    - Pointer passed to the async method
+ */
+typedef void (*snmp_callback)(int reason, Snmp *session,
+                               Pdu &pdu, SnmpTarget &target, void *data);
+
+
+//------------[ SNMP Class Def ]---------------------------------------------
+//
+/**
+ * SNMP class defintion. The Snmp class provides an object oriented
+ * approach to SNMP. The SNMP class is an encapsulation of SNMP
+ * sessions, gets, sets and get nexts. The class manages all SNMP
+ * resources and provides complete retry and timeout capability.
+ *
+ * This class is thread save.
+ *
+ * @note If you use the async methods to send requests you MUST call
+ *       Snmp::eventListHolder->SNMPProcessPendingEvents() while waiting
+ *       for the responses. This function triggers the resend of
+ *       packets and calls your callback function if the response is
+ *       received.
+ *
+ * @note Call srand() before creating the first Snmp object.
+ */
+class DLLOPT Snmp: public SnmpSynchronized
+{
+ public:
+  //------------------[ constructors ]----------------------------------
+
+  /** @name Constructors and Destructor */
+  //@{
+
+  /**
+   * Construct a new SNMP session using the given UDP port.
+   *
+   * @param status
+   *    after creation of the session this parameter will 
+   *    hold the creation status.
+   * @param port
+   *    an UDP port to be used for the session
+   * @param bind_ipv6
+   *    Set this to true if IPv6 should be used. The default is
+   *    IPv4.
+   */
+  Snmp(int &status, const unsigned short port = 0,
+       const bool bind_ipv6 = false);
+
+  /**
+   * Construct a new SNMP session using the given UDP address.
+   * Thus, binds the session on a specific IPv4 or IPv6 address. 
+   *
+   * @param status
+   *    after creation of the session this parameter will 
+   *    hold the creation status.
+   * @param addr
+   *    an UDP address to be used for the session
+   */  
+  Snmp(int &status, const UdpAddress &addr);
+
+  /**
+   * Construct a new SNMP session using the given UDP addresses.
+   * Using this constructor will bind to both IPv4 and IPv6 ports.
+   *
+   * @param status
+   *    after creation of the session this parameter will 
+   *    hold the creation status.
+   * @param addr_v4
+   *    an IPv4 UDP address to be used for the session
+   * @param addr_v6
+   *    an IPv6 UDP address to be used for the session
+   */  
+  Snmp(int &status,  const UdpAddress& addr_v4, const UdpAddress& addr_v6);
+
+  //-------------------[ destructor ]------------------------------------
+  /**
+   * Destructor.
+   */
+  virtual ~Snmp();
+
+  //@}
+
+  //--------[ Get the version of the snmp++ library ]--------------------
+  /**
+   * Get the version of the snmp++ library.
+   *
+   * @return The version of the snmp++ lib at runtime.
+   */
+  static const char *get_version();
+
+
+  //-------------------[ returns error string ]--------------------------
+  /**
+   * Returns a human readable error string.
+   *
+   * @param c - Error code returned by any method of this class
+   * @return Null terminated error string.
+   */
+  static const char *error_msg(const int c);
+#ifdef _SNMPv3
+  /**
+   * Returns a human readable error string.
+   * If a report message is returned, then the contained Oid can be
+   * used to get a error string.
+   *
+   * @param v3Oid - Oid of a SNMPv3 report Pdu
+   * @return Null terminated error string.
+   */
+  static const char* error_msg(const Oid& v3Oid);
+#endif
+
+  //------------------------[ Windows Sockets ]----------------------------
+
+  /**
+   * Initialize the Winsock library (WSAStartup).
+   *
+   * @note on Win32 this method *must* be called before creating Snmp or
+   *       Address objects.
+   */
+  static void socket_startup();
+
+
+  /**
+   * Shut down the Winsock library (WSACleanup).
+   */
+  static void socket_cleanup();
+
+  //------------------------[ send requests ]------------------------------
+
+  /** @name Sending SNMP Pdus
+   */
+  //@{
+
+  /**
+   * Send a blocking SNMP-GET request.
+   *
+   * @param pdu    - Pdu to send
+   * @param target - Target for the get
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int get(Pdu &pdu, const SnmpTarget &target);
+
+  /**
+   * Send a async SNMP-GET request.
+   *
+   * @param pdu      - Pdu to send
+   * @param target   - Target for the get
+   * @param callback - User callback function to use
+   * @param callback_data - User definable data pointer
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int get(Pdu &pdu, const SnmpTarget &target,
+                 const snmp_callback callback,
+                 const void *callback_data = 0);
+
+  /**
+   * Send a blocking SNMP-GETNEXT request.
+   *
+   * @param pdu    - Pdu to send
+   * @param target - Target for the getnext
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int get_next(Pdu &pdu, const SnmpTarget &target);
+
+  /**
+   * Send a async SNMP-GETNEXT request.
+   *
+   * @param pdu      - Pdu to send
+   * @param target   - Target for the getnext
+   * @param callback - User callback function to use
+   * @param callback_data - User definable data pointer
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int get_next(Pdu &pdu, const SnmpTarget &target,
+                       const snmp_callback callback,
+                      const void *callback_data = 0);
+
+  /**
+   * Send a blocking SNMP-SET request.
+   *
+   * @param pdu    - Pdu to send
+   * @param target - Target for the set
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int set(Pdu &pdu, const SnmpTarget &target);
+
+  /**
+   * Send a async SNMP-SET request.
+   *
+   * @param pdu      - Pdu to send
+   * @param target   - Target for the set
+   * @param callback - User callback function to use
+   * @param callback_data - User definable data pointer
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int set(Pdu &pdu, const SnmpTarget &target,
+                 const snmp_callback callback,
+                 const void * callback_data = 0);
+
+  /**
+   * Send a blocking SNMP-GETBULK request.
+   *
+   * @param pdu           - Pdu to send
+   * @param target        - Target for the getbulk
+   * @param non_repeaters - number of non repeaters
+   * @param max_reps      - maximum number of repetitions
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int get_bulk(Pdu &pdu, const SnmpTarget &target,
+                      const int non_repeaters, const int max_reps);
+
+  /**
+   * Send a async SNMP-GETBULK request.
+   *
+   * @param pdu           - Pdu to send
+   * @param target        - Target for the getbulk
+   * @param non_repeaters - number of non repeaters
+   * @param max_reps      - maximum number of repetitions
+   * @param callback      - User callback function to use
+   * @param callback_data - User definable data pointer
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int get_bulk(Pdu &pdu, const SnmpTarget &target,
+                      const int non_repeaters, const int max_reps,
+                      const snmp_callback callback,
+                      const void *callback_data = 0);
+
+  /**
+   * Send a SNMP-TRAP.
+   *
+   * @param pdu    - Pdu to send
+   * @param target - Target for the trap
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int trap(Pdu &pdu, const SnmpTarget &target);
+
+
+  /**
+   * Send a SNMPv3-REPORT.
+   *
+   * @param pdu    - Pdu to send
+   * @param target - Target for the report (must be a UTarget)
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int report(Pdu &pdu, const SnmpTarget &target);
+
+  /**
+   * Send a blocking INFORM-REQ.
+   *
+   * @param pdu    - Pdu to send
+   * @param target - Target for the inform
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int inform(Pdu &pdu, const SnmpTarget &target);
+
+  /**
+   * Send a async INFORM-REQ.
+   *
+   * @param pdu    - Pdu to send
+   * @param target - Target for the inform
+   * @param callback      - User callback function to use
+   * @param callback_data - User definable data pointer
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int inform(Pdu &pdu, const SnmpTarget &target,
+                    const snmp_callback callback,
+                    const void * callback_data = 0);
+
+  /**
+   * Send a RESPONSE.
+   *
+   * @param pdu    - Pdu to send
+   * @param target - Target for the response
+   * @param fd     - file descriptor to use, should be the one
+   *                 that was passed to the callback function
+   *
+   * @return SNMP_CLASS_SUCCES or a negative error code
+   */
+  virtual int response(Pdu &pdu, const SnmpTarget &target,
+                      const SnmpSocket fd = INVALID_SOCKET);
+
+
+  /**
+   * Send a SNMP Broadcast message.
+   *
+   * This member function sends out a valid SNMP message to a
+   * broadcast address and waits for responses. The source addresses
+   * of the response messages are added to the collection.
+   *
+   * The message is sent only once.
+   *
+   * @note SNMP_BROADCAST has to be defined in config_snmp_pp.h.
+   *
+   * @note There is no SNMP standard that defines "SNMP Broadcast
+   *       discovery". SNMP agents are not forced to answer requests
+   *       that are sent to a broadcast address.
+   *
+   * @note Do not use this method while waiting for other responses,
+   *       as these responses will be added to the collection and dropped
+   *       by this method. Solution for this problem: Use a special
+   *       Snmp object only for broadcasts.
+   *
+   * @param addresses   - The addresses of the agents, that answered.
+   * @param timeout_sec - Timeout in seconds
+   * @param addr        - Broadcast address
+   * @param version     - SNMP version to use
+   * @param community   - Only needed for SNMPv1/v2c, defaults to "public"
+   *
+   */
+  virtual int broadcast_discovery(UdpAddressCollection &addresses,
+                                 const int timeout_sec,
+                                 const UdpAddress &addr,
+                                 const snmp_version version,
+                                 const OctetStr *community = 0);
+
+#ifdef _SNMPv3
+  virtual int engine_id_discovery(OctetStr &engine_id,
+                                 const int timeout_sec,
+                                 const UdpAddress &addr);
+#endif
+  //@}
+
+  /**
+   * Cancel a pending request.
+   *
+   * @param rid - The request id to cancel
+   *
+   * @return SNMP_CLASS_SUCCES or SNMP_CLASS_INVALID_REQID on failure
+   */
+  virtual int cancel(const unsigned long rid);
+
+
+  /** @name Trap and Inform handling
+   */
+  //@{
+
+  /**
+   * Set the port for listening to traps and informs.
+   *
+   * @note This function must be called before notify_register(),
+   *       otherwise the default port is used.
+   */
+  virtual void notify_set_listen_port(const int port);
+
+  /**
+   * Get the port that is used for listening to traps and informs.
+   */
+  virtual int notify_get_listen_port();
+
+  /**
+   * Register to get traps and informs.
+   *
+   * @note Every call to one of the notify_register() methods overwrites
+   *       the previous given values.
+   *
+   * @param trapids       - ids to listen for
+   * @param targets       - targets to listen for
+   * @param callback      - User callback function to use
+   * @param callback_data - User definable data pointer
+   *
+   * @return SNMP_CLASS_SUCCESS, SNMP_CLASS_TL_FAILED or SNMP_CLASS_TL_IN_USE
+   */
+  virtual int notify_register(const OidCollection    &trapids,
+                              const TargetCollection &targets,
+                              const snmp_callback callback,
+                              const void *callback_data=0);
+
+  /**
+   * Unregister to get traps and informs.
+   * Undo the call to notify_register().
+   *
+   * @return Always SNMP_CLASS_SUCCESS
+   */
+  virtual int notify_unregister();
+
+  /**
+   * Get notify register info.
+   *
+   * @param trapids       - ids listened for
+   * @param targets       - targets listened for
+   *
+   * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_INVALID if not registered
+   */
+  virtual int get_notify_filter(OidCollection &trapids,
+                                TargetCollection &targets);
+
+  //-----------------------[ access the trap reception info ]---------------
+  /**
+   * Get a pointer to the callback function used for trap reception.
+   *
+   * @return Pointer to the function set through notify_register()
+   */
+  snmp_callback get_notify_callback() { return notifycallback; };
+
+  /**
+   * Get a pointer to the data that is passed to the callback function.
+   *
+   * @return Pointer to the data set through notify_register()
+   */
+  void *get_notify_callback_data() { return notifycallback_data; };
+
+  //@}
+
+  /**
+   * Send raw UDP data.
+   * This method may be used to send any data to the recepient.
+   *
+   * @param send_buf - Data buffer
+   * @param send_len - Length of the data
+   * @param address  - Recepient
+   * @param fd       - socket to use, if not specified, the socket of the
+   *                   object is used
+   *
+   * @return 0 on success, -1 on failure
+   */
+  virtual int send_raw_data(unsigned char *send_buf,
+                            size_t send_len, UdpAddress &address,
+                            SnmpSocket fd = INVALID_SOCKET);
+
+  const IpAddress &get_listen_address() const {return listen_address; };
+
+  /**
+   * Start one thread listening for responses and notifications.
+   * This method is used to start response and notification processing in a
+   * multi threadded setup.
+   *
+   * @note start_poll_thread() itself is not thread safe. The caller must make
+   *       sure that only one thread is calling start_poll_thread() or
+   *       stop_poll_thread() at any point in time.
+   *
+   * @param timeout - Timeout for each call of the select() or poll()
+   *                  system call.
+   *
+   * @return true if the thread is now running and false if it failed to start.
+   */
+  bool start_poll_thread(const int timeout);
+
+  /**
+   * Stop the thread listening for responses and notifications.
+   * This method is used to stop the thread started with start_poll_thread().
+   *
+   * @note stop_poll_thread() itself is not thread safe. The caller must make
+   *       sure that only one thread is calling start_poll_thread() or
+   *       stop_poll_thread() at any point in time.
+   */
+  void stop_poll_thread();
+
+  EventListHolder *get_eventListHolder() { return eventListHolder; };
+
+protected:
+
+  /**
+   * Check for the status of the worker thread.
+   * @return BOOL - TRUE - if running, FALSE - otherwise
+   */
+  bool is_running(void) const
+      { return m_bThreadRunning; };
+       
+  /**
+   * This is a working thread for the recovery of the pending events.
+   *
+   * @param pSnmp [in] pointer to the whole object
+   *
+   * @return int
+   *          0 - if succesful,
+   *          1 - in the case of error
+   */
+#ifdef WIN32
+  static int process_thread(Snmp *pSnmp);
+#else
+  static void* process_thread(void *arg);
+#endif
+
+ protected:
+
+  /**
+   * Generate a unique (for this Snmp obect) request id.
+   *
+   * @return Unique id between PDU_MIN_RID and PDU_MAX_RID
+   */
+  long MyMakeReqId();
+
+  /**
+   * Common init function used by constructors.
+   */
+  void init(int& status, IpAddress*[2],
+            const unsigned short port_v4, const unsigned short port_v6);
+
+  /**
+   * Set the notify timestamp of a trap pdu if the user did not set it.
+   */
+  void check_notify_timestamp(Pdu &pdu);
+
+  //-----------[ Snmp Engine ]----------------------------------------
+  /**
+   * gets, sets and get nexts go through here....
+   * This mf does all snmp sending and reception
+   * except for traps which are sent using trap().
+   *
+   * @note that for a UTarget with an empty engine id the
+   *       Utarget::set_engine_id() may be called.
+   */
+  int snmp_engine( Pdu &pdu,                  // pdu to use
+                   long int non_reps,         // get bulk only
+                   long int max_reps,         // get bulk only
+                   const SnmpTarget &target,        // destination target
+                   const snmp_callback cb,    // async callback function
+                   const void *cbd,          // callback data
+                  SnmpSocket fd = INVALID_SOCKET,
+                  int reports_received = 0);
+
+  //--------[ map action ]------------------------------------------------
+  // map the snmp++ action to a SMI pdu type
+  void map_action(unsigned short action, unsigned short &pdu_action);
+
+#ifdef _SNMPv3
+  /**
+   * Internal used callback data structure for async v3 requests.
+   */
+  struct V3CallBackData
+  {
+    Pdu *pdu;                  ///< The Pdu that was sent
+    long int non_reps;         ///< For GET-BULK requests
+    long int max_reps;         ///< For GET-BULK requests
+    SnmpTarget *target;        ///< Pointer to the Target object to use
+    snmp_callback oldCallback; ///< User callback function
+    const void *cbd;           ///< User callback data
+    int reports_received;      ///< How many reports are already received
+  };
+
+  friend void v3CallBack(int reason, Snmp *snmp, Pdu &pdu,
+                        SnmpTarget &target, void *v3cd);
+  friend void deleteV3Callback(struct Snmp::V3CallBackData *&cbData);
+#endif
+
+  //---[ instance variables ]
+  SnmpSocket iv_snmp_session;
+#ifdef SNMP_PP_IPv6
+  SnmpSocket iv_snmp_session_ipv6;
+#endif
+
+  IpAddress listen_address;
+  long current_rid;                   // current rid to use
+
+  // inform receive member variables
+  snmp_callback  notifycallback;
+  void * notifycallback_data;
+
+  // this member var will simulate a global var
+  EventListHolder *eventListHolder;
+
+private:
+
+  bool m_bThreadRunning;
+  int m_iPollTimeOut;
+
+  // Keep track of the thread.
+#ifdef _THREADS
+#ifdef WIN32
+  HANDLE m_hThread;
+  HANDLE m_hThreadEndEvent;
+#elif defined (CPU) && CPU == PPC603
+  int m_hThread;
+#else
+  pthread_t m_hThread;
+#endif
+#endif
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif
diff --git a/3rdparty/snmp++/include/snmp_pp/v3.h b/3rdparty/snmp++/include/snmp_pp/v3.h
new file mode 100644 (file)
index 0000000..f63440a
--- /dev/null
@@ -0,0 +1,283 @@
+/*_############################################################################
+  _## 
+  _##  v3.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+// $Id: v3.h 288 2007-03-22 22:37:09Z katz $
+
+#ifndef _V3_H
+#define _V3_H
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+class OctetStr;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/** @name SNMPv3 Security Model values
+ */
+//@{
+#define SNMP_SECURITY_MODEL_ANY  0 //!< Not used in SNMP++.
+#define SNMP_SECURITY_MODEL_V1   1 //!< Can be used for SNMPv1 only.
+#define SNMP_SECURITY_MODEL_V2   2 //!< Can be used for SNMPv2 only.
+#define SNMP_SECURITY_MODEL_USM  3 //!< Can be used for SNMPv3 only.
+//@}
+
+/**
+ * Set the amount of log messages you want to get. To disable all
+ * messages, set the level to -1
+ *
+ * @param db_level - New level
+ */
+DLLOPT void debug_set_level(const int db_level);
+
+#ifdef _DEBUG
+
+/**
+ * SNMP++ logging function.
+ *
+ * The default is to log all messages with a level < 19. To change
+ * that either edit v3.cpp or use a "extern unsigned int debug_level"
+ * to change the level.
+ *
+ * @param db_level - Priority of the message (0 = high)
+ * @param format   - Just like printf
+ */
+DLLOPT void debugprintf(int db_level, const char *format, ...);
+
+/**
+ * SNMP++ logging function for hex strings.
+ *
+ * @param db_level - Priority of the message (0 = high)
+ * @param comment  - Comment printed before the hex dump (may be 0)
+ * @param data     - pointer to the hex data
+ * @param len      - length of the hex data
+ */
+DLLOPT void debughexcprintf(int db_level, const char* comment,
+                            const unsigned char *data, const unsigned int len);
+
+//! Wrapper for debughexcprintf() without comment.
+#define debughexprintf(db_level, data, len) \
+                      debughexcprintf(db_level, NULL, data, len);
+
+#else
+
+#ifndef _MSC_VER
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#define debugprintf(db_level,format...)
+#else
+void debugprintf(int db_level, const char *format, ...);
+#endif
+#else
+// disable any warning for wrong number of arguments in macro
+#pragma warning(disable:4002)
+#define debugprintf(db_level,format)
+#endif //_MSC_VER
+
+#define debughexprintf( db_level,          data, len)
+#define debughexcprintf(db_level, comment, data, len)
+
+#endif
+
+#ifdef _SNMPv3
+
+#define MAXLENGTH_ENGINEID       32
+#define MAXLENGTH_CONTEXT_NAME   32
+#define MAXLENGTH_FILENAME       255
+#define MAXLENGTH_GLOBALDATA     42 // (2 + 1) + 7 + 7 + 3 + 7 + security
+
+#define oidV3SnmpEngine                 "1.3.6.1.6.3.10.2.1"
+#define oidV3SnmpEngineID               "1.3.6.1.6.3.10.2.1.1.0"
+#define oidV3SnmpEngineBoots            "1.3.6.1.6.3.10.2.1.2.0"
+#define oidV3SnmpEngineTime             "1.3.6.1.6.3.10.2.1.3.0"
+#define oidV3SnmpEngineMaxMessageSize   "1.3.6.1.6.3.10.2.1.4.0"
+
+// also defined in agent++/include/vacm.h
+#ifndef oidSnmpUnavailableContexts
+#define oidSnmpUnavailableContexts        "1.3.6.1.6.3.12.1.4.0"
+#define oidSnmpUnknownContexts            "1.3.6.1.6.3.12.1.5.0"
+#endif
+
+/** @name Error codes (storing engineBoots)
+ *
+ * These values are returned by getBootCounter() and saveBootCounter().
+ */
+//@{
+#define SNMPv3_OK                 0 //!< No error
+#define SNMPv3_NO_ENTRY_ERROR    -1 //!< No line for the engine id found
+#define SNMPv3_FILEOPEN_ERROR    -2 //!< Unable to open file
+#define SNMPv3_TOO_LONG_ERROR    -3 //!< The given engineID is too long
+#define SNMPv3_FILE_ERROR        -4 //!< The given file contains a wrong line
+#define SNMPv3_FILECREATE_ERROR  -5 //!< The File could not be created
+#define SNMPv3_FILERENAME_ERROR  -6 //!< Error renaming the temporary file 
+//@}
+
+/**
+ * Compare two strings.
+ *
+ * @param str1    - The first byte array
+ * @param ptr1len - Length of first array
+ * @param str2    - The second byte array
+ * @param ptr2len - Length of second array
+ *
+ * @return 1 if the strings are identical, 0 if not.
+ */
+DLLOPT int unsignedCharCompare(const unsigned char *str1,
+                               const long int ptr1len,
+                               const unsigned char *str2,
+                               const long int ptr2len);
+
+/**
+ * String copy function.
+ *
+ * @note The returned string has to be deleted with "delete []".
+ *
+ * @param src    - Source string
+ * @param srclen - Length of source string
+ *
+ * @return Pointer to a null terminated copy of src (or 0 on error).
+ */
+DLLOPT unsigned char *v3strcpy(const unsigned char *src, const int srclen);
+
+/**
+ * Encode the given string into the output buffer. For each byte
+ * of the string two bytes in the output buffer are used. The
+ * output buffer will contain chars from 0x64 to 0x79.
+ *
+ * @param in        - The string (for example engine id) to encode
+ * @param in_length - The length of the engineID
+ * @param out       - The output buffer for the encoded string, must have
+ *                    lenth 2 * in_length
+ */
+DLLOPT void encodeString(const unsigned char* in, const int in_length,
+                        char* out);
+
+/**
+ * Decode the given encoded string into the output buffer.
+ *
+ * @param in        - The encoded string
+ * @param in_length - The length of the encoded string
+ * @param out       - Buffer for the decoded string (half size of input
+ *                    string). The String will be null terminated.
+ */
+DLLOPT void decodeString(const unsigned char* in, const int in_length,
+                        char* out);
+
+/**
+ * Read the bootCounter of the given engineID stored in the given file.
+ *
+ * @param fileName - The name of the file
+ * @param engineId - Read the bootCounter for this enigneID
+ * @param boot     - OUT: the bootCounter that was read
+ *
+ * @return One of SNMPv3_OK, SNMPv3_TOO_LONG_ERROR, SNMPv3_FILE_ERROR,
+ *         SNMPv3_NO_ENTRY_ERROR, SNMPv3_FILEOPEN_ERROR
+ *
+ */
+DLLOPT int getBootCounter(const char *fileName,
+                          const OctetStr &engineId, unsigned int &boot);
+
+/**
+ * Store the bootCounter of the given engineID in the given file.
+ *
+ * @param fileName - The name of the file
+ * @param engineId - Store the bootCounter for this enigneID
+ * @param boot     - The bootCounter
+ *
+ * @return One of SNMPv3_OK, SNMPv3_FILEOPEN_ERROR, SNMPv3_FILECREATE_ERROR,
+ *         SNMPv3_FILERENAME_ERROR.
+ *
+ */
+DLLOPT int saveBootCounter(const char *fileName,
+                           const OctetStr &engineId, const unsigned int boot);
+
+
+#endif // _SNMPv3
+
+/**
+ * Tool class for easy allocation of buffer space.
+ */
+template <class T> class Buffer
+{
+ public:
+    /// Constructor: Allocate a buffer for size objects.
+    Buffer(const unsigned int size)
+    {
+       ptr = new T[size];
+       if (ptr)
+         len = size;
+       else
+         len = 0;
+    }
+
+    /// Destructor: Free allocated buffer
+    ~Buffer()
+     {
+        if (ptr) delete [] ptr;
+     }
+
+    /// Get the buffer pointer
+    T *get_ptr()
+    {
+       return ptr;
+    }
+
+    /// Overwrite the buffer space with zero.
+    void clear()
+    {
+       if (ptr)
+           memset(ptr, 0, len * sizeof(T));
+    }
+
+ private:
+    T *ptr;
+    unsigned int len;
+};
+
+// only for compatibility do not use these values:
+#define SecurityModel_any SNMP_SECURITY_MODEL_ANY
+#define SecurityModel_v1  SNMP_SECURITY_MODEL_V1
+#define SecurityModel_v2  SNMP_SECURITY_MODEL_V2
+#define SecurityModel_USM SNMP_SECURITY_MODEL_USM
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif // _V3_H
diff --git a/3rdparty/snmp++/include/snmp_pp/vb.h b/3rdparty/snmp++/include/snmp_pp/vb.h
new file mode 100644 (file)
index 0000000..1623356
--- /dev/null
@@ -0,0 +1,431 @@
+/*_############################################################################
+  _## 
+  _##  vb.h  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  SNMP++ V B . H
+
+  VARIABLE BINDING CLASS DEFINITION
+
+  DESCRIPTION:
+  This module contains the class definition for the variable binding
+  class. The VB class is an encapsulation of a SNMP VB. A VB object is
+  composed of an SNMP++ Oid and an SMI value. The Vb class utilizes Oid
+  objects and thus requires the Oid class. The Vb class may be used
+  stand alone and does not require use of any other snmp library.
+
+  DESIGN + AUTHOR:  Peter E. Mellquist
+
+=====================================================================*/
+// $Id: vb.h 1541 2009-05-29 11:29:22Z katz $
+
+#ifndef _VB_CLS
+#define _VB_CLS
+
+#include "snmp_pp/oid.h"                 // oid class def
+#include "snmp_pp/timetick.h"            // time ticks
+#include "snmp_pp/counter.h"             // counter
+#include "snmp_pp/gauge.h"               // gauge class
+#include "snmp_pp/ctr64.h"               // 64 bit counters
+#include "snmp_pp/octet.h"               // octet class
+#include "snmp_pp/address.h"             // address class def
+#include "snmp_pp/integer.h"             // integer class
+#include "snmp_pp/snmperrs.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+//------------[ VB Class Def ]-------------------------------------
+/**
+ * The Vb class is the encapsulation of the SNMP variable binding.
+ *
+ * Variable binding lists in SNMP++ are represented as arrays of Vb
+ * objects. Vb objects are passed to and from SNMP objects to provide
+ * getting or setting MIB values.  The vb class keeps its own memory
+ * for objects and does not utilize pointers to external data
+ * structures.
+ */
+class DLLOPT Vb
+{
+ //-----[ public members ]
+ public:
+
+  //-----[ constructors / destructors ]-------------------------------
+
+  /**
+   * Constructor with no arguments.
+   *
+   * This constructor creates an unitialized vb.
+   */
+  Vb() : iv_vb_value(0), exception_status(SNMP_CLASS_SUCCESS) {};
+
+  /**
+   * Constructor to initialize the oid.
+   *
+   * This constructor creates a vb with oid portion initialized.
+   */
+  Vb(const Oid &oid)
+    : iv_vb_oid(oid), iv_vb_value(0), exception_status(SNMP_CLASS_SUCCESS) {};
+
+  /**
+   * Copy constructor.
+   */
+  Vb(const Vb &vb) : iv_vb_value(0) { *this = vb; };
+
+  /**
+   * Destructor that frees all allocated memory.
+   */
+  ~Vb() { free_vb(); };
+
+  /**
+   * Overloaded assignment operator.
+   */
+  Vb& operator=(const Vb &vb);
+
+  /**
+   * Clone operator.
+   */
+  Vb *clone( ) const { return new Vb(*this); };
+
+  //-----[ set oid / get oid ]------------------------------------------
+
+  /**
+   * Set the oid from another oid.
+   */
+  void set_oid(const Oid &oid) { iv_vb_oid = oid; };
+
+  /**
+   * Get the oid portion.
+   *
+   * @note Check the validity of the object through Vb::valid() before
+   *       calling this method.
+   */
+  void get_oid(Oid &oid) const { oid = iv_vb_oid; };
+
+  /**
+   * Get the oid portion as a const.
+   *
+   * @note Check the validity of the object through Vb::valid() before
+   *       calling this method.
+   */
+  const Oid &get_oid() const { return iv_vb_oid; };
+
+  //-----[ set value ]--------------------------------------------------
+
+  /**
+   * Set the value using any SnmpSyntax object.
+   */
+  void set_value(const SnmpSyntax &val)
+    { free_vb(); iv_vb_value = val.clone(); };
+
+  /**
+   * Set the value with an int.
+   *
+   * The syntax of the Vb will be set to SMI INT32.
+   */
+  void set_value(const int i) { free_vb(); iv_vb_value = new SnmpInt32(i); };
+
+  /**
+   * Set the value with an unsigned int.
+   *
+   * The syntax of the Vb will be set to SMI UINT32.
+   */
+  void set_value(const unsigned int i)
+    { free_vb(); iv_vb_value = new SnmpUInt32(i); };
+
+  /**
+   * Set the value with a long int.
+   *
+   * @note Even on 64 bit platforms, only 32 bits are used
+   *
+   * The syntax of the Vb will be set to SMI INT32.
+   */
+  void set_value(const long i)
+    { free_vb(); iv_vb_value = new SnmpInt32(i); };
+
+  /**
+   * Set the value with an unsigned long int.
+   *
+   * @note Even on 64 bit platforms, only 32 bits are used
+   *
+   * The syntax of the Vb will be set to SMI UINT32.
+   */
+  void set_value(const unsigned long i)
+    { free_vb(); iv_vb_value = new SnmpUInt32(i); };
+
+  /**
+   * Set value using a null terminated string.
+   *
+   * The syntax of the Vb will be set to SMI octet.
+   */
+  void set_value(const char *ptr)
+    { free_vb(); iv_vb_value = new OctetStr(ptr); };
+
+  /**
+   * Set value using a string and length.
+   *
+   * The syntax of the Vb will be set to SMI octet.
+   */
+  void set_value(const unsigned char *ptr, const unsigned int len)
+    { free_vb(); iv_vb_value = new OctetStr(ptr, len); };
+
+  /**
+   * Set the value portion of the vb to null, if its not already.
+   */
+  void set_null() { free_vb(); };
+
+  //----[ get value ]------------------------------------------------
+
+  /**
+   * Get the value using a SnmpSyntax object.
+   *
+   * @param val - An object of a subclass of SnmpSyntax that will be
+   *              assigned the value of the vb.
+   *
+   * @return SNMP_CLASS_SUCCESS if the vb value could be assigned to
+   *         the passed SnmpSyntax object, else SNMP_CLASS_INVALID.
+   */
+  int get_value(SnmpSyntax &val) const;
+
+  /**
+   * Get the value.
+   *
+   * This method will only return success if the value of the vb is SMI INT32.
+   *
+   * @param i - returned value
+   *
+   * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+   */
+  int get_value(int &i) const;
+
+  /**
+   * Get the value.
+   *
+   * This method will only return success if the value of the vb can
+   * be mapped to an unsigned long (SMI types uint32, counter32, gauge
+   * and timeticks).
+   *
+   * @param i - returned value
+   *
+   * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+   */
+  int get_value(unsigned int &i) const;
+
+  /**
+   * Get the value.
+   *
+   * This method will only return success if the value of the vb is SMI INT32.
+   *
+   * @param i - returned value
+   *
+   * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+   */
+  int get_value(long &i) const;
+
+  /**
+   * Get the value.
+   *
+   * This method will only return success if the value of the vb can
+   * be mapped to an unsigned long (SMI types uint32, counter32, gauge
+   * and timeticks).
+   *
+   * @param i - returned value
+   *
+   * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+   */
+  int get_value(unsigned long &i) const;
+
+  /**
+   * Get the value.
+   *
+   * This method will only return success if the value of the vb is SMI OCTET.
+   *
+   * @note The caller must provide a target string big enough to
+   *       handle the vb string. No length checks are done within
+   *       this method. The returned string will be null terminated.
+   *
+   * @param ptr - Pointer to already allocated space to hold the vb
+   *              value. The first char will be set to zero on failure.
+   * @param len - Returned length of the string. Will be set to 0 on failure.
+   *
+   * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+   */
+  int get_value(unsigned char *ptr, unsigned long &len) const;
+
+  /**
+   * Get the value.
+   *
+   * This method will only return success if the value of the vb is SMI OCTET.
+   *
+   * @note If the target space is not big enough to hold the complete
+   *       string only part of the string is copied.
+   *
+   * @param ptr    - Pointer to already allocated space to hold the vb
+   *                 value. The first char will be set to zero on failure.
+   * @param len    - Returned length of the string. Will be set to 0
+   *                 on failure.
+   * @param maxlen - Maximum length of the space that ptr points to.
+   * @param add_null_byte - Add a null byte at end of output string.
+   *
+   *
+   * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+   */
+  int get_value(unsigned char *ptr,
+               unsigned long &len,
+               const unsigned long maxlen,
+               const bool add_null_byte = false) const;
+
+  /**
+   * Get the value.
+   *
+   * This method will only return success if the value of the vb is SMI OCTET.
+   *
+   * @note The caller must provide a target string big enough to
+   *       handle the vb string. No length checks are done within
+   *       this method. The returned string will be null terminated.
+   *
+   * @param ptr - Pointer to already allocated space to hold the vb
+   *              value. The first char will be set to zero on failure.
+   *
+   * @return SNMP_CLASS_SUCCESS on success, else SNMP_CLASS_INVALID.
+   */
+  int get_value(char *ptr) const;
+
+  /**
+   * Clone the value portion of the variable binding.
+   *
+   * The returned pointer must be deleted by the caller.
+   *
+   * @return
+   *    a pointer to a clone of the value of the receiver.
+   */
+  SnmpSyntax* clone_value() const
+      { return ((iv_vb_value) ? iv_vb_value->clone() : 0); };
+
+
+  //-----[ misc]--------------------------------------------------------
+
+  /**
+   * Return the syntax or the exception status.
+   *
+   * @return If the SNMPv2 exception status is set, it is returned.
+   *         otherwise the syntax of the value object is returned.
+   */
+  SmiUINT32 get_syntax() const;
+
+  /**
+   * Set the syntax.
+   *
+   * The Value portion of the Vb will be deleted and a new value portion
+   * is allocated with it's default value (zero).
+   *
+   * @param syntax - The new syntax.
+   */
+  void set_syntax(const SmiUINT32 syntax);
+
+  /**
+   * Set the exception status.
+   *
+   * @param status - the new SNMPv2 exception status.
+   */
+  void set_exception_status(const SmiUINT32 status)
+    { exception_status = status; };
+
+  /**
+   * Get the exception status.
+   */
+  SmiUINT32 get_exception_status() const { return exception_status; };
+
+  /**
+   * Return a formatted version of the value.
+   *
+   * @return A null terminated string (empty if no value).
+   */ 
+  const char *get_printable_value() const;
+
+  /**
+   * Return a formatted version of the Oid.
+   *
+   * @return A null terminated string (may be empty if no Oid has been set).
+   */
+  const char *get_printable_oid() const
+    { return iv_vb_oid.get_printable(); };
+
+  /**
+   * Return the validity of a Vb object.
+   *
+   * @return TRUE if oid and value have been set.
+   */
+  bool valid() const;
+
+  /**
+   * Return the space needed for serialization.
+   *
+   * @return the length of the BER encoding of this Vb.
+   */
+  int get_asn1_length() const;
+
+  /**
+   * Reset the object.
+   */
+  void clear() { free_vb(); iv_vb_oid.clear(); };
+
+ //-----[ protected members ]
+ protected:
+  Oid iv_vb_oid;               // a vb is made up of a oid
+  SnmpSyntax *iv_vb_value;     // and a value...
+  SmiUINT32 exception_status;  // are there any vb exceptions??
+
+  /**
+   * Free the value portion.
+   */
+  void free_vb();
+};
+
+#ifdef SNMP_PP_NAMESPACE
+} // end of namespace Snmp_pp
+#endif 
+
+#endif
diff --git a/3rdparty/snmp++/src/IPv6Utility.cpp b/3rdparty/snmp++/src/IPv6Utility.cpp
new file mode 100644 (file)
index 0000000..a6faab1
--- /dev/null
@@ -0,0 +1,432 @@
+/*_############################################################################
+  _## 
+  _##  IPv6Utility.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*
+ * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/*===================================================================
+
+  SNMP++ IPv6Utility.h
+
+  DESCRIPTION:
+  This module contains the Utility functions for IPV6 support functions 
+  required for WIN32 environment
+
+  Adapted and integrated into snmp++ by Ragavan Tetchinamourty
+
+=====================================================================*/
+//XXX char ipv6utility_cpp_version[] = "@(#) SNMP++ $Id: $";
+
+#include <stdio.h>  //use vsnprintf
+#include "snmp_pp/IPv6Utility.h"
+
+//FIXME #if defined(_MSC_VER) && defined(SNMP_PP_IPv6)
+#if defined(WIN32) && defined(SNMP_PP_IPv6)
+
+#define NS_INT16SZ      2
+#define NS_INADDRSZ     4
+#define NS_IN6ADDRSZ    16
+#define EAFNOSUPPORT    WSAEAFNOSUPPORT
+#define ENOSPC          28
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+
+static const char *inet_ntop4(const unsigned char *src, char *dst, size_t size);
+
+#ifdef AF_INET6
+static const char *inet_ntop6(const unsigned char *src, char *dst, size_t size);
+#endif
+
+static int inet_pton4(const char *src, unsigned char *dst);
+#ifdef AF_INET6
+static int inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+
+
+/* char *
+ * isc_net_ntop(af, src, dst, size)
+ *     convert a network format address to presentation format.
+ * return:
+ *     pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ *     Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(int af, const void *src, char *dst, size_t size)
+{
+       switch (af) {
+       case AF_INET:
+               return (inet_ntop4((const unsigned char*)src, dst, size));
+#ifdef AF_INET6
+       case AF_INET6:
+               return (inet_ntop6((const unsigned char*)src, dst, size));
+#endif
+       default:
+               errno = EAFNOSUPPORT;
+               return (NULL);
+       }
+       /* NOTREACHED */
+}
+
+#if defined(_MSC_VER)
+static int
+snprintf (char *str, int n, char *fmt, ...)
+{
+va_list a;
+va_start (a, fmt);
+int ret = vsnprintf (str, n, fmt, a);
+va_end (a);
+return ret;
+}
+#endif
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ *     format an IPv4 address
+ * return:
+ *     `dst' (as a const)
+ * notes:
+ *     (1) uses no statics
+ *     (2) takes a unsigned char* not an in_addr as input
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, size_t size)
+{
+       /*static const */char *fmt = "%u.%u.%u.%u";
+       char tmp[sizeof "255.255.255.255"];
+       size_t len;
+
+       len = snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]);   
+       
+       if (len >= size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       memcpy(dst, tmp, len + 1);
+
+       return (dst);
+}
+
+/* const char *
+ * isc_inet_ntop6(src, dst, size)
+ *     convert IPv6 binary address into presentation (printable) format
+ * author:
+ *     Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static const char *
+inet_ntop6(const unsigned char *src, char *dst, size_t size)
+{
+       /*
+        * Note that int32_t and int16_t need only be "at least" large enough
+        * to contain a value of the specified size.  On some systems, like
+        * Crays, there is no such thing as an integer variable with 16 bits.
+        * Keep this in mind if you think this function should have been coded
+        * to use pointer overlays.  All the world's not a VAX.
+        */
+       char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+       struct { int base, len; } best, cur;
+       unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
+       int i, inc;
+
+       /*
+        * Preprocess:
+        *      Copy the input (bytewise) array into a wordwise array.
+        *      Find the longest run of 0x00's in src[] for :: shorthanding.
+        */
+       memset(words, '\0', sizeof words);
+       for (i = 0; i < NS_IN6ADDRSZ; i++)
+               words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+       best.base = -1;
+       cur.base = -1;
+       for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+               if (words[i] == 0) {
+                       if (cur.base == -1)
+                               cur.base = i, cur.len = 1;
+                       else
+                               cur.len++;
+               } else {
+                       if (cur.base != -1) {
+                               if (best.base == -1 || cur.len > best.len)
+                                       best = cur;
+                               cur.base = -1;
+                       }
+               }
+       }
+       if (cur.base != -1) {
+               if (best.base == -1 || cur.len > best.len)
+                       best = cur;
+       }
+       if (best.base != -1 && best.len < 2)
+               best.base = -1;
+
+       /*
+        * Format the result.
+        */
+       tp = tmp;
+       for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+               /* Are we inside the best run of 0x00's? */
+               if (best.base != -1 && i >= best.base &&
+                   i < (best.base + best.len)) {
+                       if (i == best.base)
+                               *tp++ = ':';
+                       continue;
+               }
+               /* Are we following an initial run of 0x00s or any real hex? */
+               if (i != 0)
+                       *tp++ = ':';
+               /* Is this address an encapsulated IPv4? */
+               if (i == 6 && best.base == 0 &&
+                   (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+                       if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+                               return (NULL);
+                       tp += strlen(tp);
+                       break;
+               }
+               inc = snprintf(tp, 5, "%x", words[i]);
+               // Ragavan Commented
+               //assert(inc < 5);
+               tp += inc;
+       }
+       /* Was it a trailing run of 0x00's? */
+       if (best.base != -1 && (best.base + best.len) ==
+           (NS_IN6ADDRSZ / NS_INT16SZ))
+               *tp++ = ':';
+       *tp++ = '\0';
+
+       /*
+        * Check for overflow, copy, and we're done.
+        */
+       if ((size_t)(tp - tmp) > size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       memcpy(dst, tmp, tp - tmp);
+       return (dst);
+}
+#endif /* AF_INET6 */
+
+
+
+/* int
+ * inet_pton(af, src, dst)
+ *     convert from presentation format (which usually means ASCII printable)
+ *     to network format (which is usually some kind of binary format).
+ * return:
+ *     1 if the address was valid for the specified address family
+ *     0 if the address wasn't valid (`dst' is untouched in this case)
+ *     -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *     Paul Vixie, 1996.
+ */
+int
+inet_pton(int af,
+         const char *src,
+         void *dst)
+{
+       switch (af) {
+       case AF_INET:
+               return (inet_pton4(src, (unsigned char *)dst));
+#ifdef AF_INET6
+       case AF_INET6:
+               return (inet_pton6(src, (unsigned char *)dst));
+#endif
+       default:
+               errno = EAFNOSUPPORT;
+               return (-1);
+       }
+       /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ *     like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *     1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *     does not touch `dst' unless it's returning 1.
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)        
+{
+       static const char digits[] = "0123456789";
+       int saw_digit, octets, ch;
+       unsigned char tmp[NS_INADDRSZ], *tp;
+
+       saw_digit = 0;
+       octets = 0;
+       *(tp = tmp) = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               if ((pch = strchr(digits, ch)) != NULL) {
+                       unsigned int newstr = *tp * 10 + (pch - digits);
+
+                       if (newstr > 255)
+                               return (0);
+                       *tp = newstr;
+                       if (! saw_digit) {
+                               if (++octets > 4)
+                                       return (0);
+                               saw_digit = 1;
+                       }
+               } else if (ch == '.' && saw_digit) {
+                       if (octets == 4)
+                               return (0);
+                       *++tp = 0;
+                       saw_digit = 0;
+               } else
+                       return (0);
+       }
+       if (octets < 4)
+               return (0);
+       memcpy(dst, tmp, NS_INADDRSZ);
+       return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ *     convert presentation level address to network order binary form.
+ * return:
+ *     1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *     (1) does not touch `dst' unless it's returning 1.
+ *     (2) :: in a full address is silently ignored.
+ * credit:
+ *     inspired by Mark Andrews.
+ * author:
+ *     Paul Vixie, 1996.
+ */
+#ifdef AF_INET6
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+       static const char xdigits_l[] = "0123456789abcdef",
+                         xdigits_u[] = "0123456789ABCDEF";
+       unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+       const char *xdigits, *curtok;
+       int ch, saw_xdigit;
+       unsigned int val;
+
+       memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+       endp = tp + NS_IN6ADDRSZ;
+       colonp = NULL;
+       /* Leading :: requires some special handling. */
+       if (*src == ':')
+               if (*++src != ':')
+                       return (0);
+       curtok = src;
+       saw_xdigit = 0;
+       val = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+                       pch = strchr((xdigits = xdigits_u), ch);
+               if (pch != NULL) {
+                       val <<= 4;
+                       val |= (pch - xdigits);
+                       if (val > 0xffff)
+                               return (0);
+                       saw_xdigit = 1;
+                       continue;
+               }
+               if (ch == ':') {
+                       curtok = src;
+                       if (!saw_xdigit) {
+                               if (colonp)
+                                       return (0);
+                               colonp = tp;
+                               continue;
+                       }
+                       if (tp + NS_INT16SZ > endp)
+                               return (0);
+                       *tp++ = (unsigned char) (val >> 8) & 0xff;
+                       *tp++ = (unsigned char) val & 0xff;
+                       saw_xdigit = 0;
+                       val = 0;
+                       continue;
+               }
+               if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+                   inet_pton4(curtok, tp) > 0) {
+                       tp += NS_INADDRSZ;
+                       saw_xdigit = 0;
+                       break;  /* '\0' was seen by inet_pton4(). */
+               }
+               return (0);
+       }
+       if (saw_xdigit) {
+               if (tp + NS_INT16SZ > endp)
+                       return (0);
+               *tp++ = (unsigned char) (val >> 8) & 0xff;
+               *tp++ = (unsigned char) val & 0xff;
+       }
+       if (colonp != NULL) {
+               /*
+                * Since some memmove()'s erroneously fail to handle
+                * overlapping regions, we'll do the shift by hand.
+                */
+               const int n = tp - colonp;
+               int i;
+
+               for (i = 1; i <= n; i++) {
+                       endp[- i] = colonp[n - i];
+                       colonp[n - i] = 0;
+               }
+               tp = endp;
+       }
+       if (tp != endp)
+               return (0);
+       memcpy(dst, tmp, NS_IN6ADDRSZ);
+       return (1);
+}
+#endif // AF_INET6
+
+#endif // defined(_MSC_VER) && defined(SNMP_PP_IPv6)
diff --git a/3rdparty/snmp++/src/address.cpp b/3rdparty/snmp++/src/address.cpp
new file mode 100644 (file)
index 0000000..cc3a2de
--- /dev/null
@@ -0,0 +1,2756 @@
+/*_############################################################################
+  _## 
+  _##  address.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+  A D D R E S S. C P P
+
+  ADDRESS CLASS IMPLEMENTATION
+
+  DESIGN + AUTHOR:  Peter E. Mellquist
+
+  DESCRIPTION:      Implementation file for Address classes.
+=====================================================================*/
+char address_cpp_version[]="@(#) SNMP++ $Id: address.cpp 1711 2010-02-10 21:25:47Z katz $";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#if defined(__APPLE__)
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#include "snmp_pp/address.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/IPv6Utility.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+/* Borlands isdigit has a bug */
+#ifdef __BCPLUSPLUS__
+#define my_isdigit(c) ((c) >= '0' && (c) <= '9')
+#else
+#define my_isdigit isdigit
+#endif
+
+#ifdef ADDRESS_DEBUG
+#define ADDRESS_TRACE debugprintf(0, "ADDRESS %p Enter %s", this, __PRETTY_FUNCTION__)
+#define ADDRESS_TRACE2 debugprintf(0, "ADDRESS op Enter %s", __PRETTY_FUNCTION__)
+#else
+#define ADDRESS_TRACE
+#define ADDRESS_TRACE2
+#endif
+
+#if !defined HAVE_GETHOSTBYNAME_R || !defined HAVE_GETHOSTBYADDR_R || !defined HAVE_REENTRANT_GETHOSTBYNAME || !defined HAVE_REENTRANT_GETHOSTBYADDR
+#ifdef _THREADS
+SnmpSynchronized Address::syscall_mutex;
+#endif
+#endif
+
+//=================================================================
+//======== Abstract Address Class Implementation ==================
+//=================================================================
+
+Address::Address()
+  : addr_changed(true), valid_flag(false)
+{
+  ADDRESS_TRACE;
+
+  memset(address_buffer, 0, sizeof(unsigned char)*ADDRBUF);
+}
+
+//------------[ Address::trim_white_space( char * ptr) ]------------
+// destructive trim white space
+void Address::trim_white_space(char *ptr)
+{
+  ADDRESS_TRACE;
+
+  char *tmp = ptr;                               // init
+  while (*tmp==' ') tmp++;                       // skip leading white space
+  while (*tmp && (*tmp != ' ')) *ptr++ = *tmp++; // move string to beginning
+  *ptr = 0;                                      // set end of string
+}
+
+// Reset the object
+void Address::clear()
+{
+  addr_changed = true;
+  valid_flag = false;
+  memset(address_buffer, 0, sizeof(unsigned char)*ADDRBUF);
+}
+
+//-----------------------------------------------------------------------
+// overloaded equivlence operator, are two addresses equal?
+int operator==(const Address &lhs, const Address &rhs)
+{
+  ADDRESS_TRACE2;
+
+  return (strcmp((const char*)lhs, (const char*)rhs) == 0);
+}
+
+//------------------------------------------------------------------
+// overloaded > operator, is a1 > a2
+int operator>(const Address &lhs, const Address &rhs)
+{
+  ADDRESS_TRACE2;
+
+  return (strcmp((const char*)lhs, (const char*)rhs) > 0);
+}
+
+//-----------------------------------------------------------------
+// overloaded < operator, is a1 < a2
+int operator<(const Address &lhs, const Address &rhs)
+{
+  ADDRESS_TRACE2;
+
+  return (strcmp((const char*)lhs, (const char*)rhs) < 0);
+}
+
+//------------------------------------------------------------------
+// equivlence operator overloaded, are an address and a string equal?
+int operator==(const Address &lhs, const char *rhs)
+{
+  ADDRESS_TRACE2;
+
+  if (!rhs && !lhs.valid())
+    return TRUE;
+  if (strcmp((const char *)lhs, rhs) == 0)
+    return TRUE;
+  return FALSE;
+}
+
+//------------------------------------------------------------------
+// overloaded > , is a > inaddr
+int operator>(const Address &lhs, const char *rhs)
+{
+  ADDRESS_TRACE2;
+
+  if (!rhs)
+    return lhs.valid();  // if lhs valid then > NULL, else invalid !> NULL
+  if (strcmp((const char *)lhs, rhs) > 0)
+    return TRUE;
+  return FALSE;
+}
+
+//------------------------------------------------------------------
+// overloaded >= , is a >= inaddr
+int operator>=(const Address &lhs, const char *rhs)
+{
+  ADDRESS_TRACE2;
+
+  if (!rhs)
+    return TRUE; // always >= NULL
+  if (strcmp((const char *)lhs, rhs) >= 0)
+    return TRUE;
+  return FALSE;
+}
+
+//-----------------------------------------------------------------
+// overloaded < , are an address and a string equal?
+int operator<(const Address &lhs, const char *rhs)
+{
+  ADDRESS_TRACE2;
+
+  if (!rhs)
+    return FALSE; // always >= NULL
+  if (strcmp((const char *)lhs, rhs) < 0)
+    return TRUE;
+  return FALSE;
+}
+
+//-----------------------------------------------------------------
+// overloaded <= , is a <= inaddr
+int operator<=(const Address &lhs, const char *rhs)
+{
+  ADDRESS_TRACE2;
+
+  if (!rhs)
+    return !lhs.valid(); // invalid == NULL, else valid > NULL
+  if (strcmp((const char *)lhs, rhs) <= 0)
+    return TRUE;
+  return FALSE;
+}
+
+//=====================================================================
+//============ IPAddress Implementation ===============================
+//=====================================================================
+
+//-------[ construct an IP address with no agrs ]----------------------
+IpAddress::IpAddress()
+  : Address(), iv_friendly_name_status(0), ip_version(version_ipv4)
+{
+  ADDRESS_TRACE;
+
+  // always initialize what type this object is
+  smival.syntax = sNMP_SYNTAX_IPADDR;
+  smival.value.string.len = IPLEN;
+  smival.value.string.ptr = address_buffer;
+
+  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+}
+
+//-------[ construct an IP address with a string ]---------------------
+IpAddress::IpAddress(const char *inaddr)
+  : Address()
+{
+  ADDRESS_TRACE;
+
+  // always initialize what type this object is
+  smival.syntax = sNMP_SYNTAX_IPADDR;
+  smival.value.string.len = IPLEN;
+  smival.value.string.ptr = address_buffer;
+
+  // parse_address initializes valid, address_buffer & iv_friendly_name
+  valid_flag = parse_address(inaddr);
+}
+
+//-----[ IP Address copy constructor ]---------------------------------
+IpAddress::IpAddress(const IpAddress &ipaddr)
+    : iv_friendly_name_status(0), ip_version(ipaddr.ip_version),
+      have_ipv6_scope(ipaddr.have_ipv6_scope)
+{
+  ADDRESS_TRACE;
+
+  // always initialize what type this object is
+  smival.syntax = sNMP_SYNTAX_IPADDR;
+  smival.value.string.len = ipaddr.smival.value.string.len;
+  smival.value.string.ptr = address_buffer;
+
+  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+  valid_flag = ipaddr.valid_flag;
+  if (valid_flag)
+  {
+    // copy the address data
+    MEMCPY(address_buffer, ipaddr.address_buffer, smival.value.string.len);
+    // and the friendly name
+    strcpy(iv_friendly_name, ipaddr.iv_friendly_name);
+
+    if (!ipaddr.addr_changed)
+    {
+      memcpy(output_buffer, ipaddr.output_buffer,
+            sizeof(unsigned char) * OUTBUFF);
+      addr_changed = false;
+    }
+  }
+}
+
+//-----[ construct an IP address with a GenAddress ]---------------------
+IpAddress::IpAddress(const GenAddress &genaddr)
+  : iv_friendly_name_status(0)
+{
+  ADDRESS_TRACE;
+
+  // always initialize what type this object is
+  smival.syntax = sNMP_SYNTAX_IPADDR;
+  smival.value.string.len = IPLEN;
+  smival.value.string.ptr = address_buffer;
+
+  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+  output_buffer[0]=0;
+
+  // allow use of an ip or udp genaddress
+  valid_flag = genaddr.valid();
+  if (valid_flag)
+  {
+    if (genaddr.get_type() == type_ip)
+    {
+      // copy in the IP address data
+      *this = genaddr.cast_ipaddress();
+      return;
+    }
+    else if (genaddr.get_type() == type_udp)
+    {
+      // copy in the IP address data
+      *this = genaddr.cast_udpaddress();
+      return;
+    }
+  }
+  valid_flag = false;
+  addr_changed = true;
+}
+
+//-----[ IP Address general = operator ]-------------------------------
+SnmpSyntax& IpAddress::operator=(const SnmpSyntax &val)
+{
+  ADDRESS_TRACE;
+
+  if (this == &val) return *this; // protect against assignment from itself
+
+  addr_changed = true;
+  valid_flag = false;        // will get set TRUE if really valid
+  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+
+  if (val.valid())
+  {
+    switch (val.get_syntax())
+    {
+      case sNMP_SYNTAX_IPADDR:
+      case sNMP_SYNTAX_OCTETS:
+        if ((((IpAddress &)val).smival.value.string.len == IPLEN) ||
+           (((IpAddress &)val).smival.value.string.len == UDPIPLEN))
+        {
+          MEMCPY(address_buffer,
+                 ((IpAddress &)val).smival.value.string.ptr, IPLEN);
+         valid_flag = true;
+         ip_version = version_ipv4;
+         smival.value.string.len = IPLEN;
+        }
+        else if ((((IpAddress &)val).smival.value.string.len == IP6LEN_NO_SCOPE) ||
+                (((IpAddress &)val).smival.value.string.len == UDPIP6LEN_NO_SCOPE))
+        {
+         MEMCPY(address_buffer,
+                ((IpAddress &)val).smival.value.string.ptr, IP6LEN_NO_SCOPE);
+         valid_flag = true;
+         ip_version = version_ipv6;
+         smival.value.string.len = IP6LEN_NO_SCOPE;
+         have_ipv6_scope = false;
+        }
+        else if ((((IpAddress &)val).smival.value.string.len == IP6LEN_WITH_SCOPE) ||
+                (((IpAddress &)val).smival.value.string.len == UDPIP6LEN_WITH_SCOPE))
+        {
+         MEMCPY(address_buffer,
+                ((IpAddress &)val).smival.value.string.ptr, IP6LEN_WITH_SCOPE);
+         valid_flag = true;
+         ip_version = version_ipv6;
+         smival.value.string.len = IP6LEN_WITH_SCOPE;
+         have_ipv6_scope = true;
+        }
+        break;
+
+        // NOTE: as a value add, other types could have "logical"
+        // mappings, i.e. integer32 and unsigned32
+    }
+  }
+  return *this;
+}
+
+//------[ assignment to another ipaddress object overloaded ]-----------------
+IpAddress& IpAddress::operator=(const IpAddress &ipaddr)
+{
+  ADDRESS_TRACE;
+
+  if (this == &ipaddr) return *this; // protect against assignment from itself
+
+  valid_flag = ipaddr.valid_flag;
+  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+
+  if (valid_flag)
+  {
+    if (ipaddr.ip_version == version_ipv4)
+    {
+      MEMCPY(address_buffer, ipaddr.address_buffer, IPLEN);
+      ip_version = version_ipv4;
+      smival.value.string.len = IPLEN;
+    }
+    else
+    {
+      if (ipaddr.have_ipv6_scope)
+      {
+       MEMCPY(address_buffer, ipaddr.address_buffer, IP6LEN_WITH_SCOPE);
+       ip_version = version_ipv6;
+       smival.value.string.len = IP6LEN_WITH_SCOPE;
+       have_ipv6_scope = true;
+      }
+      else
+      {
+       MEMCPY(address_buffer, ipaddr.address_buffer, IP6LEN_NO_SCOPE);
+       ip_version = version_ipv6;
+       smival.value.string.len = IP6LEN_NO_SCOPE;
+       have_ipv6_scope = false;
+      }
+    }
+    strcpy(iv_friendly_name, ipaddr.iv_friendly_name);
+
+    if (ipaddr.addr_changed)
+      addr_changed = true;
+    else
+    {
+      memcpy(output_buffer, ipaddr.output_buffer,
+            sizeof(unsigned char) * OUTBUFF);
+      addr_changed = false;
+    }
+  }
+  else
+    addr_changed = true;
+  return *this;
+}
+
+IpAddress& IpAddress::operator=(const char *inaddr)
+{
+  ADDRESS_TRACE;
+
+  valid_flag = parse_address(inaddr);
+  addr_changed = true;
+  return *this;
+}
+
+//-------[ return the friendly name ]----------------------------------
+char *IpAddress::friendly_name(int &status)
+{
+  ADDRESS_TRACE;
+
+  if ((iv_friendly_name[0]==0) && (valid_flag))
+    this->addr_to_friendly();
+  status = iv_friendly_name_status;
+  return iv_friendly_name;
+}
+
+// parse a dotted string
+int IpAddress::parse_dotted_ipstring(const char *inaddr)
+{
+  ADDRESS_TRACE;
+
+  int token_count=0;
+  char temp[30];  // temp buffer for destruction
+
+  // check len, an ip can never be bigger than 15
+  // 123456789012345
+  // XXX.XXX.XXX.XXX
+  if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
+
+  strcpy(temp, inaddr);
+  trim_white_space(temp);
+  if (strlen(temp) > 15) return FALSE;
+
+  /* Check for the following:
+   * - exactly three dots
+   * - no dot at begin or end
+   * - at least a digit between two dots
+   * - only dots and digits allowed
+   */
+  char *ptr = temp;
+  int dot_count = 0;
+  bool last_char_was_dot = true;
+
+  while (*ptr)
+  {
+    if (*ptr == '.')
+    {
+      if (last_char_was_dot) return FALSE;
+      ++dot_count;
+      last_char_was_dot = true;
+    }
+    else if (my_isdigit(*ptr))
+    {
+      last_char_was_dot = false;
+    }
+    else
+      return FALSE;
+    ++ptr;
+  }
+  if ((dot_count != 3) || (last_char_was_dot))
+    return FALSE;
+
+  ptr = temp;
+  while (*ptr)
+  {
+    unsigned long number = 0;
+
+    if (*ptr == '.') ++ptr;    // skip over the dot
+
+    // grab a digit token and convert it to a long int
+    int digits = 0;
+    while ((*ptr) && (*ptr != '.'))
+    {
+      number = (number * 10) + *(ptr++) - '0';
+      ++digits;
+    }
+    if (digits > 3) return FALSE;
+    if (number > 255) return FALSE;
+
+    // stuff the value into the array and bump the counter
+    address_buffer[token_count++]= (unsigned char) number;
+  }
+
+  ip_version = version_ipv4;
+  smival.value.string.len = IPLEN;
+  return TRUE;
+}
+
+#define ATOI(x)    if      ((x >= 48) && (x <= 57)) x = x-48; /* 0-9 */ \
+                   else if ((x >= 97) && (x <=102)) x = x-87; /* a-f */ \
+                   else if ((x >= 65) && (x <= 70)) x = x-55; /* A-F */ \
+                   else x=0
+
+// parse a coloned string
+int IpAddress::parse_coloned_ipstring(const char *inaddr)
+{
+  ADDRESS_TRACE;
+
+  unsigned char tmp_address_buffer[ADDRBUF];
+  char temp[60];  // temp buffer for destruction
+
+  // check len, an ipv6 can never be bigger than 39 + 11
+  // 123456789012345678901234567890123456789
+  // 1BCD:2BCD:3BCD:4BCD:5BCD:6BCD:7BCD:8BCD%4123456789
+  if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
+  strcpy(temp, inaddr);
+  trim_white_space(temp);
+
+  // first check for ipv6 scope
+  unsigned int scope = 0;
+  bool have_scope = false;
+
+  {
+      int scope_pos;
+      for (int i=strlen(temp)-1; i >=0 ; i--)
+      {
+         if (temp[i] == '%')
+         {
+             scope_pos = i;
+             have_scope = true;
+             break;
+         }
+         if (!isdigit(temp[i]))
+             break;
+      }
+      if (have_scope)
+      {
+         temp[scope_pos] = 0;
+         scope = atol(temp + scope_pos + 1);
+      }
+  }
+
+  if (strlen(temp) > 39) return FALSE;
+
+  char *in_ptr = temp;
+  char *out_ptr = (char*)tmp_address_buffer;
+  char *end_first_part = NULL;
+  char second[39];
+  int second_used = FALSE;
+  int colon_count = 0;
+  int had_double_colon = FALSE;
+  int last_was_colon = FALSE;
+  int had_dot = FALSE;
+  int dot_count = 0;
+  int digit_count = 0;
+  char digits[4];
+  char last_deliminiter = 0;
+
+  while (*in_ptr != 0)
+  {
+    if (*in_ptr == '.')
+    {
+      last_deliminiter = *in_ptr;
+      had_dot = TRUE;
+      dot_count++;
+      if (dot_count > 3)
+        return FALSE;
+      if ((digit_count > 3) || (digit_count < 1))
+        return FALSE;
+      for (int i=0; i<digit_count; i++)
+        if (!my_isdigit(digits[i]))
+          return FALSE;
+      digits[digit_count] = 0;
+      int value = atoi(digits);
+      if ((value > 0) && (value <= 255))
+        *out_ptr++ = (unsigned char) value;
+      else
+      {
+        if (strcmp(digits, "0") == 0)
+          *out_ptr++ = (unsigned char) 0;
+        else
+          return FALSE;
+      }
+      digit_count = 0;
+    }
+    else if (*in_ptr == ':')
+    {
+      last_deliminiter = *in_ptr;
+
+      if (had_dot)
+        return FALSE; // don't allow : after a dot
+
+      if (digit_count)
+      {
+        // move digits to right
+       {
+          for (int i=0; i<digit_count; i++)
+          {
+            ATOI(digits[digit_count - 1 - i]);
+            digits[3-i] = digits[digit_count - 1 - i];
+          }
+       }
+       {
+          for (int i=0; i<4-digit_count; i++)
+          digits[i] = 0;
+       }
+       {
+         // pack two digits into one byte
+         for (int i=0; i < 4; i += 2)
+          {
+           unsigned char c = digits[i];
+           unsigned char d = digits[i+1];
+           *out_ptr++ = (c*16 + d);
+         }
+       }
+        digit_count = 0;
+      }
+      colon_count++;
+      if (last_was_colon)
+      {
+        if (had_double_colon)
+          return FALSE;
+        end_first_part = out_ptr;
+        out_ptr = second;
+        second_used = TRUE;
+        had_double_colon = TRUE;
+      }
+      else
+      {
+        last_was_colon = TRUE;
+      }
+    }
+    else
+    {
+      if (digit_count >= 4)
+        return FALSE;
+      if (!isxdigit(*in_ptr))
+        return FALSE;
+      digits[digit_count] = tolower(*in_ptr);
+
+      digit_count++;
+      if (digit_count > 4)
+        return FALSE;
+      last_was_colon = 0;
+    }
+    in_ptr++;
+  }
+
+  // put last bytes from digits into buffer
+  if (digit_count)
+  {
+    if (last_deliminiter == ':')
+    {
+      {
+       // move digits to right
+       for (int i=0; i<digit_count; i++)
+       {
+          ATOI(digits[digit_count - 1 - i]);
+          digits[3-i] = digits[digit_count - 1 - i];
+        }
+      }
+      {
+        for (int i=0; i<4-digit_count; i++)
+          digits[i] = 0;
+      }
+      {
+        // pack two digits into one byte
+        for (int i=0; i < 4; i += 2)
+        {
+          unsigned char c = digits[i];
+          unsigned char d = digits[i+1];
+          *out_ptr++ = (c*16 + d);
+        }
+      }
+      digit_count = 0;
+    }
+    else if (last_deliminiter == '.')
+    {
+      if ((digit_count > 3) || (digit_count < 1))
+        return FALSE;
+      for (int i=0; i<digit_count; i++)
+        if (!my_isdigit(digits[i]))
+          return FALSE;
+      digits[digit_count] = 0;
+      int value = atoi(digits);
+      if ((value > 0) && (value <= 255))
+        *out_ptr++ = (unsigned char) value;
+      else
+      {
+        if (strcmp(digits, "0") == 0)
+          *out_ptr++ = (unsigned char) 0;
+        else
+          return FALSE;
+      }
+      //digit_count = 0;
+    }
+    else
+      return FALSE;
+  }
+
+  // must have between two and seven colons
+  if ((colon_count > 7) || (colon_count < 2))
+    return FALSE;
+
+  // if there was a dot there must be three of them
+  if ((dot_count > 0) && (dot_count != 3))
+    return FALSE;
+
+  if (second_used)
+  {
+    int len_first  = SAFE_INT_CAST(end_first_part - (char*)tmp_address_buffer);
+    int len_second = SAFE_INT_CAST(out_ptr - second);
+
+    int i;
+    for (i=0; i<IP6LEN_NO_SCOPE-(len_first + len_second); i++)
+      *end_first_part++ = 0;
+    for (i=0; i<len_second; i++)
+      *end_first_part++ = second[i];
+  }
+
+  if (!end_first_part)
+    end_first_part = out_ptr;
+
+  // check for short address
+  if (end_first_part - (char*)tmp_address_buffer != IP6LEN_NO_SCOPE)
+    return FALSE;
+
+  ip_version = version_ipv6;
+  if (have_scope)
+      smival.value.string.len = IP6LEN_WITH_SCOPE;
+  else
+      smival.value.string.len = IP6LEN_NO_SCOPE;
+
+  memcpy(address_buffer, tmp_address_buffer, ADDRBUF);
+
+  if (have_scope)
+  {
+    unsigned int *scope_p = (unsigned int*)(address_buffer + IP6LEN_NO_SCOPE);
+    *scope_p = htonl(scope);
+    have_ipv6_scope = true;
+  }
+  else
+      have_ipv6_scope = false;
+
+  return TRUE;
+}
+
+#undef ATOI
+
+//-----[ IP Address parse Address ]---------------------------------
+bool IpAddress::parse_address(const char *inaddr)
+{
+  ADDRESS_TRACE;
+
+#if !defined HAVE_GETHOSTBYNAME_R && !defined HAVE_REENTRANT_GETHOSTBYNAME
+#ifdef _THREADS
+  SnmpSynchronize s(syscall_mutex);
+#endif
+#endif
+
+  addr_changed = true;
+
+  // parse the input char array fill up internal buffer with four ip
+  // bytes set and return validity flag
+
+  char ds[61];
+
+  // intialize the friendly_name member variable
+  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+  iv_friendly_name_status = 0;
+
+  // is this a dotted IP notation string or a friendly name
+  if (parse_dotted_ipstring(inaddr))
+  {
+    // since this is a valid dotted string don't do any DNS
+    return TRUE;
+  }
+  else if (parse_coloned_ipstring(inaddr))
+  {
+    // since this is a valid ipv6 string don't do any DNS
+    return TRUE;
+  }
+  else // not a dotted string, try to resolve it via DNS
+  {
+#if defined (CPU) && CPU == PPC603
+  int lookupResult = hostGetByName(inaddr);
+
+  if (lookupResult == ERROR)
+  {
+      iv_friendly_name_status = lookupResult;
+      return FALSE;
+  }
+       // now lets check out the dotted string
+  strcpy(ds,inet_ntoa(lookupResult));
+
+  if (!parse_dotted_ipstring(ds))
+     return FALSE;
+
+       // save the friendly name
+  strcpy(iv_friendly_name, inaddr);
+
+  return TRUE;
+
+#else
+  hostent *lookupResult = 0;
+
+#ifdef HAVE_GETHOSTBYNAME_R
+    char buf[2048]; // TODO: Too big buffer?
+    int herrno = 0;
+    hostent lookup_buf;
+#if defined(__sun) || defined (__QNX_NEUTRINO)
+    lookupResult = gethostbyname_r(inaddr, &lookup_buf, buf, 2048, &herrno);
+#else    
+    gethostbyname_r(inaddr, &lookup_buf, buf, 2048, &lookupResult, &herrno);
+#endif
+#ifdef SNMP_PP_IPv6
+    if (!lookupResult)
+    {
+#ifdef __sun
+      lookupResult = gethostbyname_r(inaddr, AF_INET6, &lookup_buf, buf, 2048,
+                                     &lookupResult, &herrno);
+#else        
+      gethostbyname2_r(inaddr, AF_INET6, &lookup_buf, buf, 2048,
+                        &lookupResult, &herrno);
+#endif
+    }
+#endif // SNMP_PP_IPv6
+#else // not HAVE_GETHOSTBYNAME_R
+    lookupResult = gethostbyname(inaddr);
+#ifdef SNMP_PP_IPv6
+    if (!lookupResult)
+    {
+#ifdef HAVE_GETHOSTBYNAME2
+      lookupResult = gethostbyname2(inaddr, AF_INET6);
+#else
+      lookupResult = gethostbyname(inaddr);
+#endif // HAVE_GETHOSTBYNAME2
+    }
+#endif // SNMP_PP_IPv6
+#endif // HAVE_GETHOSTBYNAME_R
+    if (lookupResult)
+    {
+#ifdef SNMP_PP_IPv6
+      if (lookupResult->h_length == sizeof(in6_addr))
+      {
+        in6_addr ipAddr;
+        memcpy((void *) &ipAddr, (void *) lookupResult->h_addr,
+               sizeof(in6_addr));
+
+        // now lets check out the coloned string
+        if (!inet_ntop(AF_INET6, &ipAddr, ds, 60))
+          return FALSE;
+        debugprintf(4, "from inet_ntop: %s", ds);
+        if (!parse_coloned_ipstring(ds))
+          return FALSE;
+
+        // save the friendly name
+        strcpy(iv_friendly_name, inaddr);
+        
+        return TRUE;
+      }
+#endif // SNMP_PP_IPv6
+      if (lookupResult->h_length == sizeof(in_addr))
+      {
+        in_addr ipAddr;
+
+        memcpy((void *) &ipAddr, (void *) lookupResult->h_addr,
+               sizeof(in_addr));
+
+        // now lets check out the dotted string
+        strcpy(ds,inet_ntoa(ipAddr));
+
+        if (!parse_dotted_ipstring(ds))
+          return FALSE;
+
+        // save the friendly name
+        strcpy(iv_friendly_name, inaddr);
+
+        return TRUE;
+      }
+    }         // end if lookup result
+    else
+    {
+#ifdef HAVE_GETHOSTBYNAME_R
+      iv_friendly_name_status = herrno;
+#else
+      iv_friendly_name_status = h_errno;
+#endif
+      return FALSE;
+    }
+#endif //PPC603
+  }  // end else not a dotted string
+  return TRUE;
+}
+
+// using the currently defined address, do a DNS
+// and try to fill up the name
+int IpAddress::addr_to_friendly()
+{
+  ADDRESS_TRACE;
+
+#if !defined HAVE_GETHOSTBYADDR_R && !defined HAVE_REENTRANT_GETHOSTBYADDR
+#ifdef _THREADS
+  SnmpSynchronize s(syscall_mutex);
+#endif
+#endif
+
+#if defined (CPU) && CPU == PPC603
+  int lookupResult;
+  char hName[MAXHOSTNAMELEN+1];
+#else
+  hostent *lookupResult;
+#endif
+  char    ds[61];
+
+  // can't look up an invalid address
+  if (!valid_flag) return -1;
+
+  // lets try and get the friendly name from the DNS
+  strcpy(ds, this->IpAddress::get_printable());
+
+#if !(defined (CPU) && CPU == PPC603) && defined HAVE_GETHOSTBYADDR_R
+  int herrno = 0;
+  hostent lookup;
+  char buf[2048]; // TODO: Buf size too big?
+#endif
+  if (ip_version == version_ipv4)
+  {
+    in_addr ipAddr;
+
+#if defined HAVE_INET_ATON
+    if (inet_aton((char*)ds, &ipAddr) == 0)
+      return -1;    // bad address
+#elif defined HAVE_INET_PTON
+    if (inet_pton(AF_INET, (char*)ds, &ipAddr) <= 0)
+      return -1; // bad address
+#else
+    ipAddr.s_addr = inet_addr((char*)ds);
+    if (ipAddr.s_addr == INADDR_NONE)
+      return -1; // bad address
+#endif
+
+#if defined (CPU) && CPU == PPC603
+       lookupResult = hostGetByAddr(ipAddr.s_addr, hName);
+#elif defined HAVE_GETHOSTBYADDR_R
+#if defined(__sun) || defined(__QNX_NEUTRINO)
+    lookupResult = gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
+                                   AF_INET, &lookup, buf, 2048, &herrno);
+#else
+    gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
+                    AF_INET, &lookup, buf, 2048, &lookupResult, &herrno);
+#endif
+#else
+    lookupResult = gethostbyaddr((char *) &ipAddr, sizeof(in_addr),
+                                 AF_INET);
+#endif
+  }
+  else
+  {
+#ifdef SNMP_PP_IPv6
+    if (have_ipv6_scope)
+    {
+       // remove scope from ds
+       for (int i=strlen(ds); i >=0; i--)
+           if (ds[i] == '%')
+           {
+               ds[i] = 0;
+               break;
+           }
+    }
+
+    in6_addr ipAddr;
+
+    if (inet_pton(AF_INET6, (char*)ds, &ipAddr) <= 0)
+      return -1; // bad address
+
+#if defined (CPU) && CPU == PPC603
+       lookupResult = hostGetByAddr(ipAddr.s_addr, hName);
+#elif defined HAVE_GETHOSTBYADDR_R
+#if defined(__sun) || defined(__QNX_NEUTRINO)
+    lookupResult = gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
+                                   AF_INET6, &lookup, buf, 2048, &herrno);
+#else
+    gethostbyaddr_r((char *) &ipAddr, sizeof(in_addr),
+                    AF_INET6, &lookup, buf, 2048, &lookupResult, &herrno);
+#endif
+#else
+    lookupResult = gethostbyaddr((char *) &ipAddr, sizeof(in6_addr),
+                                 AF_INET6);
+#endif // HAVE_GETHOSTBYADDR_R
+#else
+    return -1;
+#endif // SNMP_PP_IPv6
+  }
+  // if we found the name, then update the iv friendly name
+#if defined (CPU) && CPU == PPC603
+  if (lookupResult != ERROR)
+  {
+    strncpy(iv_friendly_name, hName, MAX_FRIENDLY_NAME);
+    return 0;
+  }
+  else
+  {
+    iv_friendly_name_status = lookupResult;
+       return lookupResult;
+  }
+
+  return -1; //should not get here
+
+#else
+  if (lookupResult)
+  {
+    strcpy(iv_friendly_name, lookupResult->h_name);
+    return 0;
+  }
+  else
+  {
+#ifdef HAVE_GETHOSTBYADDR_R
+    iv_friendly_name_status = herrno;
+#else
+    iv_friendly_name_status = h_errno;
+#endif
+    return iv_friendly_name_status;
+  }
+#endif //PPC603
+}
+
+unsigned int IpAddress::get_scope() const
+{
+  ADDRESS_TRACE;
+
+  if (valid_flag)
+  {
+    const unsigned int *scope;
+    if ((ip_version == version_ipv6) && (have_ipv6_scope))
+      scope = (const unsigned int*)(address_buffer + IP6LEN_NO_SCOPE);
+    else
+      return (unsigned int)-1;
+
+    return ntohl(*scope);
+  }
+  return (unsigned int)-1; // don't use uninitialized memory
+}
+
+bool IpAddress::set_scope(const unsigned int scope)
+{
+  ADDRESS_TRACE;
+
+  if (!valid_flag || (ip_version != version_ipv6))
+      return false;
+
+  unsigned int *scope_ptr = (unsigned int*)(address_buffer + IP6LEN_NO_SCOPE);
+
+  *scope_ptr = htonl(scope);
+  addr_changed = true;
+  smival.value.string.len = IP6LEN_WITH_SCOPE;
+  have_ipv6_scope = true;
+  return true;
+}
+
+//----[ IP address format output ]------------------------------------
+void IpAddress::format_output() const
+{
+  ADDRESS_TRACE;
+
+  // if valid format else null it
+  if (valid_flag)
+  {
+    if (ip_version == version_ipv4)
+      sprintf((char *) output_buffer,"%d.%d.%d.%d",address_buffer[0],
+               address_buffer[1], address_buffer[2], address_buffer[3]);
+    else
+      if (have_ipv6_scope)
+       sprintf((char *) output_buffer,
+               "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
+               "%02x%02x:%02x%02x:%02x%02x:%02x%02x%%%d",
+               address_buffer[ 0], address_buffer[ 1], address_buffer[ 2],
+               address_buffer[ 3], address_buffer[ 4], address_buffer[ 5],
+               address_buffer[ 6], address_buffer[ 7], address_buffer[ 8],
+               address_buffer[ 9], address_buffer[10], address_buffer[11],
+               address_buffer[12], address_buffer[13], address_buffer[14],
+               address_buffer[15], get_scope());
+      else
+        sprintf((char *) output_buffer,
+               "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
+               "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+               address_buffer[ 0], address_buffer[ 1], address_buffer[ 2],
+               address_buffer[ 3], address_buffer[ 4], address_buffer[ 5],
+               address_buffer[ 6], address_buffer[ 7], address_buffer[ 8],
+               address_buffer[ 9], address_buffer[10], address_buffer[11],
+               address_buffer[12], address_buffer[13], address_buffer[14],
+               address_buffer[15]);
+  }
+  else
+    *(char *)output_buffer = 0;
+  IpAddress *nc_this = PP_CONST_CAST(IpAddress*, this);
+  nc_this->addr_changed = false;
+}
+
+//-----------------------------------------------------------------
+// logically and two IPaddresses and
+// return the new one
+void IpAddress::mask(const IpAddress& ipaddr)
+{
+  ADDRESS_TRACE;
+
+  if (valid() && ipaddr.valid())
+  {
+    int count = (ip_version == version_ipv4) ? IPLEN : IP6LEN_NO_SCOPE;
+
+    for (int i = 0; i < count; i++)
+      address_buffer[i] = address_buffer[i] & ipaddr.address_buffer[i];
+    addr_changed = true;
+  }
+}
+
+
+// Get the count of matching bits from the left.
+int IpAddress::get_match_bits(const IpAddress match_ip) const
+{
+  ADDRESS_TRACE;
+
+  int bits = 0;
+
+  if (valid() && match_ip.valid() &&
+      (ip_version == match_ip.ip_version))
+  {
+    int count = (ip_version == version_ipv4) ? IPLEN : IP6LEN_NO_SCOPE;
+
+    for (int i = 0; i < count; i++)
+    {
+       if (address_buffer[i] == match_ip.address_buffer[i])
+           bits += 8;
+       else
+       {
+           bits += 7;
+           unsigned char c1 = address_buffer[i] >> 1;
+           unsigned char c2 = match_ip.address_buffer[i] >> 1;
+           while (c1 != c2)
+           {
+               c1 = c1 >> 1;
+               c2 = c2 >> 1;
+               bits--;
+           }
+           break;
+       }
+    }
+  }
+
+  return bits;
+}
+
+// Map a IPv4 Address to a IPv6 address.
+int IpAddress::map_to_ipv6()
+{
+  ADDRESS_TRACE;
+
+  if (!valid())
+    return FALSE;
+
+  if (ip_version != version_ipv4)
+    return FALSE;
+
+  /* just copy IPv4 address to the end of  the buffer
+     zero the first 10 bytes and fill 2 Bytes with 0xff */
+  memcpy(&address_buffer[12], address_buffer, 4);
+  memset(address_buffer, 0, 10);
+  address_buffer[10] = 0xff;
+  address_buffer[11] = 0xff;
+
+  smival.value.string.len = IP6LEN_NO_SCOPE;
+  ip_version = version_ipv6;
+  have_ipv6_scope = false;
+
+  addr_changed = true;
+  return TRUE;
+}
+
+// Reset the object
+void IpAddress::clear()
+{
+  Address::clear();
+  memset(output_buffer, 0, sizeof(output_buffer));
+  iv_friendly_name_status = 0;
+  ip_version = version_ipv4;
+  have_ipv6_scope = false;
+  memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+  smival.value.string.len = IPLEN;
+}
+
+//=======================================================================
+//========== Udp Address Implementation =================================
+//=======================================================================
+
+//-------[ construct an IP address with no agrs ]----------------------
+UdpAddress::UdpAddress()
+  : IpAddress()
+{
+  ADDRESS_TRACE;
+
+  // Inherits IP Address attributes
+  // Always initialize (override) what type this object is
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = UDPIPLEN;
+  smival.value.string.ptr = address_buffer;
+
+  sep = ':';
+  set_port(0);
+}
+
+//-----------------[ construct an Udp address with another Udp address ]---
+UdpAddress::UdpAddress(const UdpAddress &udpaddr)
+  : IpAddress(udpaddr)
+{
+  ADDRESS_TRACE;
+
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = udpaddr.smival.value.string.len;
+  smival.value.string.ptr = address_buffer;
+
+  // Copy the port value
+  sep = ':';
+  set_port(udpaddr.get_port());
+
+  if (!udpaddr.addr_changed)
+  {
+    memcpy(output_buffer, udpaddr.output_buffer,
+          sizeof(unsigned char) * OUTBUFF);
+    addr_changed = false;
+  }
+}
+
+// constructor with a dotted string
+UdpAddress::UdpAddress(const char *inaddr) : IpAddress()
+{
+  ADDRESS_TRACE;
+
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = UDPIPLEN;
+  smival.value.string.ptr = address_buffer;
+
+  valid_flag = parse_address(inaddr);
+  addr_changed = true;
+}
+
+//-----------------[ construct a UdpAddress from a GenAddress ]--------------
+UdpAddress::UdpAddress(const GenAddress &genaddr) : IpAddress()
+{
+  ADDRESS_TRACE;
+
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = UDPIPLEN;
+  smival.value.string.ptr = address_buffer;
+
+  valid_flag = genaddr.valid();
+
+  // allow use of an ip or udp genaddress
+  if (valid_flag)
+  {
+    if (genaddr.get_type() == type_udp)
+    {
+      *this = genaddr.cast_udpaddress();      // copy in the IP address data
+    }
+    else if (genaddr.get_type() == type_ip)
+    {
+      *this = genaddr.cast_ipaddress();      // copy in the IP address data
+    }
+    else
+    {
+      valid_flag = false;
+    }
+  }
+  sep = ':';
+}
+
+//--------[ construct a udp from an IpAddress ]--------------------------
+UdpAddress::UdpAddress(const IpAddress &ipaddr)
+    : IpAddress(ipaddr)
+{
+  ADDRESS_TRACE;
+
+   // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  if (ip_version == version_ipv4)
+      smival.value.string.len = UDPIPLEN;
+  else
+      if (have_ipv6_scope)
+         smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+      else
+         smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+  smival.value.string.ptr = address_buffer;
+
+  sep = ':';
+  addr_changed = true;
+  set_port(0);
+}
+
+// copy an instance of this Value
+SnmpSyntax& UdpAddress::operator=(const SnmpSyntax &val)
+{
+  ADDRESS_TRACE;
+
+  if (this == &val) return *this;   // protect against assignment from itself
+
+  valid_flag = false;                // will get set TRUE if really valid
+  addr_changed = true;
+  if (val.valid())
+  {
+    switch (val.get_syntax())
+    {
+      case sNMP_SYNTAX_IPADDR:
+      {
+        UdpAddress temp_udp(val.get_printable());
+        *this = temp_udp;        // valid_flag is set by the udp assignment
+        break;
+      }
+      case sNMP_SYNTAX_OCTETS:
+        if (((UdpAddress &)val).smival.value.string.len == UDPIPLEN)
+        {
+          MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
+                 UDPIPLEN);
+         memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+          valid_flag = true;
+          ip_version = version_ipv4;
+          smival.value.string.len = UDPIPLEN;
+        }
+        else if (((UdpAddress &)val).smival.value.string.len == UDPIP6LEN_NO_SCOPE)
+        {
+          MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
+                 UDPIP6LEN_NO_SCOPE);
+         memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+          valid_flag = true;
+          ip_version = version_ipv6;
+          smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+         have_ipv6_scope = false;
+        }
+        else if (((UdpAddress &)val).smival.value.string.len == UDPIP6LEN_WITH_SCOPE)
+        {
+          MEMCPY(address_buffer,((UdpAddress &)val).smival.value.string.ptr,
+                 UDPIP6LEN_WITH_SCOPE);
+         memset(iv_friendly_name, 0, sizeof(char) * MAX_FRIENDLY_NAME);
+          valid_flag = true;
+          ip_version = version_ipv6;
+          smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+         have_ipv6_scope = true;
+        }
+        break;
+        // NOTE: as a value add, other types could have "logical"
+        // mappings, i.e. integer32 and unsigned32
+    }
+  }
+  return *this;
+}
+
+// assignment to another UdpAddress object overloaded
+UdpAddress& UdpAddress::operator=(const UdpAddress &udpaddr)
+{
+  ADDRESS_TRACE;
+
+  if (this == &udpaddr) return *this; // protect against assignment from itself
+
+  (IpAddress &)*this = udpaddr; // use ancestor assignment for ipaddr value
+  if (ip_version == version_ipv4)
+    smival.value.string.len = UDPIPLEN;
+  else
+      if (have_ipv6_scope)
+         smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+      else
+         smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+
+  set_port(udpaddr.get_port());        // copy to port value
+  if (udpaddr.addr_changed)
+  {
+    addr_changed = true;
+  }
+  else
+  {
+    memcpy(output_buffer, udpaddr.output_buffer,
+          sizeof(unsigned char) * OUTBUFF);
+    addr_changed = false;
+  }
+
+  return *this;
+}
+
+// assignment to another UdpAddress object overloaded
+UdpAddress& UdpAddress::operator=(const IpAddress &ipaddr)
+{
+  ADDRESS_TRACE;
+
+  if (this == &ipaddr) return *this; // protect against assignment from itself
+
+  (IpAddress &)*this = ipaddr; // use ancestor assignment for ipaddr value
+
+  if (ip_version == version_ipv4)
+    smival.value.string.len = UDPIPLEN;
+  else
+      if (have_ipv6_scope)
+         smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+      else
+         smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+
+  set_port(0);        // copy to port value
+  addr_changed = true;
+  return *this;
+}
+
+UdpAddress& UdpAddress::operator=(const char *inaddr)
+{
+  ADDRESS_TRACE;
+
+  valid_flag = parse_address(inaddr);
+  addr_changed = true;
+  return *this;
+}
+
+//-----[ IP Address parse Address ]---------------------------------
+bool UdpAddress::parse_address(const char *inaddr)
+{
+  ADDRESS_TRACE;
+
+  addr_changed = true;
+
+  char buffer[MAX_FRIENDLY_NAME];
+
+  if (inaddr && (strlen(inaddr)< MAX_FRIENDLY_NAME))
+  {
+    strcpy(buffer, inaddr);
+    trim_white_space(buffer);
+  }
+  else
+  {
+    valid_flag = false;
+    return FALSE;
+  }
+  // look for port info @ the end of the string
+  // port can be delineated by a ':' or a '/'
+  // if neither are present then just treat it
+  // like a normal IpAddress
+
+  int remove_brackets = FALSE;
+  int found = FALSE;
+  int pos = (int)strlen(buffer) - 1; // safe to cast as max is MAX_FRIENDLY_NAME
+  int do_loop = TRUE;
+  int another_colon_found = FALSE;
+  bool scope_found = false;
+
+  if (pos < 0)
+  {
+    valid_flag = false;
+    return FALSE;
+  }
+
+  // search from the end, to find the start of the port 
+  // [ipv4]:port [ipv4]/port ipv4/port ipv4:port [ipv4] ipv4
+  // [ipv6]:port [ipv6]/port ipv6/port           [ipv6] ipv6
+  while (do_loop)
+  {
+    if (buffer[pos] == '/')
+    {
+      found = TRUE;
+      sep='/';
+      if (buffer[pos -1] == ']')
+        remove_brackets = TRUE;
+      break;
+    }
+    if (buffer[pos] == ':')
+    {
+      if ((pos > 1) && (buffer[pos -1] == ']'))
+      {
+        found = TRUE;
+        remove_brackets = TRUE;
+        sep=':';
+        break;
+      }
+
+      for (int i=pos - 1; i >= 0 ; i--)
+      {
+         if (buffer[i] == ':')
+             another_colon_found = TRUE;
+         if (buffer[i] == '%')
+             scope_found = true;
+      }
+      if (scope_found) // must be ipv6, so reset colon_found
+         another_colon_found = false;
+
+      if (!another_colon_found)
+      {
+        sep=':';
+        found = TRUE;
+        break;
+      }
+    }
+    if (buffer[pos] == ']')
+    {
+      // we found a ] without following a port, so increase pos
+      ++pos;
+      remove_brackets = TRUE;
+      break;
+    }
+    pos--;
+    do_loop = ((found == FALSE) && (pos >= 0) &&
+               (another_colon_found == FALSE));
+  }
+
+  if (remove_brackets)
+  {
+    buffer[pos-1] = 0;
+    buffer[0] = ' ';
+  }
+
+  bool result;
+  unsigned short port;
+
+  if (found)
+  {
+    buffer[pos] = 0;
+    port = atoi(&buffer[pos+1]);
+    result = IpAddress::parse_address(buffer);
+  }
+  else
+  {
+    port = 0;
+    result = IpAddress::parse_address(buffer);
+  }
+
+  if (ip_version == version_ipv4)
+    smival.value.string.len = UDPIPLEN;
+  else
+      if (have_ipv6_scope)
+         smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+      else
+         smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+
+  set_port(port);
+  return result;
+}
+
+
+//--------[ set the port number ]---------------------------------------
+void UdpAddress::set_port(const unsigned short p)
+{
+  ADDRESS_TRACE;
+
+  unsigned short *port_nbo;
+  if (ip_version == version_ipv4)
+    port_nbo = (unsigned short*)(address_buffer + IPLEN);
+  else
+      if (have_ipv6_scope)
+         port_nbo = (unsigned short*)(address_buffer + IP6LEN_WITH_SCOPE);
+      else
+         port_nbo = (unsigned short*)(address_buffer + IP6LEN_NO_SCOPE);
+  *port_nbo = htons(p);
+  addr_changed = true;
+}
+
+//---------[ get the port number ]--------------------------------------
+unsigned short UdpAddress::get_port() const
+{
+  ADDRESS_TRACE;
+
+  if (valid_flag)
+  {
+    const unsigned short *port_nbo;
+    if (ip_version == version_ipv4)
+      port_nbo = (const unsigned short*)(address_buffer + IPLEN);
+    else
+       if (have_ipv6_scope)
+           port_nbo = (const unsigned short*)(address_buffer + IP6LEN_WITH_SCOPE);
+       else
+           port_nbo = (const unsigned short*)(address_buffer + IP6LEN_NO_SCOPE);
+
+    return ntohs(*port_nbo);
+  }
+  return 0;// don't use uninitialized memory
+}
+
+//----[ UDP address format output ]------------------------------------
+void UdpAddress::format_output() const
+{
+  ADDRESS_TRACE;
+
+  IpAddress::format_output(); // allow ancestors to format their buffers
+
+  // if valid format else null it
+  if (valid_flag)
+  {
+    if (ip_version == version_ipv4)
+      sprintf((char *) output_buffer,"%s%c%d",
+               IpAddress::get_printable(),
+               '/',//TODO:look for problems in old code and change to "sep"
+               get_port() );
+      else
+        sprintf((char *) output_buffer,"[%s]%c%d",
+                 IpAddress::get_printable(),
+                 '/',//TODO:look for problems in old code and change to "sep"
+                 get_port() );
+  }
+  else
+    *(char*)output_buffer = 0;
+  UdpAddress *nc_this = PP_CONST_CAST(UdpAddress*, this);
+  nc_this->addr_changed = false;
+}
+
+bool UdpAddress::set_scope(const unsigned int scope)
+{
+  ADDRESS_TRACE;
+
+  /* Save the port, as IpAddress::set_scope destroys it */
+  unsigned short old_port = get_port();
+  if (!IpAddress::set_scope(scope))
+      return false;
+
+  smival.value.string.len = UDPIP6LEN_WITH_SCOPE;
+
+  set_port(old_port);
+
+  return true;
+}
+
+/**
+ * Map a IPv4 UDP address to a IPv6 UDP address.
+ *
+ * @return - TRUE if no error occured.
+ */
+int UdpAddress::map_to_ipv6()
+{
+  ADDRESS_TRACE;
+
+  /* Save the port, as IpAddress::map_to_ipv6 destroys it */
+  unsigned short old_port = get_port();
+
+  /* Map IpAddress */
+  if (!IpAddress::map_to_ipv6())
+    return FALSE;
+
+  set_port(old_port);
+  smival.value.string.len = UDPIP6LEN_NO_SCOPE;
+  ip_version = version_ipv6;
+
+  addr_changed = true;
+  return TRUE;
+}
+
+
+#ifdef _IPX_ADDRESS
+//=======================================================================
+//=========== IPX Address Implementation ================================
+//=======================================================================
+
+//----------[ constructor no args ]--------------------------------------
+IpxAddress::IpxAddress() : Address()
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = IPXLEN;
+  smival.value.string.ptr = address_buffer;
+
+  separator = 0;
+  valid_flag = false;
+  addr_changed = true;
+}
+
+
+//----------[ constructor with a string arg ]---------------------------
+IpxAddress::IpxAddress(const char  *inaddr):Address()
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = IPXLEN;
+  smival.value.string.ptr = address_buffer;
+
+  separator = 0;
+  valid_flag = parse_address(inaddr);
+  addr_changed = true;
+}
+
+
+//-----[ IPX Address copy constructor ]----------------------------------
+IpxAddress::IpxAddress(const IpxAddress &ipxaddr)
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = IPXLEN;
+  smival.value.string.ptr = address_buffer;
+
+  separator = 0;
+  valid_flag = ipxaddr.valid_flag;
+  if (valid_flag)
+     MEMCPY(address_buffer, ipxaddr.address_buffer, IPXLEN);
+  addr_changed = true;
+}
+
+
+//----[ construct an IpxAddress from a GenAddress ]---------------------------
+IpxAddress::IpxAddress(const GenAddress &genaddr)
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = IPXLEN;
+  smival.value.string.ptr = address_buffer;
+
+  valid_flag = genaddr.valid();
+  // allow use of an ipx or ipxsock address
+  if (valid_flag)
+  {
+    if ((genaddr.get_type() == type_ipx) )
+    {
+      *this = genaddr.cast_ipxaddress();     // copy in the Ipx address data
+    }
+    else if ((genaddr.get_type() == type_ipxsock) )
+    {
+      *this = genaddr.cast_ipxsockaddress();  // copy in the Ipx address data
+    }
+    else
+      valid_flag = false;
+  }
+}
+
+//-----[ IPX Address general = operator ]-------------------------------
+SnmpSyntax& IpxAddress::operator=(const SnmpSyntax &val)
+{
+  // protect against assignment from itself
+  if (this == &val) return *this;
+
+  valid_flag = false;              // will set to TRUE if really valid
+  if (val.valid()){
+    switch (val.get_syntax()){
+    case sNMP_SYNTAX_OCTETS:
+      if (((IpxAddress &)val).smival.value.string.len == IPXLEN){
+        MEMCPY(address_buffer, ((IpxAddress &)val).smival.value.string.ptr, IPXLEN);
+        valid_flag = true;
+      }
+    break;
+    }
+  }
+  addr_changed = true;
+  return *this;
+}
+
+//--------[ assignment to another IpAddress object overloaded ]----------
+IpxAddress& IpxAddress::operator=(const IpxAddress &ipxaddress)
+{
+  if (this == &ipxaddress) return *this;// protect against assignment from self
+
+  valid_flag = ipxaddress.valid_flag;
+  if (valid_flag)
+    MEMCPY(address_buffer, ipxaddress.address_buffer, IPXLEN);
+  addr_changed = true;
+  return *this;
+}
+
+
+//-----[ IPX Address parse Address ]-----------------------------------
+// Convert a string to a ten byte ipx address
+// On success sets validity  TRUE or FALSE
+//
+//     IPX address format
+//
+//  NETWORK ID| MAC ADDRESS
+// 01 02 03 04|05 06 07 08 09 10
+// XX XX XX XX|XX XX XX XX XX XX
+//
+//   Valid input format
+//
+//   XXXXXXXX.XXXXXXXXXXXX
+//   Total length must be 21
+//   Must have a separator in it
+//   First string length must be 8
+//   Second string length must be 12
+//   Each char must take on value 0-F
+//
+//
+// Input formats recognized
+//
+//  XXXXXXXX.XXXXXXXXXXXX
+//  XXXXXXXX:XXXXXXXXXXXX
+//  XXXXXXXX-XXXXXXXXXXXX
+//  XXXXXXXX.XXXXXX-XXXXXX
+//  XXXXXXXX:XXXXXX-XXXXXX
+//  XXXXXXXX-XXXXXX-XXXXXX
+bool IpxAddress::parse_address(const char *inaddr)
+{
+  char unsigned *str1,*str2;
+  char temp[30];    // don't destroy original
+  char unsigned *tmp;
+  size_t z, tmplen;
+
+  // save the orginal source
+  if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
+  strcpy(temp, inaddr);
+  trim_white_space(temp);
+  tmplen = strlen(temp);
+
+  // bad total length check
+  // 123456789012345678901
+  // XXXXXXXX-XXXXXXXXXXXX  21 len
+  //
+  // XXXXXXXX-XXXXXX-XXXXXX 22 len
+  // need at least 21 chars and no more than 22
+  if ((tmplen <21) || (tmplen >22))
+    return FALSE;
+
+  // convert the string to all lower case
+  // this allows hex values to be in upper or lower
+  for (z=0;z< tmplen;z++)
+    temp[z] = tolower(temp[z]);
+
+  // check for separated nodeid
+  // if found remove it
+  if (temp[15] == '-')
+  {
+     for(z=16;z<tmplen;z++)
+        temp[z-1] = temp[z];
+     temp[tmplen-1] = 0;
+  }
+
+  // no dot or colon separator check
+  separator = temp[8];
+  if ((separator != ':') &&
+      (separator != '.') &&
+      (separator != '-') &&
+      (separator != ' '))
+    return FALSE;
+
+  // separate the strings
+  str1 = (unsigned char *) temp;
+  while(*str1 != separator) str1++;
+  str2 = str1 + 1;
+  *str1 = 0;
+  str1= (unsigned char *) temp;
+
+  // check len of the network portion
+  if (strlen((char *) str1) != 8) return FALSE;
+
+  // check len of mac portion
+  if (strlen((char *) str2) != 12) return FALSE;
+
+  // ok we like then lens, make sure that all chars are 0-f
+  // check out the net id
+  tmp = str1;
+  while(*tmp != 0)
+    if (((*tmp >= '0') && (*tmp <= '9'))||   // good 0-9
+        ((*tmp >= 'a') && (*tmp <= 'f')))    // or a-f
+      tmp++;
+    else
+      return FALSE;
+
+  // check out the MAC address
+  tmp = str2;
+  while(*tmp != 0)
+    if (((*tmp >= '0') && (*tmp <= '9'))||   // good 0-9
+        ((*tmp >= 'a') && (*tmp <= 'f')))    // or a-f
+      tmp++;
+    else
+      return FALSE;
+
+  // convert to target string
+  tmp = str1;
+  while (*tmp != 0)
+  {
+  if ((*tmp >= '0') && (*tmp <= '9'))
+    *tmp = *tmp - (char unsigned )'0';
+  else
+    *tmp = *tmp - (char unsigned) 'a' + (char unsigned) 10;
+  tmp++;
+  }
+
+  // network id portion
+  address_buffer[0] = (str1[0]*16) + str1[1];
+  address_buffer[1] = (str1[2]*16) + str1[3];
+  address_buffer[2] = (str1[4]*16) + str1[5];
+  address_buffer[3] = (str1[6]*16) + str1[7];
+
+  tmp = str2;
+  while (*tmp != 0)
+  {
+  if ((*tmp >= '0') && (*tmp <= '9'))
+    *tmp = *tmp - (char unsigned) '0';
+  else
+    *tmp = *tmp - (char unsigned) 'a'+ (char unsigned) 10;
+  tmp++;
+  }
+
+  address_buffer[4] = (str2[0]*16)  + str2[1];
+  address_buffer[5] = (str2[2]*16)  + str2[3];
+  address_buffer[6] = (str2[4]*16)  + str2[5];
+  address_buffer[7] = (str2[6]*16)  + str2[7];
+  address_buffer[8] = (str2[8]*16)  + str2[9];
+  address_buffer[9] = (str2[10]*16) + str2[11];
+
+  return TRUE;
+}
+
+//----[ IPX address format output ]-------------------------------------
+void IpxAddress::format_output() const
+{
+  if (valid_flag)
+    sprintf((char *) output_buffer,
+            "%02x%02x%02x%02x%c%02x%02x%02x%02x%02x%02x",
+            address_buffer[0],address_buffer[1],
+            address_buffer[2],address_buffer[3],'-',
+            address_buffer[4],address_buffer[5],
+            address_buffer[6],address_buffer[7],
+            address_buffer[8],address_buffer[9]);
+  else
+    *(char*)output_buffer = 0;
+  IpxAddress *nc_this = PP_CONST_CAST(IpxAddress*, this);
+  nc_this->addr_changed = false;
+}
+
+
+#ifdef _MAC_ADDRESS
+// get the host id portion of an ipx address
+int IpxAddress::get_hostid(MacAddress& mac) const
+{
+   if (valid_flag)
+   {
+       char buffer[18];
+       sprintf(buffer,"%02x:%02x:%02x:%02x:%02x:%02x", address_buffer[4],
+                address_buffer[5], address_buffer[6], address_buffer[7],
+                address_buffer[8], address_buffer[9]);
+       MacAddress temp(buffer);
+       mac = temp;
+       if (mac.valid())
+        return TRUE;
+   }
+   return FALSE;
+}
+#endif // function that needs _MAC_ADDRESS
+
+//========================================================================
+//======== IpxSockAddress Implementation =================================
+//========================================================================
+
+//----------[ constructor no args ]--------------------------------------
+IpxSockAddress::IpxSockAddress() : IpxAddress()
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = IPXSOCKLEN;
+  smival.value.string.ptr = address_buffer;
+
+  set_socket(0);
+  addr_changed = true;
+}
+
+//-----------[ construct an IpxSockAddress with another IpxSockAddress]----
+IpxSockAddress::IpxSockAddress(const IpxSockAddress &ipxaddr)
+  : IpxAddress(ipxaddr)
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = IPXSOCKLEN;
+  smival.value.string.ptr = address_buffer;
+
+  // copy the socket value
+  set_socket(ipxaddr.get_socket());
+  addr_changed = true;
+}
+
+
+//---------------[ construct a IpxSockAddress from a string ]--------------
+IpxSockAddress::IpxSockAddress(const char *inaddr):IpxAddress()
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = IPXSOCKLEN;
+  smival.value.string.ptr = address_buffer;
+
+  valid_flag = parse_address(inaddr);
+  addr_changed = true;
+}
+
+
+//---------------[ construct a IpxSockAddress from a GenAddress ]----------
+IpxSockAddress::IpxSockAddress(const GenAddress &genaddr):IpxAddress()
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = IPXSOCKLEN;
+  smival.value.string.ptr = address_buffer;
+
+  valid_flag = false;
+  unsigned short socketid = 0;
+  // allow use of an ipx or ipxsock address
+  if ((genaddr.get_type() == type_ipx) )
+  {
+    valid_flag = genaddr.valid();
+    if (valid_flag)
+    {
+      // copy in the Ipx address data
+      IpxAddress temp_ipx((const char *) genaddr);
+      *this = temp_ipx;
+    }
+  }
+  else if ((genaddr.get_type() == type_ipxsock) )
+  {
+    valid_flag = genaddr.valid();
+    if (valid_flag)
+    {
+      // copy in the Ipx address data
+      IpxSockAddress temp_ipxsock((const char *) genaddr);
+      *this = temp_ipxsock;
+      //  socketid info since are making an IpxSockAddress
+      socketid = temp_ipxsock.get_socket();
+    }
+  }
+  set_socket(socketid);
+  addr_changed = true;
+}
+
+//------------[ construct an IpxSockAddress from a IpxAddress ]--------------
+IpxSockAddress::IpxSockAddress(const IpxAddress &ipxaddr):IpxAddress(ipxaddr)
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = IPXSOCKLEN;
+  smival.value.string.ptr = address_buffer;
+
+  set_socket(0);
+  addr_changed = true;
+}
+
+// copy an instance of this Value
+SnmpSyntax& IpxSockAddress::operator=(const SnmpSyntax &val)
+{
+  if (this == &val) return *this; // protect against assignment from itself
+
+  valid_flag = false;              // will set to TRUE if really valid
+  if (val.valid()){
+    switch (val.get_syntax()){
+    case sNMP_SYNTAX_OCTETS:
+      {
+        // See if it is of the Ipx address family
+        // This handles IpxSockAddress == IpxAddress
+        IpxSockAddress temp_ipx(val.get_printable());
+        if (temp_ipx.valid()){
+          *this = temp_ipx;                // ipxsock = ipxsock
+        }
+        // See if it is an OctetStr of appropriate length
+        else if (((IpxSockAddress &)val).smival.value.string.len == IPXSOCKLEN){
+          MEMCPY(address_buffer,
+                 ((IpxSockAddress &)val).smival.value.string.ptr,
+                 IPXSOCKLEN);
+          valid_flag = true;
+        }
+      }
+      break;
+    }
+  }
+  addr_changed = true;
+  return *this;
+}
+
+// assignment to another IpAddress object overloaded
+IpxSockAddress& IpxSockAddress::operator=(const IpxSockAddress &ipxaddr)
+{
+  if (this == &ipxaddr) return *this; // protect against assignment from itself
+
+  (IpxAddress&)*this = ipxaddr;         // use ancestor assignment for ipx addr
+  set_socket(ipxaddr.get_socket());        // copy socket value
+  addr_changed = true;
+  return *this;
+}
+
+//----[ IPX address format output ]-------------------------------------
+void IpxSockAddress::format_output() const
+{
+  IpxAddress::format_output(); // allow ancestors to format their buffers
+
+  if (valid_flag)
+    sprintf((char *) output_buffer,"%s/%d",
+            IpxAddress::get_printable(), get_socket());
+  else
+    *(char*)output_buffer = 0;
+  IpxSockAddress *nc_this = PP_CONST_CAST(IpxSockAddress*, this);
+  nc_this->addr_changed = false;
+}
+
+//-----[ IP Address parse Address ]---------------------------------
+bool IpxSockAddress::parse_address(const char *inaddr)
+{
+   char buffer[MAX_FRIENDLY_NAME];
+   unsigned short socketid=0;
+
+   if (inaddr && (strlen(inaddr)< MAX_FRIENDLY_NAME))
+     strcpy(buffer, inaddr);
+   else
+   {
+     valid_flag = false;
+     return FALSE;
+   }
+   // look for port info @ the end of the string
+   // port can be delineated by a ':' or a '/'
+   // if neither are present then just treat it
+   // like a normal IpAddress
+   char *tmp;
+   tmp = strstr(buffer,"/");
+
+   if (tmp != NULL)
+   {
+     *tmp=0;   // new null terminator
+     tmp++;
+     socketid = atoi(tmp);
+   }
+   set_socket(socketid);
+   return IpxAddress::parse_address(buffer);
+}
+
+
+
+//-------------[ set the socket number ]----------------------------------
+void IpxSockAddress::set_socket(const unsigned short s)
+{
+  unsigned short sock_nbo = htons(s);
+  MEMCPY(&address_buffer[IPXLEN], &sock_nbo, 2);
+  addr_changed = true;
+}
+
+//--------------[ get the socket number ]---------------------------------
+unsigned short IpxSockAddress::get_socket() const
+{
+  if (valid_flag)
+  {
+    unsigned short sock_nbo;
+    MEMCPY(&sock_nbo, &address_buffer[IPXLEN], 2);
+    return ntohs(sock_nbo);
+  }
+  return 0; // don't use uninitialized memory
+}
+#endif // _IPX_ADDRESS
+
+#ifdef _MAC_ADDRESS
+//========================================================================
+//======== MACAddress Implementation =====================================
+//========================================================================
+
+//--------[ constructor, no arguments ]-----------------------------------
+MacAddress::MacAddress() : Address()
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = MACLEN;
+  smival.value.string.ptr = address_buffer;
+
+  valid_flag = false;
+  addr_changed = true;
+}
+
+//-----[ MAC Address copy constructor ]---------------------------------
+MacAddress::MacAddress(const MacAddress &macaddr)
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = MACLEN;
+  smival.value.string.ptr = address_buffer;
+
+  valid_flag = macaddr.valid_flag;
+  if (valid_flag)
+    MEMCPY(address_buffer, macaddr.address_buffer, MACLEN);
+  addr_changed = true;
+}
+
+//---------[ constructor with a string argument ]-------------------------
+MacAddress::MacAddress(const char  *inaddr):Address()
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = MACLEN;
+  smival.value.string.ptr = address_buffer;
+
+  valid_flag = parse_address(inaddr);
+  addr_changed = true;
+}
+
+//-----[ construct a MacAddress from a GenAddress ]------------------------
+MacAddress::MacAddress(const GenAddress &genaddr)
+{
+  // always initialize SMI info
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = MACLEN;
+  smival.value.string.ptr = address_buffer;
+
+  valid_flag = false;
+  // allow use of mac address
+  if (genaddr.get_type() == type_mac)
+  {
+    valid_flag = genaddr.valid();
+    if (valid_flag)
+    {
+      // copy in the Mac address data
+      *this = genaddr.cast_macaddress();
+    }
+  }
+  addr_changed = true;
+}
+
+//------[ assignment to another ipaddress object overloaded ]--------------
+MacAddress& MacAddress::operator=(const MacAddress &macaddress)
+{
+  if (this == &macaddress) return *this;// protect against assignment from self
+
+  valid_flag = macaddress.valid_flag;
+  if (valid_flag)
+    MEMCPY(address_buffer, macaddress.address_buffer, MACLEN);
+  addr_changed = true;
+  return *this;
+}
+
+
+
+//-----[ MAC Address general = operator ]---------------------------------
+SnmpSyntax& MacAddress::operator=(const SnmpSyntax &val)
+{
+  if (this == &val) return *this;  // protect against assignment from itself
+
+  valid_flag = false;              // will set to TRUE if really valid
+  if (val.valid())
+  {
+    switch (val.get_syntax())
+    {
+      case sNMP_SYNTAX_OCTETS:
+       if (((MacAddress &)val).smival.value.string.len == MACLEN)
+       {
+         MEMCPY(address_buffer, ((MacAddress &)val).smival.value.string.ptr,
+                MACLEN);
+         valid_flag = true;
+       }
+       break;
+    }
+  }
+  addr_changed = true;
+  return *this;
+}
+
+//-----[ MAC Address parse Address ]--------------------------------------
+// Convert a string to a six byte MAC address
+// On success sets validity TRUE or FALSE
+//
+//     MAC address format
+//
+//   MAC ADDRESS
+//   01 02 03 04 05 06
+//   XX:XX:XX:XX:XX:XX
+//   Valid input format
+//
+//   XXXXXXXXXXXX
+//   Total length must be 17
+//   Each char must take on value 0-F
+//
+//
+bool MacAddress::parse_address(const char *inaddr)
+{
+  char temp[30];    // don't destroy original
+  char unsigned *tmp;
+  size_t z;
+
+  // save the orginal source
+  if (!inaddr || (strlen(inaddr) >= sizeof(temp))) return FALSE;
+  strcpy(temp, inaddr);
+  trim_white_space(temp);
+
+  // bad total length check
+  if (strlen(temp) != 17)
+     return FALSE;
+
+  // check for colons
+  if ((temp[2] != ':')||(temp[5] != ':')||(temp[8]!=':')||(temp[11]!=':')||(temp[14] !=':'))
+     return FALSE;
+
+  // strip off the colons
+  tmp = (unsigned char *) temp;
+  int i = 0;
+  while (*tmp != 0)
+  {
+     if (*tmp != ':')
+     {
+        temp[i] = *tmp;
+        i++;
+     }
+     tmp++;
+  }
+  temp[i] = 0;
+
+  // convert to lower
+  for(z=0;z<strlen(temp);z++)
+     temp[z] = tolower(temp[z]);
+
+
+  // check out the MAC address
+  tmp = (unsigned char *) temp;
+  while(*tmp != 0)
+    if (((*tmp >= '0') && (*tmp <= '9'))||   // good 0-9
+        ((*tmp >= 'a') && (*tmp <= 'f')))    // or a-f
+      tmp++;
+    else
+      return FALSE;
+
+  // convert to target string
+  tmp = (unsigned char *) temp;
+  while (*tmp != 0)
+  {
+  if ((*tmp >= '0') && (*tmp <= '9'))
+    *tmp = *tmp - (char unsigned )'0';
+  else
+    *tmp = *tmp - (char unsigned) 'a' + (char unsigned) 10;
+  tmp++;
+  }
+
+  address_buffer[0] =  (temp[0]*16) + temp[1];
+  address_buffer[1] =  (temp[2]*16) + temp[3];
+  address_buffer[2] =  (temp[4]*16) + temp[5];
+  address_buffer[3] =  (temp[6]*16) + temp[7];
+  address_buffer[4] =  (temp[8]*16) + temp[9];
+  address_buffer[5] =  (temp[10]*16) + temp[11];
+
+  return TRUE;
+}
+
+//----[ MAC address format output ]---------------------------------
+void MacAddress::format_output() const
+{
+  if (valid_flag)
+    sprintf((char*)output_buffer,"%02x:%02x:%02x:%02x:%02x:%02x",
+           address_buffer[0], address_buffer[1], address_buffer[2],
+           address_buffer[3], address_buffer[4], address_buffer[5]);
+  else
+    *(char*)output_buffer = 0;
+  MacAddress *nc_this = PP_CONST_CAST(MacAddress*, this);
+  nc_this->addr_changed = false;
+}
+
+unsigned int MacAddress::hashFunction() const
+{
+  return ((((address_buffer[0] << 8) + address_buffer[1]) * HASH0)
+       + (((address_buffer[2] << 8) + address_buffer[3]) * HASH1)
+        + (((address_buffer[4] << 8) + address_buffer[5]) * HASH2));
+}
+#endif // _MAC_ADDRESS
+
+//========================================================================
+//========== Generic Address Implementation ==============================
+//========================================================================
+
+//-----------[ constructor, no arguments ]--------------------------------
+GenAddress::GenAddress() : Address()
+{
+  ADDRESS_TRACE;
+
+  // initialize SMI info
+  // BOK: this is generally not used for GenAddress,
+  // but we need this to be a replica of the real address'
+  // smival info so that operator=SnmpSyntax will work.
+  smival.syntax = sNMP_SYNTAX_NULL;                // to be overridden
+  smival.value.string.len = 0;                        // to be overridden
+  smival.value.string.ptr = address_buffer;        // constant
+
+  valid_flag = false;
+  address = 0;
+  output_buffer[0] = 0;
+}
+
+//-----------[ constructor with a string argument ]----------------------
+GenAddress::GenAddress(const char  *addr,
+                      const Address::addr_type use_type)
+{
+  ADDRESS_TRACE;
+
+  // initialize SMI info
+  // BOK: smival is generally not used for GenAddress, but
+  //      we need this to be a replica of the real address'
+  //      smival info so that <class>::operator=SnmpSyntax
+  //      will work.
+  smival.syntax = sNMP_SYNTAX_NULL;                // to be overridden
+  smival.value.string.len = 0;                        // to be overridden
+  smival.value.string.ptr = address_buffer;        // constant
+
+  address = 0;
+  parse_address(addr, use_type);
+
+  // Copy real address smival info into GenAddr smival
+  // BOK: smival is generally not used for GenAddress, but
+  //      we need this to be a replica of the real address'
+  //      smival info so that <class>::operator=SnmpSyntax
+  //      will work.
+  if (valid_flag ) {
+      smival.syntax = ((GenAddress *)address)->smival.syntax;
+      smival.value.string.len =
+          ((GenAddress *)address)->smival.value.string.len;
+      memcpy(smival.value.string.ptr,
+          ((GenAddress *)address)->smival.value.string.ptr,
+          (size_t)smival.value.string.len);
+  }
+  output_buffer[0] = 0;
+}
+
+//-----------[ constructor with an Address argument ]--------------------
+GenAddress::GenAddress(const Address &addr)
+{
+  ADDRESS_TRACE;
+
+  output_buffer[0] = 0;
+  // initialize SMI info
+  // BOK: this is generally not used for GenAddress,
+  // but we need this to be a replica of the real address'
+  // smival info so that operator=SnmpSyntax will work.
+  smival.syntax = sNMP_SYNTAX_NULL;                // to be overridden
+  smival.value.string.len = 0;                        // to be overridden
+  smival.value.string.ptr = address_buffer;        // constant
+
+  valid_flag = false;
+  // make sure that the object is valid
+  if (!addr.valid()) {
+    address = 0;
+    return;
+  }
+
+  // addr can be a GenAddress object and calling clone() on that is bad...
+  if (addr.is_gen_address())
+    address = (Address *)(((const GenAddress&)addr).address->clone());
+  else
+    address = (Address*)addr.clone();
+
+  if (address)
+    valid_flag = address->valid();
+
+  // Copy real address smival info into GenAddr smival
+  // BOK: smival is generally not used for GenAddress, but
+  //      we need this to be a replica of the real address'
+  //      smival info so that <class>::operator=SnmpSyntax
+  //      will work.
+  if (valid_flag )
+  {
+    smival.syntax = address->get_syntax();
+    smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
+    memcpy(smival.value.string.ptr,
+           ((GenAddress *)address)->smival.value.string.ptr,
+           (size_t)smival.value.string.len);
+  }
+}
+
+//-----------------[ constructor with another GenAddress object ]-------------
+GenAddress::GenAddress(const GenAddress &addr)
+{
+  ADDRESS_TRACE;
+
+  output_buffer[0] = 0;
+  // initialize SMI info
+  // BOK: this is generally not used for GenAddress,
+  // but we need this to be a replica of the real address'
+  // smival info so that operator=SnmpSyntax will work.
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.len = 0;
+  smival.value.string.ptr = address_buffer;
+
+  valid_flag = false;
+  // make sure that the object is valid
+  if (!addr.valid_flag)
+  {
+    address = 0;
+    return;
+  }
+
+  address = (Address *)addr.address->clone();
+  if (address)
+    valid_flag = address->valid();
+
+  // Copy real address smival info into GenAddr smival
+  // BOK: smival is generally not used for GenAddress, but
+  //      we need this to be a replica of the real address'
+  //      smival info so that <class>::operator=SnmpSyntax
+  //      will work.
+  if (valid_flag )
+  {
+    smival.syntax = ((GenAddress *)address)->smival.syntax;
+    smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
+    memcpy(smival.value.string.ptr,
+           ((GenAddress *)address)->smival.value.string.ptr,
+           (size_t)smival.value.string.len);
+  }
+}
+
+//------[ assignment GenAddress = GenAddress ]-----------------------------
+GenAddress& GenAddress::operator=(const GenAddress &addr)
+{
+  ADDRESS_TRACE;
+
+  if (this == &addr) return *this;  // protect against assignment from itself
+
+  valid_flag = false;
+  if (address)
+  {
+    delete address;
+    address = 0;
+  }
+  if (addr.address)
+    address = (Address *)(addr.address->clone());
+  if (address)
+    valid_flag = address->valid();
+
+  // Copy real address smival info into GenAddr smival
+  // BOK: smival is generally not used for GenAddress, but
+  //      we need this to be a replica of the real address'
+  //      smival info so that <class>::operator=SnmpSyntax
+  //      will work.
+  if (valid_flag )
+  {
+    smival.syntax = ((GenAddress *)address)->smival.syntax;
+    smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
+    memcpy(smival.value.string.ptr,
+           ((GenAddress *)address)->smival.value.string.ptr,
+           (size_t)smival.value.string.len);
+  }
+
+  return *this;
+}
+
+//------[ assignment GenAddress = Address ]--------------------------------
+GenAddress& GenAddress::operator=(const Address &addr)
+{
+  ADDRESS_TRACE;
+
+  if (this == &addr) return *this;  // protect against assignment from itself
+
+  valid_flag = false;
+  if (address)
+  {
+    delete address;
+    address = 0;
+  }
+
+  // addr can be a GenAddress object and calling clone() on that is bad...
+  if (addr.is_gen_address())
+    address = (Address *)(((const GenAddress&)addr).address->clone());
+  else
+    address = (Address*)addr.clone();
+
+  if (address)
+    valid_flag = address->valid();
+
+  // Copy real address smival info into GenAddr smival
+  // BOK: smival is generally not used for GenAddress, but
+  //      we need this to be a replica of the real address'
+  //      smival info so that <class>::operator=SnmpSyntax
+  //      will work.
+  if (valid_flag )
+  {
+    smival.syntax = ((GenAddress *)address)->smival.syntax;
+    smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
+    memcpy(smival.value.string.ptr,
+           ((GenAddress *)address)->smival.value.string.ptr,
+           (size_t)smival.value.string.len);
+  }
+
+  return *this;
+}
+
+
+//------[ assignment GenAddress = any SnmpSyntax ]-----------------------
+SnmpSyntax& GenAddress::operator=(const SnmpSyntax &val)
+{
+  ADDRESS_TRACE;
+
+  if (this == &val) return *this; // protect against assignment from itself
+
+  valid_flag = false;             // will get set to TRUE if really valid
+  if (address)
+  {
+    delete address;
+    address = 0;
+  }
+
+  if (val.valid())
+  {
+    switch (val.get_syntax() )
+    {
+      //-----[ ip address case ]-------------
+      // BOK: this case shouldn't be needed since there is an explicit
+      // GenAddr=Address assignment that will override this assignment.
+      // Left here for posterity.
+      case sNMP_SYNTAX_IPADDR:
+      {
+        address = new IpAddress(val.get_printable());
+        if (address)
+          valid_flag = address->valid();
+      }
+      break;
+
+      //-----[ udp address case ]------------
+      //-----[ ipx address case ]------------
+      //-----[ mac address case ]------------
+      // BOK:  This is here only to support GenAddr = primitive OctetStr.
+      // The explicit GenAddr=Address assignment will handle the cases
+      // GenAddr = [UdpAdd|IpxAddr|IpxSock|MacAddr].
+      // Note, using the heuristic of octet str len to determine type of
+      // address to create is not accurate when address lengths are equal
+      // (e.g., UDPIPLEN == MACLEN).  It gets worse if we add AppleTalk or
+      // OSI which use variable length addresses!
+      case sNMP_SYNTAX_OCTETS:
+      {
+        unsigned long val_len;
+        val_len = ((GenAddress &)val).smival.value.string.len;
+
+        if ((val_len == UDPIPLEN) || IS_UDPIP6LEN(val_len))
+          address = new UdpAddress;
+        else if ((val_len == IPLEN) || IS_IP6LEN(val_len))
+          address = new IpAddress;
+#ifdef _IPX_ADDRESS
+        else if (val_len == IPXLEN)
+          address = new IpxAddress;
+        else if (val_len == IPXSOCKLEN)
+          address = new IpxSockAddress;
+#endif
+#ifdef _MAC_ADDRESS
+        else  if (val_len == MACLEN)
+          address = new MacAddress;
+#endif
+
+        if (address)
+        {
+          *address = val;
+          valid_flag = address->valid();
+        }
+      }
+      break;
+    }   // end switch
+  }
+
+  // Copy real address smival info into GenAddr smival
+  // BOK: smival is generally not used for GenAddress, but
+  //      we need this to be a replica of the real address'
+  //      smival info so that <class>::operator=SnmpSyntax
+  //      will work.
+  if (valid_flag )
+  {
+    smival.syntax = ((GenAddress *)address)->smival.syntax;
+    smival.value.string.len = ((GenAddress *)address)->smival.value.string.len;
+    memcpy(smival.value.string.ptr,
+           ((GenAddress *)address)->smival.value.string.ptr,
+           (size_t)smival.value.string.len);
+  }
+
+  return *this;
+}
+
+
+// redefined parse address for macs
+bool GenAddress::parse_address(const char *addr,
+                              const Address::addr_type use_type)
+{
+  ADDRESS_TRACE;
+
+  if (address) delete address;
+
+  // try to create each of the addresses until the correct one
+  // is found
+
+  //BOK: Need to try IPX Sock and IPX before UDP since on Win32,
+  //     gethostbyname() seems to think the ipx network number
+  //     portion is a valid ipaddress string... stupid WinSOCK!
+
+#ifdef _IPX_ADDRESS
+  if ((use_type == Address::type_invalid) ||
+      (use_type == Address::type_ipxsock))
+  {
+    // ipxsock address
+    address = new IpxSockAddress(addr);
+    valid_flag = address->valid();
+    if (valid_flag && ((IpxSockAddress*)address)->get_socket())
+      return TRUE;   // ok its an ipxsock address
+
+    delete address;  // otherwise delete it and try another
+  }
+
+  if ((use_type == Address::type_invalid) ||
+      (use_type == Address::type_ipx))
+  {
+    // ipx address
+    address = new IpxAddress(addr);
+    valid_flag = address->valid();
+    if (valid_flag)
+      return TRUE;   // ok its an ipx address
+
+    delete address;  // otherwise delete it and try another
+  }
+#endif // _IPX_ADDRESS
+
+  //TM: Must try the derived classes first...one pitfall of the
+  //following solution is if someone creates with a port/socket of 0 the
+  //class will get demoted to ip/ipx.  The only proper way to do this is
+  //to parse the strings ourselves.
+
+  if ((use_type == Address::type_invalid) ||
+      (use_type == Address::type_udp))
+  {
+    // udp address
+    address = new UdpAddress(addr);
+    valid_flag = address->valid();
+    if (valid_flag && ((UdpAddress*)address)->get_port())
+      return TRUE;       // ok its a udp address
+
+    delete address;  // otherwise delete it and try another
+  }
+
+  if ((use_type == Address::type_invalid) ||
+      (use_type == Address::type_ip))
+  {
+    // ip address
+    address = new IpAddress(addr);
+    valid_flag = address->valid();
+    if (valid_flag)
+      return TRUE;       // ok its an ip address
+
+    delete address;   // otherwise delete it and try another
+  }
+
+#ifdef _MAC_ADDRESS
+  if ((use_type == Address::type_invalid) ||
+      (use_type == Address::type_mac))
+  {
+    // mac address
+    address = new MacAddress(addr);
+    valid_flag = address->valid();
+    if (valid_flag)
+      return TRUE;    // ok, its a mac
+
+    delete address;  // otherwise its invalid
+  }
+#endif // _MAC_ADDRESS
+
+  address = 0;
+  return FALSE;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/asn1.cpp b/3rdparty/snmp++/src/asn1.cpp
new file mode 100644 (file)
index 0000000..eec57c5
--- /dev/null
@@ -0,0 +1,1997 @@
+/*_############################################################################
+  _## 
+  _##  asn1.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+/*===================================================================
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+  A S N 1. C P P
+
+  ASN encoder / decoder implementation
+
+  DESIGN + AUTHOR:  Peter E. Mellquist
+=====================================================================*/
+char asn1_cpp_version[]="#(@) SNMP++ $Id: asn1.cpp 1557 2009-07-03 20:16:09Z katz $";
+
+#ifdef __unix
+#include /**/ <sys/types.h>
+#include /**/ <netinet/in.h>
+#endif
+
+#include /**/ <stdlib.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/snmperrs.h"
+#include "snmp_pp/log.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifndef NULL
+#define NULL   0
+#endif
+
+/*
+ * asn_parse_int - pulls a long out of an ASN int type.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the end of this object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_parse_int(unsigned char *data,
+                            int *datalength,
+                            unsigned char *type,
+                            long *intp)
+{
+  /*
+   * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+   *       timestamp   0x43 asnlength byte {byte}*
+   */
+  unsigned char *bufp = data;
+  unsigned long         asn_length;
+  long value = 0;
+
+  *type = *bufp++;
+  if ((*type != 0x02) && (*type != 0x43) &&
+      (*type != 0x41)) {
+    ASNERROR("Wrong Type. Not an integer");
+    return NULL;
+  }
+  bufp = asn_parse_length(bufp, &asn_length);
+  if (bufp == NULL) {
+    ASNERROR("bad length");
+    return NULL;
+  }
+  if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+    ASNERROR("overflow of message (int)");
+    return NULL;
+  }
+  if (asn_length > sizeof(*intp)) {
+    ASNERROR("I don't support such large integers");
+    return NULL;
+  }
+  *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+  if (*bufp & 0x80)
+    value = -1; /* integer is negative */
+  while(asn_length--)
+    value = (value << 8) | *bufp++;
+  *intp = value;
+  return bufp;
+}
+
+
+/*
+ * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the end of this object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_parse_unsigned_int(unsigned char *data,     
+                                      int *datalength,
+                                      unsigned char *type,
+                                      unsigned long *intp)
+{
+  /*
+   * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+   *                   0x43 asnlength byte {byte}*
+   */
+  unsigned char *bufp = data;
+  unsigned long        asn_length;
+  unsigned long value = 0;
+
+  // get the type
+  *type = *bufp++;
+  if ((*type != 0x02) && (*type != 0x43) &&
+      (*type != 0x41) && (*type != 0x42) &&
+      (*type != 0x47)) {
+    ASNERROR("Wrong Type. Not an unsigned integer");
+    return NULL;
+  }
+
+  // pick up the len
+  bufp = asn_parse_length(bufp, &asn_length);
+  if (bufp == NULL) {
+    ASNERROR("bad length");
+    return NULL;
+  }
+
+  // check the len for message overflow
+  if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+    ASNERROR("overflow of message (uint)");
+    return NULL;
+  }
+
+  // check for legal uint size
+  if ((asn_length > 5) || ((asn_length > 4) && (*bufp != 0x00))) {
+    ASNERROR("I don't support such large integers");
+    return NULL;
+  }
+
+  // check for leading  0 octet
+  if (*bufp == 0x00) {
+    bufp++;
+    asn_length--;
+  }
+
+  // fix the returned data length value
+  *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+
+  // calculate the value
+  for (long i=0;i<(long)asn_length;i++)
+    value = (value << 8) + (unsigned long) *bufp++;
+
+  *intp = value;  // assign return value
+
+  return bufp;   // return the bumped pointer
+}
+
+
+/*
+ * asn_build_int - builds an ASN object containing an integer.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the end of this object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_build_int(unsigned char *data, int *datalength,
+                             const unsigned char type,
+                             const long *intp)
+{
+  /*
+   * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+   */
+  long integer = *intp;
+  unsigned long mask;
+  int intsize = sizeof(long);
+
+  /* Truncate "unnecessary" bytes off of the most significant end of this
+   * 2's complement integer.  There should be no sequence of 9
+   * consecutive 1's or 0's at the most significant end of the
+   * integer.
+   */
+  mask = 0x1FFul << ((8 * (sizeof(long) - 1)) - 1);
+  /* mask is 0xFF800000 on a big-endian machine */
+  while((((integer & mask) == 0) || ((integer & mask) == mask))
+       && intsize > 1) {
+    intsize--;
+    integer <<= 8;
+  }
+  data = asn_build_header(data, datalength, type, intsize);
+  if (data == NULL)          return NULL;
+  if (*datalength < intsize) return NULL;
+  *datalength -= intsize;
+  mask = 0xFFul << (8 * (sizeof(long) - 1));
+  /* mask is 0xFF000000 on a big-endian machine */
+  while(intsize--) {
+    *data++ = (unsigned char)((integer & mask) >> (8 * (sizeof(long) - 1)));
+    integer <<= 8;
+  }
+  return data;
+}
+
+
+/*
+ * asn_build_unsigned_int - builds an ASN object containing an integer.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the end of this object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_build_unsigned_int(unsigned char *data, // modified data
+                                      int *datalength,     // returned buffer length
+                                      unsigned char type,  // SMI type
+                                      unsigned long *intp) // Uint to encode
+{
+  /*
+   * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+   */
+  unsigned long u_integer = *intp;
+  long u_integer_len;
+  long x;
+
+  // figure out the len
+  if (((u_integer >> 24) & 0xFF) != 0)
+    u_integer_len = 4;
+  else if (((u_integer >> 16) & 0xFF) !=0)
+    u_integer_len = 3;
+  else if (((u_integer >> 8) & 0xFF) !=0)
+    u_integer_len = 2;
+  else
+    u_integer_len = 1;
+
+  // check for 5 byte len where first byte will be a null
+  if (((u_integer >> (8 * (u_integer_len -1))) & 0x080) !=0)   {
+    u_integer_len++;
+  }
+
+  // build up the header
+  data = asn_build_header(data, datalength, type, u_integer_len);
+  if (data == NULL)                return NULL;
+  if (*datalength < u_integer_len) return NULL;
+
+  // special case, add a null byte for len of 5
+  if (u_integer_len == 5) {
+    *data++ = 0;
+    for (x=1;x<u_integer_len;x++)
+      *data++= (unsigned char) (u_integer >> (8 * ((u_integer_len-1)-x)& 0xFF));
+  }
+  else
+  {
+    for (x=0;x<u_integer_len;x++)
+      *data++= (unsigned char) (u_integer >> (8 * ((u_integer_len-1)-x)& 0xFF));
+  }
+  *datalength -= u_integer_len;
+  return data;
+}
+
+
+/*
+ * asn_parse_string - pulls an octet string out of an ASN octet string type.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the beginning of the next object.
+ *
+ *  "string" is filled with the octet string.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_parse_string(unsigned char  *data,
+                                int *datalength,
+                                unsigned char *type,
+                                unsigned char *str,
+                                int *strlength)
+{
+  /*
+   * ASN.1 octet string ::= primstring | cmpdstring
+   * primstring ::= 0x04 asnlength byte {byte}*
+   * cmpdstring ::= 0x24 asnlength string {string}*
+   * ipaddress  ::= 0x40 4 byte byte byte byte
+   */
+  unsigned char *bufp = data;
+  unsigned long         asn_length;
+
+  *type = *bufp++;
+  if ((*type != 0x04) && (*type != 0x24) &&
+      (*type != 0x40) && (*type != 0x44) &&
+      (*type != 0x45)) {
+    ASNERROR("asn parse string: Wrong Type. Not a string");
+    return NULL;
+  }
+  bufp = asn_parse_length(bufp, &asn_length);
+  if (bufp == NULL)
+    return NULL;
+  if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+    ASNERROR("asn parse string: overflow of message");
+    return NULL;
+  }
+  if ((int)asn_length > *strlength) {
+    ASNERROR("asn parse string: String to parse is longer than buffer, aborting parsing.");
+    return NULL;
+  }
+
+  memcpy(str, bufp, asn_length);
+  *strlength = (int)asn_length;
+  *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+  return bufp + asn_length;
+}
+
+
+/*
+ * asn_build_string - Builds an ASN octet string object containing the input string.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the beginning of the next object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_build_string(unsigned char *data,
+                                int *datalength,
+                                const unsigned char type,
+                                const unsigned char *string,
+                                const int strlength)
+{
+  /*
+   * ASN.1 octet string ::= primstring | cmpdstring
+   * primstring ::= 0x04 asnlength byte {byte}*
+   * cmpdstring ::= 0x24 asnlength string {string}*
+   * This code will never send a compound string.
+   */
+  data = asn_build_header(data, datalength, type, strlength);
+  if (data == NULL)            return NULL;
+  if (*datalength < strlength) return NULL;
+
+  memcpy(data, string, strlength);
+  *datalength -= strlength;
+  return data + strlength;
+}
+
+
+/*
+ * asn_parse_header - interprets the ID and length of the current object.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   in this object following the id and length.
+ *
+ *  Returns a pointer to the first byte of the contents of this object.
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_parse_header(unsigned char *data,
+                               int *datalength,
+                                unsigned char *type)
+{
+  unsigned char *bufp = data;
+  register int header_len;
+  unsigned long asn_length;
+
+  /* this only works on data types < 30, i.e. no extension octets */
+  if (IS_EXTENSION_ID(*bufp)) {
+    ASNERROR("can't process ID >= 30");
+    return NULL;
+  }
+  *type = *bufp;
+  bufp = asn_parse_length(bufp + 1, &asn_length);
+  if (bufp == NULL)
+    return NULL;
+  header_len = SAFE_INT_CAST(bufp - data);
+  if ((unsigned long)(header_len + asn_length) > (unsigned long)*datalength) {
+    ASNERROR("asn length too long");
+    return NULL;
+  }
+  *datalength = (int)asn_length;
+  return bufp;
+}
+
+/*
+ * asn_build_header - builds an ASN header for an object with the ID and
+ * length specified.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   in this object following the id and length.
+ *
+ *  This only works on data types < 30, i.e. no extension octets.
+ *  The maximum length is 0xFFFF;
+ *
+ *  Returns a pointer to the first byte of the contents of this object.
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_build_header(unsigned char *data,
+                                int *datalength,
+                                unsigned char type,
+                                int length)
+{
+  if (*datalength < 1)
+    return NULL;
+  *data++ = type;
+  (*datalength)--;
+  return asn_build_length(data, datalength, length);
+}
+
+/*
+ * asn_build_sequence - builds an ASN header for a sequence with the ID and
+ * length specified.
+ *
+ *  This only works on data types < 30, i.e. no extension octets.
+ *
+ *  Returns a pointer to the first byte of the contents of this object.
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_build_sequence(unsigned char *data,
+                                  int *datalength,
+                                  unsigned char type,
+                                  int length)
+{
+  if (*datalength < 2) /* need at least two octets for a sequence */
+  {
+    ASNERROR("build_sequence");
+    return NULL;
+  }
+  *data++ = type;
+  (*datalength)--;
+
+  unsigned char *data_with_length = asn_build_length(data, datalength, length);
+  if (data_with_length == NULL)
+  {
+    (*datalength)++; /* correct datalength to emulate old behavior of build_sequence */
+    return NULL;
+  }
+     
+  return data_with_length;
+}
+
+/*
+ * asn_parse_length - interprets the length of the current object.
+ *  On exit, length contains the value of this length field.
+ *
+ *  Returns a pointer to the first byte after this length
+ *  field (aka: the start of the data field).
+ *  Returns NULL on any error.
+ */
+unsigned char * asn_parse_length(unsigned char *data,
+                                 unsigned long *length)
+{
+  unsigned char lengthbyte = *data;
+  *length = 0;
+  if (lengthbyte & ASN_LONG_LEN) {
+    lengthbyte &= ~ASN_LONG_LEN;       /* turn MSb off */
+    if (lengthbyte == 0) {
+      ASNERROR("We don't support indefinite lengths");
+      return NULL;
+    }
+    if (lengthbyte > sizeof(int)) {
+      ASNERROR("we can't support data lengths that long");
+      return NULL;
+    }
+    for (int i=0 ; i < lengthbyte ; i++)
+    {
+      *length = (*length << 8) + *(data + 1 + i);
+    }
+    // check for length greater than 2^31
+    if (*length > 0x80000000ul) {
+      ASNERROR("SNMP does not support data lengths > 2^31");
+      return NULL;
+    }
+    return data + lengthbyte + 1;
+  } else { /* short asnlength */
+    *length = (long)lengthbyte;
+    return data + 1;
+  }
+}
+
+unsigned char *asn_build_length(unsigned char *data,
+                                int *datalength,
+                                int length)
+{
+  unsigned char *start_data = data;
+
+  /* no indefinite lengths sent */
+  if (length < 0x80) {
+    if (*datalength < 1) {
+      ASNERROR("build_length");
+      return NULL;
+    }  
+    *data++ = (unsigned char)length;
+  }
+  else if (length <= 0xFF) {
+    if (*datalength < 2) {
+      ASNERROR("build_length");
+      return NULL;
+    }  
+    *data++ = (unsigned char)(0x01 | ASN_LONG_LEN);
+    *data++ = (unsigned char)length;
+  }
+  else if (length <= 0xFFFF) { /* 0xFF < length <= 0xFFFF */
+    if (*datalength < 3) {
+      ASNERROR("build_length");
+      return NULL;
+    }  
+    *data++ = (unsigned char)(0x02 | ASN_LONG_LEN);
+    *data++ = (unsigned char)((length >> 8) & 0xFF);
+    *data++ = (unsigned char)(length & 0xFF);
+  }
+  else if (length <= 0xFFFFFF) { /* 0xFF < length <= 0xFFFF */
+    if (*datalength < 4) {
+      ASNERROR("build_length");
+      return NULL;
+    }  
+    *data++ = (unsigned char)(0x03 | ASN_LONG_LEN);
+    *data++ = (unsigned char)((length >> 16) & 0xFF);
+    *data++ = (unsigned char)((length >> 8) & 0xFF);
+    *data++ = (unsigned char)(length & 0xFF);
+  }
+  else {
+    if (*datalength < 5) {
+      ASNERROR("build_length");
+      return NULL;
+    }  
+    *data++ = (unsigned char)(0x04 | ASN_LONG_LEN);
+    *data++ = (unsigned char)((length >> 24) & 0xFF);
+    *data++ = (unsigned char)((length >> 16) & 0xFF);
+    *data++ = (unsigned char)((length >> 8) & 0xFF);
+    *data++ = (unsigned char)(length & 0xFF);
+  }
+  *datalength -= SAFE_INT_CAST(data - start_data);
+  return data;
+}
+
+/*
+ * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the beginning of the next object.
+ *
+ *  "objid" is filled with the object identifier.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_parse_objid(unsigned char *data,
+                               int *datalength,
+                               unsigned char *type,
+                               oid *objid,
+                               int *objidlength)
+{
+  /*
+   * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
+   * subidentifier ::= {leadingbyte}* lastbyte
+   * leadingbyte ::= 1 7bitvalue
+   * lastbyte ::= 0 7bitvalue
+   */
+  unsigned char *bufp = data;
+  oid *oidp = objid + 1;
+  unsigned long subidentifier;
+  long length;
+  unsigned long asn_length;
+
+  *type = *bufp++;
+  if (*type != 0x06) {
+    ASNERROR("Wrong Type. Not an oid");
+    return NULL;
+  }
+  bufp = asn_parse_length(bufp, &asn_length);
+  if (bufp == NULL)
+    return NULL;
+  if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+    ASNERROR("overflow of message (objid)");
+    return NULL;
+  }
+  *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+
+  /* Handle invalid object identifier encodings of the form 06 00 robustly */
+  if (asn_length == 0)
+    objid[0] = objid[1] = 0;
+
+  length = asn_length;
+  (*objidlength)--;    /* account for expansion of first byte */
+  while (length > 0 && (*objidlength)-- > 0) {
+    subidentifier = 0;
+    do {       /* shift and add in low order 7 bits */
+      subidentifier = (subidentifier << 7) + (*(unsigned char *)bufp & ~ASN_BIT8);
+      length--;
+    } while (*(unsigned char *)bufp++ & ASN_BIT8); /* last byte has high bit clear */
+    if (subidentifier > (unsigned long)MAX_SUBID) {
+      ASNERROR("subidentifier too long");
+      return NULL;
+    }
+    *oidp++ = (oid)subidentifier;
+  }
+
+  /*
+   * The first two subidentifiers are encoded into the first component
+   * with the value (X * 40) + Y, where:
+   *   X is the value of the first subidentifier.
+   *  Y is the value of the second subidentifier.
+   */
+  subidentifier = (unsigned long)objid[1];
+  if (subidentifier == 0x2B) {
+    objid[0] = 1;
+    objid[1] = 3;
+  } else {
+    objid[1] = (unsigned char)(subidentifier % 40);
+    objid[0] = (unsigned char)((subidentifier - objid[1]) / 40);
+  }
+
+  *objidlength = (int)(oidp - objid);
+  return bufp;
+}
+
+/*
+ * asn_build_objid - Builds an ASN object identifier object containing the
+ * input string.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the beginning of the next object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_build_objid(unsigned char *data,
+                                int *datalength,
+                                unsigned char type,
+                                oid *objid,
+                                int objidlength)
+{
+  /*
+   * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
+   * subidentifier ::= {leadingbyte}* lastbyte
+   * leadingbyte ::= 1 7bitvalue
+   * lastbyte ::= 0 7bitvalue
+   */
+  // F.Fock correct buffer size must be 5*8bit*MAX_OID_LEN
+  unsigned char buf[MAX_OID_LEN*5];
+  unsigned char *bp = buf;
+  oid *op = objid;
+  int    asnlength;
+  unsigned long subid, mask, testmask;
+  int bits, testbits;
+
+  if (objidlength < 2) {
+    *bp++ = 0;
+    objidlength = 0;
+  } else {
+    *bp++ = (unsigned char) (op[1] + (op[0] * 40));
+    objidlength -= 2;
+    op += 2;
+  }
+
+  while(objidlength-- > 0) {
+    subid = *op++;
+    if (subid < 127) { /* off by one? */
+      *bp++ = (unsigned char)subid;
+    } else {
+      mask = 0x7F; /* handle subid == 0 case */
+      bits = 0;
+      /* testmask *MUST* !!!! be of an unsigned type */
+      for(testmask = 0x7F, testbits = 0; testmask != 0;
+         testmask <<= 7, testbits += 7) {
+       if (subid & testmask) { /* if any bits set */
+         mask = testmask;
+         bits = testbits;
+       }
+      }
+      /* mask can't be zero here */
+      for(;mask != 0x7F; mask >>= 7, bits -= 7) {
+       /* fix a mask that got truncated above */
+       if (mask == 0x1E00000)
+         mask = 0xFE00000;
+       *bp++ = (unsigned char)(((subid & mask) >> bits) | ASN_BIT8);
+      }
+      *bp++ = (unsigned char)(subid & mask);
+    }
+  }
+  asnlength = SAFE_INT_CAST(bp - buf);
+  data = asn_build_header(data, datalength, type, asnlength);
+  if (data == NULL)            return NULL;
+  if (*datalength < asnlength) return NULL;
+
+  memcpy((char *)data, (char *)buf,  asnlength);
+  *datalength -= asnlength;
+  return data + asnlength;
+}
+
+/*
+ * asn_parse_null - Interprets an ASN null type.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the beginning of the next object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_parse_null(unsigned char    *data,
+                              int *datalength,
+                              unsigned char *type)
+{
+  /*
+   * ASN.1 null ::= 0x05 0x00
+   */
+  unsigned char   *bufp = data;
+  unsigned long            asn_length;
+
+  *type = *bufp++;
+  if (*type != 0x05) {
+    ASNERROR("Wrong Type. Not a null");
+    return NULL;
+  }
+  bufp = asn_parse_length(bufp, &asn_length);
+  if (bufp == NULL)
+    return NULL;
+  if (asn_length != 0) {
+    ASNERROR("Malformed NULL");
+    return NULL;
+  }
+  *datalength -= SAFE_INT_CAST(bufp - data);
+  return bufp + asn_length;
+}
+
+
+/*
+ * asn_build_null - Builds an ASN null object.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the beginning of the next object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_build_null(unsigned char *data,
+                               int *datalength,
+                               unsigned char type)
+{
+  /*
+   * ASN.1 null ::= 0x05 0x00
+   */
+  return asn_build_header(data, datalength, type, 0);
+}
+
+/*
+ * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the beginning of the next object.
+ *
+ *  "string" is filled with the bit string.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_parse_bitstring(unsigned char *data,
+                                    int *datalength,
+                                    unsigned char *type,
+                                    unsigned char *string,
+                                    int *strlength)
+{
+  /*
+   * bitstring ::= 0x03 asnlength unused {byte}*
+   */
+  unsigned char *bufp = data;
+  unsigned long            asn_length;
+
+  *type = *bufp++;
+  if (*type != 0x03) {
+    ASNERROR("Wrong Type. Not a bitstring");
+    return NULL;
+  }
+  bufp = asn_parse_length(bufp, &asn_length);
+  if (bufp == NULL)
+    return NULL;
+  if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+    ASNERROR("overflow of message (bitstring)");
+    return NULL;
+  }
+  if ((int) asn_length > *strlength) {
+    ASNERROR("I don't support such long bitstrings");
+    return NULL;
+  }
+  if (asn_length < 1) {
+    ASNERROR("Invalid bitstring");
+    return NULL;
+  }
+  if (*bufp > 7) {
+    ASNERROR("Invalid bitstring");
+    return NULL;
+  }
+
+  memcpy((char *)string,(char *)bufp,  (int)asn_length);
+  *strlength = (int)asn_length;
+  *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+  return bufp + asn_length;
+}
+
+
+/*
+ * asn_build_bitstring - Builds an ASN bit string object containing the
+ * input string.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the beginning of the next object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_build_bitstring(unsigned char *data,
+                                    int *datalength,
+                                    unsigned char type,        
+                                    unsigned char *string,
+                                    int strlength)
+{
+  /*
+   * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
+   */
+  if (strlength < 1 || *string > 7) {
+    ASNERROR("Building invalid bitstring");
+    return NULL;
+  }
+  data = asn_build_header(data, datalength, type, strlength);
+  if (data == NULL)            return NULL;
+  if (*datalength < strlength) return NULL;
+
+  memcpy((char *)data,(char *)string, strlength);
+  *datalength -= strlength;
+  return data + strlength;
+}
+
+
+/*
+ * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
+ * type.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the end of this object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_parse_unsigned_int64(unsigned char *data,
+                                        int *datalength,
+                                        unsigned char *type,
+                                        struct counter64 *cp)
+{
+  /*
+   * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+   */
+  unsigned char *bufp = data;
+  unsigned long            asn_length;
+  unsigned long low = 0, high = 0;
+
+  *type = *bufp++;
+  if ((*type != 0x02) && (*type != 0x46)) {
+    ASNERROR("Wrong Type. Not an integer 64");
+    return NULL;
+  }
+  bufp = asn_parse_length(bufp, &asn_length);
+  if (bufp == NULL) {
+    ASNERROR("bad length");
+    return NULL;
+  }
+  if ((asn_length + (bufp - data)) > (unsigned long)(*datalength)) {
+    ASNERROR("overflow of message (uint64)");
+    return NULL;
+  }
+  if (((int)asn_length > 9) ||
+      (((int)asn_length == 9) && *bufp != 0x00)) {
+    ASNERROR("I don't support such large integers");
+    return NULL;
+  }
+  *datalength -= (int)asn_length + SAFE_INT_CAST(bufp - data);
+  if (*bufp & 0x80) {
+    low = (unsigned long) -1; // integer is negative
+    high = (unsigned long) -1;
+  }
+  while(asn_length--) {
+    high = (high << 8) | ((low & 0xFF000000) >> 24);
+    low = ((low << 8) | *bufp++) & 0xFFFFFFFF;
+  }
+  cp->low = low;
+  cp->high = high;
+
+  return bufp;
+}
+
+
+/*
+ * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
+ *  On entry, datalength is input as the number of valid bytes following
+ *   "data".  On exit, it is returned as the number of valid bytes
+ *   following the end of this object.
+ *
+ *  Returns a pointer to the first byte past the end
+ *   of this object (i.e. the start of the next object).
+ *  Returns NULL on any error.
+ */
+unsigned char *asn_build_unsigned_int64(unsigned char *data,
+                                        int *datalength,
+                                        unsigned char type,
+                                        struct counter64 *cp)
+{
+  /*
+   * ASN.1 integer ::= 0x02 asnlength byte {byte}*
+   */
+  unsigned long low = cp->low;
+  unsigned long high = cp->high;
+  unsigned long mask = 0xFF000000ul;
+  int add_null_byte = 0;
+  int intsize = 8;
+
+  if (((high & mask) >> 24) & 0x80) {
+    /* if MSB is set */
+    add_null_byte = 1;
+    intsize++;
+  }
+  else {
+    /*
+     * Truncate "unnecessary" bytes off of the most significant end of this 2's
+     * complement integer.
+     * There should be no sequence of 9 consecutive 1's or 0's at the most
+     * significant end of the integer.
+     */
+    unsigned long mask2 = 0xFF800000ul;
+    while ((((high & mask2) == 0) || ((high & mask2) == mask2)) &&
+          (intsize > 1)) {
+      intsize--;
+      high = (high << 8) | ((low & mask) >> 24);
+      low <<= 8;
+    }
+  }
+  data = asn_build_header(data, datalength, type, intsize);
+  if (data == NULL)          return NULL;
+  if (*datalength < intsize) return NULL;
+  *datalength -= intsize;
+  if (add_null_byte == 1) {
+    *data++ = 0;
+    intsize--;
+  }
+  while(intsize--) {
+    *data++ = (unsigned char)((high & mask) >> 24);
+    high = (high << 8) | ((low & mask) >> 24);
+    low <<= 8;
+  }
+  return data;
+}
+
+
+// create a pdu
+struct snmp_pdu *snmp_pdu_create(int command)
+{
+  struct snmp_pdu *pdu;
+
+  pdu = (struct snmp_pdu *)malloc(sizeof(struct snmp_pdu));
+  if (!pdu) return pdu;
+  memset((char *)pdu, 0,sizeof(struct snmp_pdu));
+  pdu->command = command;
+#ifdef _SNMPv3
+  pdu->msgid = 0;
+#endif
+  pdu->errstat = 0;
+  pdu->errindex = 0;
+  pdu->enterprise = NULL;
+  pdu->enterprise_length = 0;
+  pdu->variables = NULL;
+  return pdu;
+}
+
+// free content and clear pointers
+void clear_pdu(struct snmp_pdu *pdu, bool clear_all)
+{
+  struct variable_list *vp, *ovp;
+
+  vp = pdu->variables;
+  while (vp)
+  {
+    if (vp->name) free((char *)vp->name);  // free the oid part
+    if (vp->val.string) free((char *)vp->val.string);  // free deep data
+    ovp = vp;
+    vp = vp->next_variable;     // go to the next one
+    free((char *)ovp);     // free up vb itself
+  }
+  pdu->variables = NULL;
+
+  // if enterprise free it up
+  if (pdu->enterprise)
+    free((char *)pdu->enterprise);
+  pdu->enterprise = NULL;
+
+  if (!clear_all) return;
+
+  pdu->command = 0;
+  pdu->reqid   = 0;
+#ifdef _SNMPv3
+  pdu->msgid   = 0;
+  pdu->maxsize_scopedpdu = 0;
+#endif
+  pdu->errstat = 0;
+  pdu->errindex = 0;
+
+  pdu->enterprise_length = 0;
+  pdu->trap_type = 0;
+  pdu->specific_type = 0;
+  pdu->time = 0;
+}
+
+// free a pdu
+void snmp_free_pdu(struct snmp_pdu *pdu)
+{
+  clear_pdu(pdu); // clear and free content
+  free(pdu);   // free up pdu itself
+}
+
+
+// add a null var to a pdu
+void snmp_add_var(struct snmp_pdu *pdu,
+                 oid *name,
+                 int name_length,
+                 SmiVALUE *smival)
+{
+  struct variable_list *vars;
+
+  // if we don't have a vb list ,create one
+  if (pdu->variables == NULL)
+    pdu->variables = vars = (struct variable_list *)malloc(sizeof(struct variable_list));
+  else
+  {
+    // we have one, find the end
+    vars = pdu->variables;
+    while (vars->next_variable) vars = vars->next_variable;
+
+    // create a new one
+    vars->next_variable = (struct variable_list *)malloc(sizeof(struct variable_list));
+    // bump ptr
+    vars = vars->next_variable;
+  }
+
+  // add the oid with no data
+  vars->next_variable = NULL;
+
+  // hook in the Oid portion
+  vars->name = (oid *)malloc(name_length * sizeof(oid));
+
+  memcpy((char *)vars->name,(char *)name, name_length * sizeof(oid));
+  vars->name_length = name_length;
+
+  // hook in the SMI value
+  switch(smival->syntax)
+    {
+      // null , do nothing
+    case sNMP_SYNTAX_NULL:
+    case sNMP_SYNTAX_NOSUCHOBJECT:
+    case sNMP_SYNTAX_NOSUCHINSTANCE:
+    case sNMP_SYNTAX_ENDOFMIBVIEW:
+      {
+       vars->type = (unsigned char) smival->syntax;
+       vars->val.string = NULL;
+       vars->val_len = 0;
+      }
+      break;
+
+      // octects
+    case sNMP_SYNTAX_OCTETS:
+    case sNMP_SYNTAX_OPAQUE:
+    case sNMP_SYNTAX_IPADDR:
+      {
+       vars->type = (unsigned char) smival->syntax;
+       vars->val.string = (unsigned char *)malloc((unsigned)smival->value.string.len);
+       vars->val_len = (int) smival->value.string.len;
+       memcpy((unsigned char *) vars->val.string,
+               (unsigned char *) smival->value.string.ptr,
+               (unsigned) smival->value.string.len);
+      }
+      break;
+
+      // oid
+    case sNMP_SYNTAX_OID:
+      {
+       vars->type = (unsigned char) smival->syntax;
+        vars->val_len = (int) smival->value.oid.len * sizeof(oid);
+       vars->val.objid = (oid *)malloc((unsigned)vars->val_len);
+       memcpy((unsigned long *)vars->val.objid,
+              (unsigned long *)smival->value.oid.ptr,
+              (unsigned) vars->val_len);
+      }
+      break;
+
+
+       
+    case sNMP_SYNTAX_TIMETICKS:
+    case sNMP_SYNTAX_CNTR32:
+    case sNMP_SYNTAX_GAUGE32:
+      //    case sNMP_SYNTAX_UINT32:
+      {
+       long templong;
+       vars->type = (unsigned char) smival->syntax;
+       vars->val.integer = (long *)malloc(sizeof(long));
+       vars->val_len = sizeof(long);
+       templong = (long) smival->value.uNumber;
+       memcpy((long*) vars->val.integer,
+               (long*) &templong,
+               sizeof(long));
+      }
+      break;
+
+    case sNMP_SYNTAX_INT32:
+      {
+       long templong;
+       vars->type = (unsigned char) smival->syntax;
+       vars->val.integer = (long *)malloc(sizeof(long));
+       vars->val_len = sizeof(long);
+       templong = (long) smival->value.sNumber;
+       memcpy((long*) vars->val.integer,
+               (long*) &templong,
+               sizeof(long));
+      }
+      break;
+
+      // 64 bit counter
+    case sNMP_SYNTAX_CNTR64:
+      {
+       vars->type = (unsigned char) smival->syntax;
+       vars->val.counter64 = (struct counter64 *)malloc(sizeof(struct counter64));
+       vars->val_len = sizeof(struct counter64);
+       memcpy((struct counter64*) vars->val.counter64,
+               (SmiLPCNTR64) &(smival->value.hNumber),
+               sizeof(SmiCNTR64));
+      }
+      break;
+
+    } // end switch
+
+}
+
+// build the authentication, works for v1 or v2c
+static unsigned char *snmp_auth_build(unsigned char *data,
+                                     int *length,
+                                     const long int version,
+                                     const unsigned char *community,
+                                     const int community_len,
+                                     const int messagelen)
+{
+  // 5 is 3 octets for version and 2 for community header + len
+  // This assumes that community will not be longer than 0x7f chars.
+  data = asn_build_sequence(data, length, ASN_SEQ_CON,
+                           messagelen + community_len + 5);
+  if (data == NULL) { 
+    ASNERROR("buildheader");
+    return NULL;
+  }
+  data = asn_build_int(data, length, ASN_UNI_PRIM | ASN_INTEGER, &version);
+  if (data == NULL) {
+    ASNERROR("buildint");
+    return NULL;
+  }
+
+  data = asn_build_string(data, length, ASN_UNI_PRIM | ASN_OCTET_STR,
+                         community, community_len);
+  if (data == NULL) {
+    ASNERROR("buildstring");
+    return NULL;
+  }
+
+  return data;
+}
+
+
+// build a variable binding
+unsigned char * snmp_build_var_op(unsigned char *data,
+                                 oid * var_name,
+                                 int *var_name_len,
+                                 unsigned char var_val_type,
+                                 int var_val_len,
+                                 unsigned char *var_val,
+                                 int *listlength)
+{
+  int valueLen;
+  Buffer<unsigned char> buffer(MAX_SNMP_PACKET);
+  unsigned char *buffer_pos = buffer.get_ptr();
+  int bufferLen = MAX_SNMP_PACKET;
+
+  buffer_pos = asn_build_objid(buffer_pos, &bufferLen,
+                              ASN_UNI_PRIM | ASN_OBJECT_ID,
+                              var_name, *var_name_len);
+  if (buffer_pos == NULL) {
+    ASNERROR("build_var_op: build_objid failed");
+    return NULL;
+  }
+
+  // based on the type...
+  switch(var_val_type) {
+  case ASN_INTEGER:
+    if (var_val_len != sizeof(long))
+    {
+      ASNERROR("build_var_op: Illegal size of integer");
+      return NULL;
+    }
+    buffer_pos = asn_build_int(buffer_pos, &bufferLen,
+                               var_val_type, (long *)var_val);
+    break;
+
+  case SMI_GAUGE:
+  case SMI_COUNTER:
+  case SMI_TIMETICKS:
+  case SMI_UINTEGER:
+    if (var_val_len != sizeof(unsigned long))
+    {
+      ASNERROR("build_var_op: Illegal size of unsigned integer");
+      return NULL;
+    }
+    buffer_pos = asn_build_unsigned_int(buffer_pos, &bufferLen,
+                                        var_val_type, (unsigned long *)var_val);
+    break;
+
+  case SMI_COUNTER64:
+    if (var_val_len != sizeof(counter64))
+    {
+      ASNERROR("build_var_op: Illegal size of counter64");
+      return NULL;
+    }
+    buffer_pos = asn_build_unsigned_int64(buffer_pos, &bufferLen,
+                                          var_val_type,
+                                          (struct counter64 *)var_val);
+    break;
+
+  case ASN_OCTET_STR:
+  case SMI_IPADDRESS:
+  case SMI_OPAQUE:
+  case SMI_NSAP:
+    buffer_pos = asn_build_string(buffer_pos, &bufferLen, var_val_type,
+                                  var_val, var_val_len);
+    break;
+
+  case ASN_OBJECT_ID:
+    buffer_pos = asn_build_objid(buffer_pos, &bufferLen, var_val_type,
+                                 (oid *)var_val, var_val_len / sizeof(oid));
+    break;
+
+  case ASN_NULL:
+    buffer_pos = asn_build_null(buffer_pos, &bufferLen, var_val_type);
+    break;
+
+  case ASN_BIT_STR:
+    buffer_pos = asn_build_bitstring(buffer_pos, &bufferLen, var_val_type,
+                                     var_val, var_val_len);
+    break;
+
+  case SNMP_NOSUCHOBJECT:
+  case SNMP_NOSUCHINSTANCE:
+  case SNMP_ENDOFMIBVIEW:
+    buffer_pos = asn_build_null(buffer_pos, &bufferLen, var_val_type);
+    break;
+
+  default:
+    ASNERROR("build_var_op: wrong type");
+    return NULL;
+  }
+  if (buffer_pos == NULL) {
+    ASNERROR("build_var_op: value build failed");
+    return NULL;
+  }
+
+  valueLen = SAFE_INT_CAST(buffer_pos - buffer.get_ptr());
+
+  data = asn_build_sequence(data, listlength, ASN_SEQ_CON, valueLen);
+
+  if(data == NULL || *listlength < valueLen)
+  {
+    ASNERROR("build_var_op");
+    data = NULL;
+  }
+  else
+  {
+    memcpy(data, buffer.get_ptr(), valueLen);
+    data += valueLen;
+    (*listlength)-=valueLen;
+  }
+  return data;
+}
+
+
+unsigned char *build_vb(struct snmp_pdu *pdu,
+                       unsigned char *buf, int *buf_len)
+{
+  Buffer<unsigned char> tmp_buf(MAX_SNMP_PACKET);
+  unsigned char *cp = tmp_buf.get_ptr();
+  struct   variable_list *vp;
+  int vb_length;
+  int length = MAX_SNMP_PACKET;
+
+  // build varbinds into packet buffer
+  for(vp = pdu->variables; vp; vp = vp->next_variable)
+  {
+    cp = snmp_build_var_op(cp, vp->name, &vp->name_length,
+                           vp->type, vp->val_len,
+                           (unsigned char *)vp->val.string,
+                           &length);
+    if (cp == NULL) return 0;
+  }
+  vb_length = SAFE_INT_CAST(cp - tmp_buf.get_ptr());
+  *buf_len -= vb_length;
+  if (*buf_len <= 0) return 0;
+
+  // encode the length of encoded varbinds into buf
+  cp = asn_build_header(buf, buf_len, ASN_SEQ_CON, vb_length);
+  if (cp == NULL) return 0;
+
+  // copy varbinds from packet behind header in buf
+  memcpy(cp, tmp_buf.get_ptr(), vb_length);
+
+  return (cp + vb_length);
+}
+
+unsigned char *build_data_pdu(struct snmp_pdu *pdu,
+                             unsigned char *buf, int *buf_len,
+                             unsigned char *vb_buf, int vb_buf_len)
+{
+  Buffer<unsigned char> tmp_buf(MAX_SNMP_PACKET);
+  unsigned char *cp = tmp_buf.get_ptr();
+  int totallength;
+  int length = MAX_SNMP_PACKET;
+
+  // build data of pdu into tmp_buf
+  if (pdu->command != TRP_REQ_MSG)
+  {
+    // request id
+    cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &pdu->reqid);
+    if (cp == NULL) return 0;
+
+    // error status
+    cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &pdu->errstat);
+    if (cp == NULL) return 0;
+
+    // error index
+    cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &pdu->errindex);
+    if (cp == NULL) return 0;
+  }
+  else
+  { // this is a trap message
+    // enterprise
+    cp = asn_build_objid(cp, &length, ASN_UNI_PRIM | ASN_OBJECT_ID,
+                         (oid *)pdu->enterprise, pdu->enterprise_length);
+    if (cp == NULL) return 0;
+
+    // agent-addr ; must be IPADDRESS changed by Frank Fock
+    cp = asn_build_string(cp, &length, SMI_IPADDRESS,
+                         (unsigned char *)&pdu->agent_addr.sin_addr.s_addr,
+                         sizeof(pdu->agent_addr.sin_addr.s_addr));
+    if (cp == NULL) return 0;
+
+    long dummy = pdu->trap_type;
+    // generic trap
+    cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &dummy);
+    if (cp == NULL) return 0;
+
+    dummy = pdu->specific_type;
+    // specific trap
+    cp = asn_build_int(cp, &length, ASN_UNI_PRIM | ASN_INTEGER, &dummy);
+    if (cp == NULL) return 0;
+
+    // timestamp
+    cp = asn_build_unsigned_int(cp, &length, SMI_TIMETICKS, &pdu->time);
+    if (cp == NULL) return 0;
+  }
+
+  if (length < vb_buf_len) return 0;
+
+  // save relative position of varbinds
+  int vb_rel_pos = SAFE_INT_CAST(cp - tmp_buf.get_ptr());
+  totallength = SAFE_INT_CAST(cp - tmp_buf.get_ptr()) + vb_buf_len;
+
+  // build header for datapdu into buf
+  cp = asn_build_header(buf, buf_len,
+                       (unsigned char)pdu->command, totallength);
+  if (cp == NULL) return 0;
+  if (*buf_len < totallength) return 0;
+
+  // copy data behind header
+  memcpy(cp, tmp_buf.get_ptr(), totallength - vb_buf_len);
+  memcpy((char *)cp + vb_rel_pos, (char *)vb_buf, vb_buf_len);
+  *buf_len -= totallength;
+  return (cp + totallength);
+}
+
+// serialize the pdu
+int snmp_build(struct snmp_pdu *pdu,
+               unsigned char *packet,          int *out_length,
+               const long version,
+               const unsigned char* community, const int community_len)
+{
+  Buffer<unsigned char> buf(MAX_SNMP_PACKET);
+  unsigned char  *cp;
+  int       length;
+  int   totallength;
+
+  // encode vbs with header into packet
+  length = *out_length;
+  cp = build_vb(pdu, packet, &length);
+  if (cp == 0) return -1;
+  totallength = SAFE_INT_CAST(cp - packet);
+  if (totallength >= *out_length) return -1;
+
+  // encode datadpu into buf
+  length = MAX_SNMP_PACKET;
+  cp = build_data_pdu(pdu, buf.get_ptr(), &length,
+                     packet, totallength);
+  if (cp == 0) return -1;
+  totallength = SAFE_INT_CAST(cp - buf.get_ptr());
+  if (totallength >= *out_length) return -1;
+
+  // build SNMP header
+  length = *out_length;
+  cp = snmp_auth_build(packet, &length, version,
+                       community, community_len, totallength);
+  if (cp == NULL) return -1;
+  if ((*out_length - (cp - packet)) < totallength) return -1;
+
+  // copy data
+  memcpy(cp, buf.get_ptr(), totallength);
+  totallength += SAFE_INT_CAST(cp - packet);
+  *out_length = totallength;
+
+  return 0;
+}
+
+// parse the authentication header
+static unsigned char *snmp_auth_parse(unsigned char *data,
+                                     int *length,
+                                     unsigned char *community,
+                                     int *community_len,
+                                     long      *version)
+{
+  unsigned char type;
+
+  // get the type
+  data = asn_parse_header(data, length, &type);
+  if (data == NULL) {
+    ASNERROR("bad header");
+    return NULL;
+  }
+
+  if (type != ASN_SEQ_CON) {
+    ASNERROR("wrong auth header type");
+    return NULL;
+  }
+
+  // get the version
+  data = asn_parse_int(data, length, &type, version);
+  if (data == NULL) {
+    ASNERROR("bad parse of version");
+    return NULL;
+  }
+
+  // get the community name
+  data = asn_parse_string(data, length, &type, community, community_len);
+  if (data == NULL) {
+    ASNERROR("bad parse of community");
+    return NULL;
+  }
+
+  return (unsigned char *)data;
+}
+
+unsigned char *
+snmp_parse_var_op(unsigned char *data,  // IN - pointer to the start of object
+                  oid      *var_name,           // OUT - object id of variable
+                  int      *var_name_len,       // IN/OUT - length of variable name
+                  unsigned char  *var_val_type, // OUT - type of variable (int or octet string) (one byte)
+                  int      *var_val_len,        // OUT - length of variable
+                  unsigned char  **var_val,     // OUT - pointer to ASN1 encoded value of variable
+                  int      *listlength)         // IN/OUT - number of valid bytes left in var_op_list
+{
+  unsigned char var_op_type;
+  int  var_op_len = *listlength;
+  unsigned char *var_op_start = data;
+
+  data = asn_parse_header(data, &var_op_len, &var_op_type);
+  if (data == NULL) {
+    ASNERROR("Error snmp_parse_var_op: 1");
+    return NULL;
+  }
+  if (var_op_type != ASN_SEQ_CON)
+    return NULL;
+  data = asn_parse_objid(data, &var_op_len, &var_op_type, var_name, var_name_len);
+  if (data == NULL) {
+    ASNERROR("Error snmp_parse_var_op: 2");
+    return NULL;
+  }
+  if (var_op_type != (ASN_UNI_PRIM | ASN_OBJECT_ID))
+    return NULL;
+  *var_val = data;     /* save pointer to this object */
+  /* find out what type of object this is */
+  data = asn_parse_header(data, &var_op_len, var_val_type);
+  if (data == NULL) {
+    ASNERROR("Error snmp_parse_var_op: 3");
+    return NULL;
+  }
+  if (((unsigned long)var_op_len + (data - var_op_start)) > (unsigned long)(*listlength)) {
+    ASNERROR("Error snmp_parse_var_op: 4");
+    return NULL;
+  }
+  *var_val_len = (int)var_op_len;
+  data += var_op_len;
+  *listlength -= (int)(data - var_op_start);
+  return data;
+}
+
+
+int snmp_parse_vb(struct snmp_pdu *pdu, unsigned char *&data, int &data_len)
+{
+  unsigned char  *var_val;
+  int len;
+  struct variable_list *vp = 0;
+  oid      objid[ASN_MAX_NAME_LEN], *op;
+  unsigned char type;
+
+  // get the vb list from received data
+  data = asn_parse_header(data, &data_len, &type);
+  if (data == NULL)
+    return SNMP_CLASS_ASN1ERROR;
+  if (type != ASN_SEQ_CON)
+    return SNMP_CLASS_ASN1ERROR;
+  pdu->variables = NULL;
+  while(data_len > 0) {
+    if (pdu->variables == NULL) {
+      pdu->variables = vp = (struct variable_list *)malloc(sizeof(struct variable_list));
+    } else {
+      vp->next_variable = (struct variable_list *)malloc(sizeof(struct variable_list));
+      vp = vp->next_variable;
+    }
+    vp->next_variable = NULL;
+    vp->val.string = NULL;
+    vp->name = NULL;
+    vp->name_length = ASN_MAX_NAME_LEN;
+    data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type,
+                             &vp->val_len, &var_val, &data_len);
+    if (data == NULL)
+      return SNMP_CLASS_ASN1ERROR;
+    op = (oid *)malloc((unsigned)vp->name_length * sizeof(oid));
+
+    memcpy((char *)op, (char *)objid, vp->name_length * sizeof(oid));
+    vp->name = op;
+
+    len = MAX_SNMP_PACKET;
+    switch((short)vp->type) {
+    case ASN_INTEGER:
+      vp->val.integer = (long *)malloc(sizeof(long));
+      vp->val_len = sizeof(long);
+      asn_parse_int(var_val, &len, &vp->type, vp->val.integer);
+      break;
+
+    case SMI_COUNTER:
+    case SMI_GAUGE:
+    case SMI_TIMETICKS:
+    case SMI_UINTEGER:
+      vp->val.integer = (long *)malloc(sizeof(long));
+      vp->val_len = sizeof(long);
+      asn_parse_unsigned_int(var_val, &len, &vp->type, vp->val.integer);
+      break;
+
+    case SMI_COUNTER64:
+      vp->val.counter64 = (struct counter64 *)malloc(sizeof(struct counter64));
+      vp->val_len = sizeof(struct counter64);
+      asn_parse_unsigned_int64(var_val, &len, &vp->type,
+                              vp->val.counter64);
+      break;
+       
+    case ASN_OCTET_STR:
+    case SMI_IPADDRESS:
+    case SMI_OPAQUE:
+    case SMI_NSAP:
+      vp->val.string = (unsigned char *)malloc((unsigned)vp->val_len);
+      asn_parse_string(var_val, &len, &vp->type, vp->val.string, &vp->val_len);
+      break;
+
+    case ASN_OBJECT_ID:
+      vp->val_len = ASN_MAX_NAME_LEN;
+      asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
+      //vp->val_len *= sizeof(oid);
+      vp->val.objid = (oid *)malloc((unsigned)vp->val_len * sizeof(oid));
+
+      memcpy((char *)vp->val.objid,
+            (char *)objid,
+            vp->val_len * sizeof(oid));
+      break;
+
+    case SNMP_NOSUCHOBJECT:
+    case SNMP_NOSUCHINSTANCE:
+    case SNMP_ENDOFMIBVIEW:
+    case ASN_NULL:
+      break;
+
+    default:
+      ASNERROR("bad type returned ");
+      return SNMP_CLASS_ASN1ERROR;
+    }
+  }
+  return SNMP_CLASS_SUCCESS;
+}
+
+
+int snmp_parse_data_pdu(snmp_pdu *pdu, unsigned char *&data, int &length)
+{
+  oid      objid[ASN_MAX_NAME_LEN];
+  int      four = 4;
+  unsigned char  type;
+
+  data = asn_parse_header(data, &length, &type);
+  if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+  pdu->command = type;
+
+  if (pdu->command != TRP_REQ_MSG)
+  {
+    // get the rid error status and error index
+    data = asn_parse_int(data, &length, &type, &pdu->reqid);
+    if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+    data = asn_parse_int(data, &length, &type, &pdu->errstat);
+    if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+    data = asn_parse_int(data, &length, &type, &pdu->errindex);
+    if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+  }
+  else
+  {  // is a trap
+
+    // get the enterprise
+    pdu->enterprise_length = ASN_MAX_NAME_LEN;
+    data = asn_parse_objid(data, &length, &type,
+                          objid, &pdu->enterprise_length);
+    if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+    pdu->enterprise = (oid *)malloc(pdu->enterprise_length * sizeof(oid));
+
+    memcpy((char *)pdu->enterprise,(char *)objid,
+          pdu->enterprise_length * sizeof(oid));
+
+    // get source address
+    data = asn_parse_string(data, &length, &type,
+                           (unsigned char *)&pdu->agent_addr.sin_addr.s_addr,
+                           &four);
+    if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+    // get trap type
+    long dummy = 0;
+    data = asn_parse_int(data, &length, &type, &dummy);
+    pdu->trap_type = dummy;
+
+    if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+    // trap specific type
+    dummy = 0;
+    data = asn_parse_int(data, &length, &type, &dummy);
+    pdu->specific_type = dummy;
+    if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+
+    // timestamp
+    data = asn_parse_unsigned_int(data, &length, &type, &pdu->time);
+    if (data == NULL) return SNMP_CLASS_ASN1ERROR;
+  }
+  return SNMP_CLASS_SUCCESS;
+}
+
+
+// parse a pdu
+int snmp_parse(struct snmp_pdu *pdu,
+                unsigned char *data, int data_length,
+               unsigned char *community_name,
+               int &community_len,
+               snmp_version &spp_version)
+{
+  long    version = -1;
+
+  // authenticates message and returns length if valid
+  data = snmp_auth_parse(data, &data_length,
+                        community_name, &community_len,
+                        &version);
+  if (data == NULL)
+    return SNMP_CLASS_ASN1ERROR;
+
+  if(version != SNMP_VERSION_1 && version != SNMP_VERSION_2C) {
+    ASNERROR("Wrong version");
+    return SNMP_CLASS_BADVERSION;
+  }
+
+  spp_version = (snmp_version) version;
+
+  int res = snmp_parse_data_pdu(pdu, data, data_length);
+  if (res != SNMP_CLASS_SUCCESS)
+    return res;
+
+  return snmp_parse_vb(pdu, data, data_length);
+}
+
+
+#ifdef _SNMPv3
+// Parse the field HeaderData of a SNMPv3 message and return the values.
+unsigned char *asn1_parse_header_data(unsigned char *buf, int *buf_len,
+                                     long *msg_id, long *msg_max_size,
+                                     unsigned char *msg_flags,
+                                     long *msg_security_model)
+{
+  unsigned char *buf_ptr = buf;
+  int length = *buf_len;
+  unsigned char type;
+
+  buf = asn_parse_header(buf, &length, &type);
+  if (!buf)
+  {
+    debugprintf(0, "Parse error in header HeaderData");
+    return 0;
+  }
+
+  if (type != ASN_SEQ_CON) {
+    debugprintf(0, "wrong type in header of msgHeaderData");
+    return 0;
+  }
+
+  buf = asn_parse_int(buf, &length, &type, msg_id);
+  if (!buf) {
+    debugprintf(0, "Parse error: msg_id");
+    return 0;
+  }
+
+  buf = asn_parse_int(buf, &length, &type, msg_max_size);
+  if (!buf) {
+    debugprintf(0, "Parse error: msg_max_size");
+    return 0;
+  }
+
+  int dummy = 1;
+  buf = asn_parse_string(buf, &length, &type, msg_flags, &dummy);
+
+  if ((dummy !=1) || (!buf)) {
+    debugprintf(0, "Parse error: msg_flags");
+    return 0;
+  }
+
+  buf = asn_parse_int(buf, &length, &type, msg_security_model);
+  if (!buf) {
+    debugprintf(0, "Parse error: msg_security_model");
+    return 0;
+  }
+
+  if (length) {
+    debugprintf(0, "Parse error: wrong length in header of HeaderData");
+    return 0;
+  }
+
+  debugprintf(3, "Parsed HeaderData: globalDataLength(0x%x), msg_id(%ld), "
+            "msg_max_size(0x%lx), msg_flags(0x%x), msg_security_model(0x%lx)",
+             length, *msg_id, *msg_max_size, *msg_flags, *msg_security_model);
+
+  *buf_len -= SAFE_INT_CAST(buf - buf_ptr);
+  return buf;
+}
+
+// Encode the given values for the HeaderData into the buffer.
+unsigned char *asn1_build_header_data(unsigned char *outBuf, int *maxLength,
+                                      long msgID,
+                                      long maxMessageSize,
+                                      unsigned char msgFlags,
+                                      long securityModel)
+
+{
+  unsigned char buf[MAXLENGTH_GLOBALDATA];
+  unsigned char *bufPtr = (unsigned char*)&buf;
+  unsigned char *outBufPtr = outBuf;
+  int length = *maxLength;
+  int totalLength;
+
+#ifdef INVALID_MAXMSGSIZE
+  debugprintf(-10, "\nWARNING: Using constant MaxMessageSize!\n");
+  maxMessageSize = 65535;
+#endif
+
+  debugprintf(3, "Coding msgID(%ld), maxMessageSize(0x%lx), "
+             "msgFlags(0x%x), securityModel(0x%lx)",
+              msgID, maxMessageSize, msgFlags, securityModel);
+
+  bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER, &msgID);
+  if (bufPtr == NULL) {
+    debugprintf(0, "asn_build_header_data: Error coding msgID");
+    return NULL;
+  }
+  bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
+                         &maxMessageSize);
+  if (bufPtr == NULL) {
+    debugprintf(0, "asn_build_header_data: Error coding maxMessageSize");
+    return NULL;
+  }
+
+  bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
+                            &msgFlags, 1);
+  if (bufPtr == NULL) {
+    debugprintf(0, "asn_build_header_data: Error coding msgFlags");
+    return NULL;
+  }
+
+  bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
+                         &securityModel);
+  if (bufPtr == NULL) {
+    debugprintf(0, "asn_build_header_data: Error coding securityModel");
+    return NULL;
+  }
+
+  totalLength = SAFE_INT_CAST(bufPtr - (unsigned char*)&buf);
+
+  debugprintf(3, "Coding sequence (headerdata), length = 0x%x", totalLength);
+  outBufPtr = asn_build_sequence(outBufPtr, maxLength, ASN_SEQ_CON,
+                                 totalLength);
+
+  if (outBufPtr == NULL) {
+    debugprintf(0, "asn_build_header_data: Error coding seq headerdata");
+    return NULL;
+  }
+
+  if (*maxLength < totalLength) {
+    debugprintf(0, "asn_build_header_data: Length error");
+    return NULL;
+  }
+
+  memcpy(outBufPtr, (unsigned char*)&buf, totalLength);
+  outBufPtr += totalLength;
+  *maxLength -= totalLength;
+
+  debugprintf(21, "bufHeaderData:");
+  debughexprintf(21, outBuf, SAFE_INT_CAST(outBufPtr - outBuf));
+
+  return outBufPtr;
+}
+#endif
+
+// Parse the ScopedPDU and return the encoded values.
+unsigned char *asn1_parse_scoped_pdu(
+         unsigned char *scoped_pdu, int *scoped_pdu_len,
+         unsigned char *context_engine_id, int *context_engine_id_len,
+         unsigned char *context_name, int *context_name_len)
+{
+  unsigned char type;
+
+  scoped_pdu = asn_parse_header(scoped_pdu, scoped_pdu_len, &type);
+  if (!scoped_pdu) {
+    debugprintf(0, "Parse error: Wrong header in scoped_pdu.");
+    return 0;
+  }
+
+  if (type != ASN_SEQ_CON) {
+    debugprintf(0, "Parse error: Wrong header type in scoped_pdu.");
+    return 0;
+  }
+
+  scoped_pdu = asn_parse_string(scoped_pdu, scoped_pdu_len, &type,
+                                context_engine_id, context_engine_id_len);
+  if (!scoped_pdu) {
+    debugprintf(0, "Parse error: context_engine_id");
+    return 0;
+  }
+
+  scoped_pdu = asn_parse_string(scoped_pdu, scoped_pdu_len, &type,
+                                context_name, context_name_len);
+  if (!scoped_pdu) {
+    debugprintf(0, "mpParseScopedPDU: bad parse of context_name");
+    return 0;
+  }
+
+  debugprintf(3, "Parsed scoped_pdu: context_engine_id length(0x%x), "
+             "context_name length(0x%x)",
+             *context_engine_id_len, *context_name_len);
+
+  return scoped_pdu;
+}
+
+// Encode the given values for the scopedPDU into the buffer.
+unsigned char *asn1_build_scoped_pdu(
+                   unsigned char *outBuf, int *max_len,
+                   unsigned char *contextEngineID, long contextEngineIDLength,
+                   unsigned char *contextName, long contextNameLength,
+                   unsigned char *data, long dataLength)
+{
+  Buffer<unsigned char> buffer(MAX_SNMP_PACKET);
+  unsigned char *bufPtr = buffer.get_ptr();
+  unsigned char *outBufPtr = outBuf;
+
+  LOG_BEGIN(DEBUG_LOG | 10);
+  LOG("ASN1: coding (context engine id) (context name)");
+  LOG(OctetStr(contextEngineID, contextEngineIDLength).get_printable());
+  LOG(OctetStr(contextName, contextNameLength).get_printable());
+  LOG_END;
+
+  bufPtr = asn_build_string(bufPtr, max_len, ASN_UNI_PRIM | ASN_OCTET_STR,
+                            contextEngineID, contextEngineIDLength);
+  if (!bufPtr)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("ASN1: Error encoding contextEngineID");
+    LOG_END;
+
+    return 0;
+  }
+
+  bufPtr = asn_build_string(bufPtr, max_len, ASN_UNI_PRIM | ASN_OCTET_STR,
+                            contextName, contextNameLength);
+  if (!bufPtr)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("ASN1: Error encoding contextName");
+    LOG_END;
+
+    return 0;
+  }
+
+  long bufLength = SAFE_INT_CAST(bufPtr - buffer.get_ptr());
+
+  memcpy((char *)bufPtr, (char *)data, dataLength);
+  bufLength += dataLength;
+
+  LOG_BEGIN(DEBUG_LOG | 10);
+  LOG("ASN1: Encoding scoped PDU sequence (len)");
+  LOG(bufLength);
+  LOG_END;
+
+  outBufPtr = asn_build_sequence(outBufPtr, max_len, ASN_SEQ_CON, bufLength);
+  if (!outBufPtr)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("ASN1: Error encoding scopedPDU sequence");
+    LOG_END;
+
+    return 0;
+  }
+
+  memcpy(outBufPtr, buffer.get_ptr(), bufLength);
+  outBufPtr += bufLength;
+
+#ifdef __DEBUG
+  LOG_BEGIN(DEBUG_LOG | 15);
+  LOG("ASN1: Result of build_scoped_pdu (len) (data)");
+  LOG(outBufPtr - outBuf);
+  LOG(OctetStr(outBuf, outBufPtr - outBuf).get_printable_hex());
+  LOG_END;
+#endif
+
+  return outBufPtr;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/auth_priv.cpp b/3rdparty/snmp++/src/auth_priv.cpp
new file mode 100644 (file)
index 0000000..575de01
--- /dev/null
@@ -0,0 +1,2200 @@
+/*_############################################################################
+  _## 
+  _##  auth_priv.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+char auth_priv_version[]="@(#) SNMP++ $Id: auth_priv.cpp 1799 2010-08-14 20:11:45Z katz $";
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+// Only use DES, AES, SHA1 and MD5 from libtomcrypt if openssl is not used
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+#include <tomcrypt.h>
+#endif
+
+// Use DES, AES, SHA and MD5 from openssl
+#ifdef _USE_OPENSSL
+#include <openssl/des.h>
+#include <openssl/aes.h>
+#include <openssl/sha.h>
+#include <openssl/md5.h>
+#endif
+
+// Use internal functions for SHA and MD5 and libdes only
+// if not using libtomcrypt and openssl
+#if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+#include "snmp_pp/sha.h"
+#ifdef RSAEURO
+#include <rsaeuro.h>
+#else
+#include <des.h>
+#include "snmp_pp/md5.h"
+#endif
+#endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
+// IDEA can only be used with a valid license
+#ifdef _USE_IDEA
+#include "snmp_pp/idea.h"
+#endif
+
+#include "snmp_pp/auth_priv.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/snmperrs.h"
+#include "snmp_pp/address.h"
+#include "snmp_pp/log.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+/*-----------------[ defines for crypto libraries ]------------------*/
+
+#ifdef _USE_OPENSSL
+
+/* -- START: Defines for OpenSSL -- */
+typedef SHA_CTX               SHAHashStateType;
+#define SHA1_INIT(s)          SHA1_Init(s)
+#define SHA1_PROCESS(s, p, l) SHA1_Update(s, p, l)
+#define SHA1_DONE(s, k)       SHA1_Final(k, s)
+
+typedef MD5_CTX               MD5HashStateType;
+#define MD5_INIT(s)           MD5_Init(s)
+#define MD5_PROCESS(s, p, l)  MD5_Update(s, p, l)
+#define MD5_DONE(s, k)        MD5_Final(k, s)
+
+typedef des_key_schedule      DESCBCType;
+#define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
+                 if (des_key_sched((C_Block*)(k), s) < 0) \
+                 { \
+                  debugprintf(0, "Starting DES encryption failed."); \
+                  return SNMPv3_USM_ERROR; \
+                 }
+#define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
+                 if (des_key_sched((C_Block*)(k), s) < 0) \
+                 { \
+                  debugprintf(0, "Starting DES decryption failed."); \
+                  return SNMPv3_USM_ERROR; \
+                 }
+
+#define DES_CBC_ENCRYPT(pt, ct, s, iv, l) \
+                        des_ncbc_encrypt(pt, ct, l, \
+                                         s, (C_Block*)(iv), DES_ENCRYPT)
+#define DES_CBC_DECRYPT(ct, pt, s, iv, l) \
+                        des_ncbc_encrypt(ct, pt, l, \
+                                         s, (C_Block*)(iv), DES_DECRYPT)
+
+#define DES_EDE3_CBC_ENCRYPT(pt, ct, l, k1, k2, k3, iv) \
+               des_ede3_cbc_encrypt(pt, ct, l, \
+                                    k1, k2, k3, (C_Block*)(iv), DES_ENCRYPT)
+
+#define DES_EDE3_CBC_DECRYPT(ct, pt, l, k1, k2, k3, iv) \
+               des_ede3_cbc_encrypt(ct, pt, l, \
+                                    k1, k2, k3, (C_Block*)(iv), DES_DECRYPT)
+
+#define DES_MEMSET(s, c, l)   memset(&(s), c, l)
+
+/* -- END: Defines for OpenSSL -- */
+
+#else
+
+#ifdef _USE_LIBTOMCRYPT
+
+/* -- START: Defines for LibTomCrypt -- */
+typedef hash_state            SHAHashStateType;
+#define SHA1_INIT(s)          sha1_init(s)
+#define SHA1_PROCESS(s, p, l) sha1_process(s, p, l)
+#define SHA1_DONE(s, k)       sha1_done(s, k)
+
+typedef hash_state            MD5HashStateType;
+#define MD5_INIT(s)           md5_init(s)
+#define MD5_PROCESS(s, p, l)  md5_process(s, p, l)
+#define MD5_DONE(s, k)        md5_done(s, k)
+
+typedef symmetric_CBC         DESCBCType;
+#define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
+                 if (cbc_start(c, iv, k, kl, r, &(s)) != CRYPT_OK) \
+                 { \
+                  debugprintf(0, "Starting DES encryption failed."); \
+                  return SNMPv3_USM_ERROR; \
+                 }
+
+#define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
+                 if (cbc_start(c, iv, k, kl, r, &(s)) != CRYPT_OK) \
+                 { \
+                  debugprintf(0, "Starting DES decryption failed."); \
+                  return SNMPv3_USM_ERROR; \
+                 }
+
+#define DES_CBC_ENCRYPT(pt, ct, s, iv, l) \
+                 if (cbc_encrypt(pt, ct, l, &(s)) != CRYPT_OK) \
+                 { \
+                  debugprintf(0, "Error during DES encryption."); \
+                  return SNMPv3_USM_ERROR; \
+                 }
+#define DES_CBC_DECRYPT(ct, pt, s, iv, l) \
+                 if (cbc_decrypt(ct, pt, l, &(s)) != CRYPT_OK) \
+                 { \
+                  debugprintf(0, "Error during DES decryption."); \
+                  return SNMPv3_USM_ERROR; \
+                 }
+#define DES_MEMSET(s, c, l)   memset(&(s), c, l)
+/* -- END: Defines for LibTomCrypt -- */
+
+#else // _USE_LIBTOMCRYPT  --> libdes
+
+/* -- START: Defines for libdes -- */
+
+typedef SHA_CTX               SHAHashStateType;
+#define SHA1_INIT(s)          SHAInit(s)
+#define SHA1_PROCESS(s, p, l) SHAUpdate(s, p, l)
+#define SHA1_DONE(s, k)       SHAFinal(k, s)
+
+typedef MD5_CTX               MD5HashStateType;
+#define MD5_INIT(s)           MD5Init(s)
+#define MD5_PROCESS(s, p, l)  MD5Update(s, p, l)
+#define MD5_DONE(s, k)        MD5Final(k, s)
+
+#define DES_EDE3_CBC_ENCRYPT(pt, ct, l, k1, k2, k3, iv) \
+               des_ede3_cbc_encrypt((C_Block*)(pt), (C_Block*)(ct), l, \
+                                    k1, k2, k3, (C_Block*)(iv), DES_ENCRYPT)
+
+#define DES_EDE3_CBC_DECRYPT(ct, pt, l, k1, k2, k3, iv) \
+               des_ede3_cbc_encrypt((C_Block*)(ct), (C_Block*)(pt), l, \
+                                    k1, k2, k3, (C_Block*)(iv), DES_DECRYPT)
+
+#ifdef RSAEURO
+
+#undef  MD5_PROCESS
+#define MD5_PROCESS(s, p, l)  MD5Update(s, (unsigned char*)(p), l)
+
+typedef DES_CBC_CTX           DESCBCType;
+#define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
+                              DES_CBCInit(&(s), (unsigned char*)(k), iv, 1)
+#define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
+                              DES_CBCInit(&(s),(unsigned char*)(k), iv, 0)
+#define DES_CBC_ENCRYPT(pt, ct, s, iv, l) DES_CBCUpdate(&(s), pt, ct, l)
+#define DES_CBC_DECRYPT(ct, pt, s, iv, l) DES_CBCUpdate(&(s), (unsigned char*)(ct), pt, l)
+#define DES_MEMSET(s, c, l)   R_memset((POINTER)&(s), c, l)
+
+#else // RSAEURO
+
+typedef des_key_schedule      DESCBCType;
+#define DES_CBC_START_ENCRYPT(c, iv, k, kl, r, s) \
+                 if (des_key_sched((C_Block*)(k), s) < 0) \
+                 { \
+                  debugprintf(0, "Starting DES encryption failed."); \
+                  return SNMPv3_USM_ERROR; \
+                 }
+#define DES_CBC_START_DECRYPT(c, iv, k, kl, r, s) \
+                 if (des_key_sched((C_Block*)(k), s) < 0) \
+                 { \
+                  debugprintf(0, "Starting DES decryption failed."); \
+                  return SNMPv3_USM_ERROR; \
+                 }
+
+#define DES_CBC_ENCRYPT(pt, ct, s, iv, l) \
+                        des_ncbc_encrypt((C_Block*)(pt), (C_Block*)(ct), l, \
+                                         s, (C_Block*)(iv), DES_ENCRYPT)
+#define DES_CBC_DECRYPT(ct, pt, s, iv, l) \
+                        des_ncbc_encrypt((C_Block*)(ct), (C_Block*)(pt), l, \
+                                         s, (C_Block*)(iv), DES_DECRYPT)
+#define DES_MEMSET(s, c, l)   memset(&(s), c, l)
+
+/* -- END: Defines for libdes -- */
+
+#endif // RSAEURO
+
+#endif // _USE_LIBTOMCRYPT
+
+#endif // _USE_OPENSSL
+
+AuthPriv::AuthPriv(int &construct_state)
+{
+  auth = new AuthPtr[10];
+  priv = new PrivPtr[10];
+
+  if (auth)
+    auth_size = 10;
+  else
+  {
+    auth_size = 0;
+
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Error allocating array for authentication.");
+    LOG_END;
+  }
+
+  if (priv)
+    priv_size = 10;
+  else
+  {
+    priv_size = 0;
+
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Error allocating array for privacy.");
+    LOG_END;
+  }
+
+  for (int i = 0; i < auth_size; i++)
+    auth[i] = 0;
+
+  for (int j = 0; j < priv_size; j++)
+    priv[j] = 0;
+
+  /* Check size of salt, has to be 64 bits */
+  if (sizeof(salt) != 8)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: *BUG* sizeof(pp_uint64) is not 8 bytes. snmp++ has to be patched for this system.");
+    LOG_END;
+
+    construct_state = SNMPv3_USM_ERROR;
+    return;
+  }
+
+  /* Initialize salt. srand() has been already done in Snmp::init() */
+  unsigned int *rnd = (unsigned int*)(void *)&salt;
+  for (size_t i = 0; i < sizeof(salt); i += sizeof(unsigned int), rnd++)
+  {
+    *rnd = rand() << 1;
+    if (rand() < (RAND_MAX / 2))
+      *rnd += 1;
+  }
+
+  construct_state = SNMPv3_USM_OK;
+
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+  /* register needed hashes and ciphers in libtomcrypt */
+  if (register_cipher(&rijndael_desc) < 0)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Error registering Rijndael.");
+    LOG_END;
+
+    construct_state = SNMPv3_USM_ERROR;
+  }
+
+  if (register_cipher(&des_desc) < 0)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Error registering DES.");
+    LOG_END;
+
+    construct_state = SNMPv3_USM_ERROR;
+  }
+
+  if (register_cipher(&des3_desc) < 0)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Error registering 3DES.");
+    LOG_END;
+
+    construct_state = SNMPv3_USM_ERROR;
+  }
+
+  if (register_hash(&sha1_desc) < 0)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Error registering SHA1.");
+    LOG_END;
+
+    construct_state = SNMPv3_USM_ERROR;
+  }
+
+  if (register_hash(&md5_desc) < 0)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Error registering MD5.");
+    LOG_END;
+
+    construct_state = SNMPv3_USM_ERROR;
+  }
+#endif // defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+}
+
+AuthPriv::~AuthPriv()
+{
+  for (int i = 0; i < auth_size; i++)
+    if (auth[i])
+    {
+      delete auth[i];
+      auth[i] = 0;
+    }
+
+  for (int j = 0; j < priv_size; j++)
+    if (priv[j])
+    {
+      delete priv[j];
+      priv[j] = 0;
+    }
+
+  delete [] auth;
+  delete [] priv;
+}
+
+int AuthPriv::add_auth(Auth *new_auth)
+{
+  if (!new_auth)
+  {
+    return SNMP_CLASS_ERROR;
+  }
+
+  int id = new_auth->get_id();
+
+  if (id < 0)
+  {
+    return SNMP_CLASS_ERROR;
+  }
+
+  if (id >= auth_size)
+  {
+    AuthPtr *new_array = new AuthPtr[id + 5];
+    if (!new_array)
+    {
+      LOG_BEGIN(ERROR_LOG | 1);
+      LOG("AuthPriv: Could not allocate new auth array.");
+      LOG_END;
+
+      return SNMP_CLASS_ERROR;
+    }
+    for (int i=0 ; i<auth_size; i++)
+      new_array[i] = auth[i];
+
+    for (int j=auth_size ; j<id + 5; j++)
+      new_array[j] = 0;
+
+    AuthPtr *victim = auth;
+    auth = new_array;
+    delete [] victim;
+    auth_size = id + 5;
+  }
+
+  new_auth->set_salt(&salt);
+
+  if (auth[id])
+  {
+    LOG_BEGIN(WARNING_LOG | 4);
+    LOG("AuthPriv: deleting old auth object before adding new one (id)");
+    LOG(id);
+    LOG_END;
+
+    delete auth[id];
+  }
+
+  auth[id] = new_auth;
+
+  LOG_BEGIN(INFO_LOG | 6);
+  LOG("AuthPriv: Added auth protocol (id)");
+  LOG(id);
+  LOG_END;
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+int AuthPriv::del_auth(const int auth_id)
+{
+  if ((auth_id < 0) || (auth_id >= auth_size) || (auth[auth_id] == 0))
+  {
+    LOG_BEGIN(WARNING_LOG | 4);
+    LOG("AuthPriv: Request to delete non existing auth protocol (id)");
+    LOG(auth_id);
+    LOG_END;
+
+    return SNMP_CLASS_ERROR;
+  }
+
+  delete auth[auth_id];
+  auth[auth_id] = 0;
+
+  LOG_BEGIN(INFO_LOG | 6);
+  LOG("AuthPriv: Removed auth protocol (id)");
+  LOG(auth_id);
+  LOG_END;
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+
+int AuthPriv::add_priv(Priv *new_priv)
+{
+  if (!new_priv)
+  {
+    return SNMP_CLASS_ERROR;
+  }
+
+  int id = new_priv->get_id();
+
+  if (id < 0)
+  {
+    return SNMP_CLASS_ERROR;
+  }
+
+  if (id >= priv_size)
+  {
+    PrivPtr *new_array = new PrivPtr[id + 5];
+    if (!new_array)
+    {
+      LOG_BEGIN(ERROR_LOG | 1);
+      LOG("AuthPriv: Could not allocate new priv array.");
+      LOG_END;
+
+      return SNMP_CLASS_ERROR;
+    }
+    for (int i=0 ; i<priv_size; i++)
+      new_array[i] = priv[i];
+
+    for (int j=priv_size ; j<id + 5; j++)
+      new_array[j] = 0;
+
+    PrivPtr *victim = priv;
+    priv = new_array;
+    delete [] victim;
+    priv_size = id + 5;
+  }
+
+  new_priv->set_salt(&salt);
+
+  if (priv[id])
+  {
+    LOG_BEGIN(WARNING_LOG | 4);
+    LOG("AuthPriv: deleting old priv object before adding new one (id)");
+    LOG(id);
+    LOG_END;
+
+    delete priv[id];
+  }
+
+  priv[id] = new_priv;
+
+  LOG_BEGIN(INFO_LOG | 6);
+  LOG("AuthPriv: Added priv protocol (id)");
+  LOG(id);
+  LOG_END;
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+int AuthPriv::del_priv(const int priv_id)
+{
+  if ((priv_id < 0) || (priv_id >= priv_size) || (priv[priv_id] == 0))
+  {
+    LOG_BEGIN(WARNING_LOG | 4);
+    LOG("AuthPriv: Request to delete non existing priv protocol (id)");
+    LOG(priv_id);
+    LOG_END;
+
+    return SNMP_CLASS_ERROR;
+  }
+
+  delete priv[priv_id];
+  priv[priv_id] = 0;
+
+  LOG_BEGIN(INFO_LOG | 6);
+  LOG("AuthPriv: Removed priv protocol (id)");
+  LOG(priv_id);
+  LOG_END;
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+Auth *AuthPriv::get_auth(const int auth_prot)
+{
+  if ((auth_prot >= 0) && (auth_prot < auth_size))
+    return auth[auth_prot];
+  return 0;
+}
+
+Priv *AuthPriv::get_priv(const int priv_prot)
+{
+  if ((priv_prot >= 0) && (priv_prot < priv_size))
+    return priv[priv_prot];
+  return 0;
+}
+
+// Get the unique id for the given auth protocol.
+int AuthPriv::get_auth_id(const char *string_id) const
+{
+  for (int i = 0; i < auth_size; ++i)
+    if ((auth[i]) && (strcmp(string_id, auth[i]->get_id_string()) == 0))
+      return i;
+  return -1;
+}
+
+// Get the unique id for the given priv protocol.
+int AuthPriv::get_priv_id(const char *string_id) const
+{
+  for (int i = 0; i < priv_size; ++i)
+    if ((priv[i]) && (strcmp(string_id, priv[i]->get_id_string()) == 0))
+      return i;
+  return -1;
+}
+
+int AuthPriv::get_keychange_value(const int       auth_prot,
+                                  const OctetStr& old_key,
+                                  const OctetStr& new_key,
+                                  OctetStr&       keychange_value)
+{
+
+  // uses fixed key length determined from oldkey!
+  // works with SHA and MD5
+  // modifications needed to support variable length keys
+  // algorithm according to USM-document textual convention KeyChange
+
+  keychange_value.clear();
+  int key_len = old_key.len();
+
+  Auth *a = get_auth(auth_prot);
+
+  if (!a)
+    return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
+
+  // compute random value
+  OctetStr random = "";
+
+  for (int i=0; i<key_len; i++) {
+#ifdef _TEST
+    // do not use random values for testing
+    random += OctetStr((unsigned char*)"\0",1);
+#else
+    char tmprand = rand();
+    random += tmprand;
+#endif
+  }
+
+#ifdef __DEBUG
+  debugprintf(21, "Values for keyChange:");
+  debughexcprintf(21, "old_key", old_key.data(), old_key.len());
+  debughexcprintf(21, "new_key", new_key.data(), new_key.len());
+  debughexcprintf(21, "random value", random.data(), random.len());
+#endif
+
+  int iterations = (key_len - 1) / a->get_hash_len();
+  OctetStr tmp = old_key;
+  OctetStr delta;
+
+  for (int k = 0; k < iterations; k++)
+  {
+      unsigned char digest[SNMPv3_USM_MAX_KEY_LEN];
+      memset((char*)digest, 0, SNMPv3_USM_MAX_KEY_LEN);
+      tmp += random;
+      debughexcprintf(21, "loop tmp1", tmp.data(), tmp.len());
+      a->hash(tmp.data(), tmp.len(), digest);
+      tmp.set_data(digest, a->get_hash_len());
+      debughexcprintf(21, "loop tmp2", tmp.data(), tmp.len());
+      delta.set_len(delta.len() + a->get_hash_len());
+      for (int kk=0; kk < a->get_hash_len(); kk++)
+         delta[k * a->get_hash_len() + kk]
+             = tmp[kk] ^ new_key[k * a->get_hash_len() + kk];
+      debughexcprintf(21, "loop delta", delta.data(), delta.len());
+  }
+
+  unsigned char digest[SNMPv3_USM_MAX_KEY_LEN];
+  memset((char*)digest, 0, SNMPv3_USM_MAX_KEY_LEN);
+  tmp += random;
+  debughexcprintf(21, " tmp1", tmp.data(), tmp.len());
+  a->hash(tmp.data(), tmp.len(), digest);
+  tmp.set_data(digest, key_len - delta.len());
+  debughexcprintf(21, " tmp2", tmp.data(), tmp.len());
+  for (unsigned int j = 0; j < tmp.len(); j++)
+      tmp[j] = tmp[j] ^ new_key[iterations * a->get_hash_len() + j];
+  debughexcprintf(21, " tmp3", tmp.data(), tmp.len());
+
+  keychange_value = random;
+  keychange_value += delta;
+  keychange_value += tmp;
+
+#ifdef __DEBUG
+  debughexcprintf(21, "keychange_value",
+                  keychange_value.data(), keychange_value.len());
+#endif
+
+  return SNMPv3_USM_OK;
+}
+
+int AuthPriv::password_to_key_auth(const int            auth_prot,
+                                   const unsigned char *password,
+                                   const unsigned int   password_len,
+                                   const unsigned char *engine_id,
+                                   const unsigned int   engine_id_len,
+                                   unsigned char *key,
+                                   unsigned int  *key_len)
+{
+  if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
+  {
+    *key_len = 0;
+    return SNMPv3_USM_OK;
+  }
+
+  if (!password || (password_len == 0))
+  {
+    LOG_BEGIN(WARNING_LOG | 2);
+    LOG("AuthPriv: Password to key auth needs a non empty password");
+    LOG_END;
+
+    return SNMPv3_USM_ERROR;
+  }
+
+  Auth *a = get_auth(auth_prot);
+
+  if (!a)
+    return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
+
+  int res = a->password_to_key(password, password_len,
+                               engine_id, engine_id_len,
+                               key, key_len);
+
+  return res;
+}
+
+
+int AuthPriv::password_to_key_priv(const int            auth_prot,
+                                   const int            priv_prot,
+                                   const unsigned char *password,
+                                   const unsigned int   password_len,
+                                   const unsigned char *engine_id,
+                                   const unsigned int   engine_id_len,
+                                   unsigned char *key,
+                                   unsigned int  *key_len)
+{
+  /* check for priv protocol */
+  if (priv_prot == SNMP_PRIVPROTOCOL_NONE)
+  {
+    *key_len = 0;
+    return SNMPv3_USM_OK;
+  }
+
+  if (!password || (password_len == 0))
+  {
+    LOG_BEGIN(WARNING_LOG | 2);
+    LOG("AuthPriv: Password to key priv needs a non empty password");
+    LOG_END;
+
+    return SNMPv3_USM_ERROR;
+  }
+
+  Priv *p = get_priv(priv_prot);
+  Auth *a = get_auth(auth_prot);
+
+  if (!p)  return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
+  if (!a)  return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
+
+  unsigned int max_key_len = *key_len; /* save length of buffer! */
+  unsigned int min_key_len = p->get_min_key_len();
+
+  /* check if buffer for key is long enough */
+  if (min_key_len > max_key_len)
+    return SNMPv3_USM_ERROR; // TODO: better error code!
+
+  int res = password_to_key_auth(auth_prot,
+                                password, password_len,
+                                engine_id, engine_id_len,
+                                key, key_len);
+  if (res != SNMPv3_USM_OK)
+    return res;
+
+  /* We have a too short key: Call priv protocoll to extend it */
+  if (*key_len < min_key_len)
+  {
+    res = p->extend_short_key(password, password_len,
+                             engine_id, engine_id_len,
+                             key, key_len, max_key_len, a);
+    if (res != SNMPv3_USM_OK)
+      return res;
+  }
+
+  /* make sure key length is valid */
+  p->fix_key_len(*key_len);
+
+  return SNMPv3_USM_OK;
+}
+
+
+
+
+int AuthPriv::encrypt_msg(const int            priv_prot,
+                          const unsigned char *key,
+                          const unsigned int   key_len,
+                          const unsigned char *buffer,
+                          const unsigned int   buffer_len,
+                          unsigned char       *out_buffer,
+                          unsigned int        *out_buffer_len,
+                          unsigned char       *privacy_params,
+                          unsigned int        *privacy_params_len,
+                          const unsigned long  engine_boots,
+                          const unsigned long  engine_time)
+{
+  /* check for priv protocol */
+  Priv *p = get_priv(priv_prot);
+
+  if (!p)
+    return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
+
+  return p->encrypt(key, key_len, buffer, buffer_len,
+                    out_buffer, out_buffer_len,
+                    privacy_params, privacy_params_len,
+                    engine_boots, engine_time);
+}
+
+int AuthPriv::decrypt_msg(const int            priv_prot,
+                          const unsigned char *key,
+                          const unsigned int   key_len,
+                          const unsigned char *buffer,
+                          const unsigned int   buffer_len,
+                          unsigned char       *out_buffer,
+                          unsigned int        *out_buffer_len,
+                          const unsigned char *privacy_params,
+                          const unsigned int   privacy_params_len,
+                         const unsigned long  engine_boots,
+                         const unsigned long  engine_time)
+{
+  /* check for priv protocol */
+  Priv *p = get_priv(priv_prot);
+
+  if (!p)
+    return SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
+
+  return p->decrypt(key, key_len, buffer, buffer_len,
+                    out_buffer, out_buffer_len,
+                    privacy_params, privacy_params_len,
+                   engine_boots, engine_time);
+}
+
+
+int AuthPriv::add_default_modules()
+{
+  int ret = SNMP_CLASS_SUCCESS;
+
+  if (add_auth(new AuthSHA()) != SNMP_ERROR_SUCCESS)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Could not add default protocol AuthSHA.");
+    LOG_END;
+
+    ret = SNMP_CLASS_ERROR;
+  }
+
+  if (add_auth(new AuthMD5()) != SNMP_ERROR_SUCCESS)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Could not add default protocol AuthMD5.");
+    LOG_END;
+
+    ret = SNMP_CLASS_ERROR;
+  }
+
+  if (add_priv(new PrivDES()) != SNMP_ERROR_SUCCESS)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Could not add default protocol PrivDES.");
+    LOG_END;
+
+    ret = SNMP_CLASS_ERROR;
+  }
+
+#ifdef _USE_IDEA
+  if (add_priv(new PrivIDEA()) != SNMP_ERROR_SUCCESS)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Could not add default protocol PrivIDEA.");
+    LOG_END;
+
+    ret = SNMP_CLASS_ERROR;
+  }
+#endif
+
+#if defined(_USE_LIBTOMCRYPT) || defined(_USE_OPENSSL)
+  if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES128)) != SNMP_ERROR_SUCCESS)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Could not add default protocol PrivAES 128.");
+    LOG_END;
+
+    ret = SNMP_CLASS_ERROR;
+  }
+
+  if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES192)) != SNMP_ERROR_SUCCESS)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Could not add default protocol PrivAES 192.");
+    LOG_END;
+
+    ret = SNMP_CLASS_ERROR;
+  }
+
+  if (add_priv(new PrivAES(SNMP_PRIVPROTOCOL_AES256)) != SNMP_ERROR_SUCCESS)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Could not add default protocol PrivAES 256.");
+    LOG_END;
+
+    ret = SNMP_CLASS_ERROR;
+  }
+#endif
+
+#ifdef _USE_3DES_EDE
+  if (add_priv(new Priv3DES_EDE()) != SNMP_ERROR_SUCCESS)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("AuthPriv: Could not add default protocol Priv3DES_EDE.");
+    LOG_END;
+
+    ret = SNMP_CLASS_ERROR;
+  }
+#endif
+
+
+  if (ret == SNMP_CLASS_SUCCESS)
+  {
+    LOG_BEGIN(INFO_LOG | 3);
+    LOG("AuthPriv: Added default Auth and Priv protocols.");
+    LOG_END;
+  }
+
+  return ret;
+}
+
+int AuthPriv::get_auth_params_len(const int auth_prot)
+{
+  Auth *a = get_auth(auth_prot);
+
+  if (!a)
+    return 0;
+
+  return a->get_auth_params_len();
+}
+
+int AuthPriv::get_priv_params_len(const int priv_prot)
+{
+  Priv *p = get_priv(priv_prot);
+
+  if (!p)
+    return 0;
+
+  return p->get_priv_params_len();
+}
+
+int AuthPriv::auth_out_msg(const int            auth_prot,
+                           const unsigned char *key,
+                           unsigned char       *msg,
+                           const int            msg_len,
+                           unsigned char       *auth_par_ptr)
+{
+  if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
+    return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
+
+  Auth *a = get_auth(auth_prot);
+
+  if (!a)
+    return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
+
+  return a->auth_out_msg(key, msg, msg_len, auth_par_ptr);
+}
+
+int AuthPriv::auth_inc_msg(const int            auth_prot,
+                           const unsigned char *key,
+                           unsigned char       *msg,
+                           const int            msg_len,
+                           unsigned char       *auth_par_ptr,
+                           const int            auth_par_len)
+{
+  if (auth_prot == SNMP_AUTHPROTOCOL_NONE)
+    return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
+
+  Auth *a = get_auth(auth_prot);
+
+  if (!a)
+    return SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL;
+
+  /* @todo check if auth par is inside msg
+  if ((auth_par_ptr < msg) ||
+      (msg + msg_len < auth_par_ptr + auth_par_len))
+  {
+    LOG_BEGIN(WARNING_LOG | 1);
+    LOG("AuthPriv: Authentication data is not within message (msg start) (len) (auth start) (len)");
+    LOG(msg);
+    LOG(msg_len);
+    LOG(auth_par_ptr);
+    LOG(auth_par_len);
+    LOG_END;
+
+    return SNMPv3_USM_ERROR;
+  }
+  */
+
+  return a->auth_inc_msg(key, msg, msg_len, auth_par_ptr, auth_par_len);
+}
+
+/* ========================================================== */
+
+/* ----------------------- AuthSHA ---------------------------------------*/
+
+int AuthSHA::password_to_key(const unsigned char *password,
+                             const unsigned int   password_len,
+                             const unsigned char *engine_id,
+                             const unsigned int   engine_id_len,
+                             unsigned char *key,
+                             unsigned int *key_len)
+{
+  *key_len = 20; /* All SHA keys have 20 bytes length */
+
+#ifdef __DEBUG
+  debugprintf(5,"password_to_key SHA: password: (%s).",
+             OctetStr(password, password_len).get_printable());
+  debugprintf(5,"password_to_key SHA: engine_id: (%s).",
+             OctetStr(engine_id, engine_id_len).get_printable());
+#endif
+
+  SHAHashStateType sha_hash_state;
+  unsigned char *cp, password_buf[72];
+  unsigned long  password_index = 0;
+  unsigned long  count = 0, i;
+
+  SHA1_INIT(&sha_hash_state);   /* initialize SHA */
+
+  /**********************************************/
+  /* Use while loop until we've done 1 Megabyte */
+  /**********************************************/
+  while (count < 1048576) {
+    cp = password_buf;
+    for (i = 0; i < 64; i++) {
+      /*************************************************/
+      /* Take the next octet of the password, wrapping */
+      /* to the beginning of the password as necessary.*/
+      /*************************************************/
+      *cp++ = password[password_index++ % password_len];
+    }
+
+    SHA1_PROCESS(&sha_hash_state, password_buf, 64);
+    count += 64;
+  }
+
+  SHA1_DONE(&sha_hash_state, key);          /* tell SHA we're done */
+
+#ifdef __DEBUG
+  debughexcprintf(21, "key", key, *key_len);
+#endif
+
+  /*****************************************************/
+  /* Now localize the key with the engine_id and pass  */
+  /* through SHA to produce final key                  */
+  /* May want to ensure that engine_id_len <= 32,      */
+  /* otherwise need to use a buffer larger than 72     */
+  /*****************************************************/
+  memcpy(password_buf,                            key,       *key_len);
+  memcpy(password_buf + *key_len,                 engine_id, engine_id_len);
+  memcpy(password_buf + *key_len + engine_id_len, key,       *key_len);
+
+  SHA1_INIT(&sha_hash_state);
+  SHA1_PROCESS(&sha_hash_state, password_buf, (2 * *key_len) + engine_id_len);
+  SHA1_DONE(&sha_hash_state, key);
+
+#ifdef __DEBUG
+  debughexcprintf(21, "localized key", key, *key_len);
+#endif
+
+  return SNMPv3_USM_OK;
+}
+
+int AuthSHA::hash(const unsigned char *data,
+                  const unsigned int   data_len,
+                  unsigned char       *digest) const
+{
+  SHAHashStateType sha_hash_state;
+
+  SHA1_INIT(&sha_hash_state);
+  SHA1_PROCESS(&sha_hash_state, data, data_len);
+  SHA1_DONE(&sha_hash_state, digest);
+
+  return SNMPv3_USM_OK;
+}
+
+int AuthSHA::auth_out_msg(const unsigned char *key,
+                          unsigned char *msg,
+                          const int msg_len,
+                          unsigned char *auth_par_ptr)
+{
+  SHAHashStateType sha_hash_state;
+  int           key_len = 20; /* We use only 20 Byte Key! */
+  unsigned char digest[20];
+  unsigned char k_ipad[65];   /* inner padding - key XORd with ipad */
+  unsigned char k_opad[65];   /* outer padding - key XORd with opad */
+
+  memset((char*)(auth_par_ptr), 0, 12);
+
+#ifdef __DEBUG
+  debughexcprintf(21, "key", key, 16);
+#endif
+
+  /*
+   * the HMAC_SHA transform looks like:
+   *
+   * SHA(K XOR opad, SHA(K XOR ipad, msg))
+   *
+   * where K is an n byte key
+   * ipad is the byte 0x36 repeated 64 times
+   * opad is the byte 0x5c repeated 64 times
+   * and text is the data being protected
+   */
+
+  /* start out by storing ipads and opads in pads */
+  memset( (char*)k_ipad, 0x36, sizeof k_ipad);
+  memset( (char*)k_opad, 0x5c, sizeof k_opad);
+
+  /* XOR pads with key */
+  for (int i=0; i < key_len; ++i) {
+    k_ipad[i] ^= key[i];
+    k_opad[i] ^= key[i];
+  }
+
+  /* perform inner SHA */
+  SHA1_INIT(&sha_hash_state);           /* init sha_hash_state for 1st pass */
+  SHA1_PROCESS(&sha_hash_state, k_ipad, 64);   /* start with inner pad      */
+  SHA1_PROCESS(&sha_hash_state, msg, msg_len); /* then text of datagram     */
+  SHA1_DONE(&sha_hash_state, digest);          /* finish up 1st pass        */
+  /* perform outer SHA */
+  SHA1_INIT(&sha_hash_state);           /* init sha_hash_state for 2nd pass */
+  SHA1_PROCESS(&sha_hash_state, k_opad, 64);   /* start with outer pad      */
+  SHA1_PROCESS(&sha_hash_state, digest, 20);   /* then results of 1st hash  */
+  SHA1_DONE(&sha_hash_state, digest);          /* finish up 2nd pass        */
+
+#ifdef __DEBUG
+  debughexcprintf(21,"digest", digest, 160 / 8);
+#endif
+
+  memcpy(auth_par_ptr, digest, 12);
+
+  return SNMPv3_USM_OK;
+}
+
+
+int AuthSHA::auth_inc_msg(const unsigned char *key,
+                          unsigned char *msg,
+                          const int msg_len,
+                          unsigned char *auth_par_ptr,
+                          const int      auth_par_len)
+{
+  unsigned char receivedDigest[20];
+
+  if (auth_par_len != 12)
+  {
+    debugprintf(4, "SHA illegal digest length (%d), authentication FAILED.",
+               auth_par_len);
+    return SNMPv3_USM_AUTHENTICATION_FAILURE;
+  }
+
+#ifdef __DEBUG
+  debughexcprintf(21, "digest in Message", auth_par_ptr, 12);
+  debughexcprintf(21, "key", key, 20);
+#endif
+
+  /* Save received digest */
+  memcpy(receivedDigest, auth_par_ptr, 12);
+
+  if (SNMPv3_USM_OK != auth_out_msg(key, msg, msg_len, auth_par_ptr))
+  {
+    /* copy digest back into message and return error */
+    memcpy(auth_par_ptr, receivedDigest, 12);
+    debugprintf(4, "SHA authentication FAILED (1).");
+    return SNMPv3_USM_AUTHENTICATION_FAILURE;
+  }
+
+  /* compare digest to received digest */
+  for (int i=0; i < 12 ; ++i)
+  {
+    if (auth_par_ptr[i] != receivedDigest[i])
+    {
+      /* copy digest back into message and return error */
+      memcpy(auth_par_ptr, receivedDigest, 12);
+      debugprintf(4, "SHA authentication FAILED.");
+      return SNMPv3_USM_AUTHENTICATION_FAILURE;
+    }
+  }
+  debugprintf(4, "SHA authentication OK.");
+  return SNMPv3_USM_OK;
+}
+
+
+/* ----------------------- AuthMD5 ---------------------------------------*/
+
+int AuthMD5::password_to_key(const unsigned char *password,
+                             const unsigned int   password_len,
+                             const unsigned char *engine_id,
+                             const unsigned int   engine_id_len,
+                             unsigned char *key,
+                             unsigned int *key_len)
+{
+  *key_len = 16; /* All MD5 keys have 16 bytes length */
+
+#ifdef __DEBUG
+  debugprintf(5,"password: %s.",
+              OctetStr(password, password_len).get_printable());
+  debugprintf(5,"engineID: %s.",
+              OctetStr(engine_id, engine_id_len).get_printable());
+#endif
+
+  MD5HashStateType md5_hash_state;
+  unsigned char  *cp, password_buf[65];
+  unsigned long   password_index = 0;
+  unsigned long   count = 0, i;
+
+  MD5_INIT(&md5_hash_state);   /* initialize MD5 */
+
+  /**********************************************/
+  /* Use while loop until we've done 1 Megabyte */
+  /**********************************************/
+  while (count < 1048576) {
+    cp = password_buf;
+    for (i = 0; i < 64; i++) {
+      /*************************************************/
+      /* Take the next octet of the password, wrapping */
+      /* to the beginning of the password as necessary.*/
+      /*************************************************/
+      *cp++ = password[password_index++ % password_len];
+    }
+    MD5_PROCESS(&md5_hash_state, password_buf, 64);
+    count += 64;
+  }
+  MD5_DONE(&md5_hash_state, key);      /* tell MD5 we're done */
+
+#ifdef __DEBUG
+  debughexcprintf(21, "key", key, *key_len);
+#endif
+
+  /*****************************************************/
+  /* Now localize the key with the engine_id and pass  */
+  /* through MD5 to produce final key                  */
+  /* May want to ensure that engine_id_len <= 32,      */
+  /* otherwise need to use a buffer larger than 64     */
+  /*****************************************************/
+  memcpy(password_buf,                            key,       *key_len);
+  memcpy(password_buf + *key_len,                 engine_id, engine_id_len);
+  memcpy(password_buf + *key_len + engine_id_len, key,       *key_len);
+
+  MD5_INIT(&md5_hash_state);
+  MD5_PROCESS(&md5_hash_state, password_buf, (2 * *key_len) + engine_id_len);
+  MD5_DONE(&md5_hash_state, key);
+
+#ifdef __DEBUG
+  debughexcprintf(21, "localized key", key, *key_len);
+#endif
+
+  return SNMPv3_USM_OK;
+}
+
+int AuthMD5::hash(const unsigned char *data,
+                  const unsigned int   data_len,
+                  unsigned char       *digest) const
+{
+  MD5HashStateType md5_hash_state;
+
+  MD5_INIT(&md5_hash_state);
+  MD5_PROCESS(&md5_hash_state, data, data_len);
+  MD5_DONE(&md5_hash_state, digest);
+
+  return SNMPv3_USM_OK;
+}
+
+int AuthMD5::auth_out_msg(const unsigned char *key,
+                          unsigned char *msg,
+                          const int      msg_len,
+                          unsigned char *auth_par_ptr)
+{
+  MD5HashStateType md5_hash_state;
+  int           key_len = 16; /* We use only 16 Byte Key! */
+  unsigned char digest[16];
+  unsigned char k_ipad[65];   /* inner padding - key XORd with ipad */
+  unsigned char k_opad[65];   /* outer padding - key XORd with opad */
+
+  memset((char*)(auth_par_ptr), 0, 12);
+
+#ifdef __DEBUG
+  debughexcprintf(21, "key", key, 16);
+#endif
+
+  /*
+   * the HMAC_MD5 transform looks like:
+   *
+   * MD5(K XOR opad, MD5(K XOR ipad, msg))
+   *
+   * where K is an n byte key
+   * ipad is the byte 0x36 repeated 64 times
+   * opad is the byte 0x5c repeated 64 times
+   * and text is the data being protected
+   */
+
+  /* start out by storing key in pads */
+  memset( (char*)k_ipad, 0, sizeof k_ipad);
+  memset( (char*)k_opad, 0, sizeof k_opad);
+  memcpy( (char*)k_ipad, (char*)key, key_len);
+  memcpy( (char*)k_opad, (char*)key, key_len);
+
+  /* XOR key with ipad and opad values */
+  for (int i=0; i<64; i++) {
+    k_ipad[i] ^= 0x36;
+    k_opad[i] ^= 0x5c;
+  }
+
+  /* perform inner MD5 */
+  MD5_INIT(&md5_hash_state);            /* init md5_hash_state for 1st pass */
+  MD5_PROCESS(&md5_hash_state, k_ipad, 64);    /* start with inner pad      */
+  MD5_PROCESS(&md5_hash_state, msg, msg_len);  /* then text of datagram     */
+  MD5_DONE(&md5_hash_state, digest);           /* finish up 1st pass        */
+  /* perform outer MD5 */
+  MD5_INIT(&md5_hash_state);            /* init md5_hash_state for 2nd pass */
+  MD5_PROCESS(&md5_hash_state, k_opad, 64);    /* start with outer pad      */
+  MD5_PROCESS(&md5_hash_state, digest, 16);    /* then results of 1st hash  */
+  MD5_DONE(&md5_hash_state, digest);           /* finish up 2nd pass        */
+
+#ifdef __DEBUG
+  debughexcprintf(21, "digest", digest, 128 / 8);
+#endif
+
+  memcpy(auth_par_ptr, digest, 12);
+
+  return SNMPv3_USM_OK;
+}
+
+int AuthMD5::auth_inc_msg(const unsigned char *key,
+                          unsigned char *msg,
+                          const int msg_len,
+                          unsigned char *auth_par_ptr,
+                          const int      auth_par_len)
+{
+  unsigned char receivedDigest[16];
+
+  if (auth_par_len != 12)
+  {
+    debugprintf(4, "MD5 illegal digest length (%d), authentication FAILED.",
+               auth_par_len);
+    return SNMPv3_USM_AUTHENTICATION_FAILURE;
+  }
+
+#ifdef __DEBUG
+  debughexcprintf(21, "digest in Message", auth_par_ptr, 12);
+  debughexcprintf(21, "key", key, 16);
+#endif
+
+  memcpy(receivedDigest, auth_par_ptr, 12);
+
+  if (SNMPv3_USM_OK != auth_out_msg(key, msg, msg_len, auth_par_ptr))
+  {
+    /* copy digest back into message and return error */
+    memcpy(auth_par_ptr, receivedDigest, 12);
+    debugprintf(4, "MD5 authentication FAILED (1).");
+    return SNMPv3_USM_AUTHENTICATION_FAILURE;
+  }
+
+  /* compare digest to received digest */
+  for (int i=0; i < 12 ; ++i)
+  {
+    if (auth_par_ptr[i] != receivedDigest[i])
+    {
+      /* copy digest back into message and return error */
+      memcpy(auth_par_ptr, receivedDigest, 12);
+      debugprintf(4, "MD5 authentication FAILED.");
+      return SNMPv3_USM_AUTHENTICATION_FAILURE;
+    }
+  }
+  debugprintf(4, "MD5 authentication OK.");
+  return SNMPv3_USM_OK;
+}
+
+/* ========================= PRIV ================================*/
+
+/* ----------------------- PrivDES ---------------------------------------*/
+
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+PrivDES::PrivDES()
+{
+  cipher = find_cipher("des");
+}
+#endif
+
+int PrivDES::encrypt(const unsigned char *key,
+                     const unsigned int   /*key_len*/,
+                     const unsigned char *buffer,
+                     const unsigned int   buffer_len,
+                     unsigned char       *out_buffer,
+                     unsigned int        *out_buffer_len,
+                     unsigned char       *privacy_params,
+                     unsigned int        *privacy_params_len,
+                     const unsigned long  engine_boots,
+                     const unsigned long  /*engine_time*/)
+{
+  unsigned char initVect[8];
+  pp_uint64     my_salt = (*salt)++;
+
+#ifdef INVALID_ENCRYPTION
+  debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
+  my_salt = 0;
+#endif
+
+  /* check space in privacy_params buffer */
+  if (*privacy_params_len < 8)
+  {
+    debugprintf(4, "Buffer too small: should be 8, is (%i).",
+                *privacy_params_len);
+    return SNMPv3_USM_ENCRYPTION_ERROR;
+  }
+  /* Length is always 8 */
+  *privacy_params_len = 8;
+
+  // last 8 bytes of key are used as base for initialization vector
+  memcpy((char*)initVect, key+8, 8);
+
+  // put salt in privacy_params
+  for (int j=0; j<4; j++)
+  {
+    privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
+    privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
+  }
+
+  // xor initVect with salt
+  for (int i=0; i<8; i++)
+    initVect[i] ^= privacy_params[i];
+
+#ifdef __DEBUG
+  debughexcprintf(21, "apDESEncryptData: Data to encrypt",
+                 buffer, buffer_len);
+  debughexcprintf(21, "apDESEncryptData: used key (only 8 bytes used)",
+                  key, 16);
+  debughexcprintf(21, "apDESEncryptData: used iv",
+                  initVect, 8);
+#endif
+
+  DESCBCType symcbc;
+  DES_CBC_START_ENCRYPT(cipher, initVect, key, 8, 16, symcbc);
+
+  for(unsigned int k = 0; k <= buffer_len - 8; k += 8) {
+    DES_CBC_ENCRYPT(buffer + k, out_buffer + k, symcbc, initVect, 8);
+  }
+
+  /* last part of buffer */
+  if (buffer_len % 8)
+  {
+    unsigned char tmp_buf[8];
+    unsigned char *tmp_buf_ptr = tmp_buf;
+    int start = buffer_len - (buffer_len % 8);
+    memset(tmp_buf, 0, 8);
+    for (unsigned int l = start; l < buffer_len; l++)
+      *tmp_buf_ptr++ = buffer[l];
+    DES_CBC_ENCRYPT(tmp_buf, out_buffer + start, symcbc, initVect, 8);
+    *out_buffer_len = buffer_len + 8 - (buffer_len % 8);
+  }
+  else
+    *out_buffer_len = buffer_len;
+
+  /* Clear context buffer (paranoia!)*/
+  DES_MEMSET(symcbc, 0, sizeof(symcbc));
+
+#ifdef __DEBUG
+  debughexcprintf(21, "apDESEncryptData: created privacy_params",
+                  privacy_params, 8);
+  debughexcprintf(21, "apDESEncryptData: encrypted Data",
+                  out_buffer, *out_buffer_len);
+#endif
+
+  return SNMPv3_USM_OK;
+}
+
+
+
+int PrivDES::decrypt(const unsigned char *key,
+                     const unsigned int   /*key_len*/,
+                     const unsigned char *buffer,
+                     const unsigned int   buffer_len,
+                     unsigned char *outBuffer,
+                     unsigned int  *outBuffer_len,
+                     const unsigned char *privacy_params,
+                     const unsigned int   privacy_params_len,
+                    const unsigned long  /*engine_boots*/,
+                    const unsigned long  /*engine_time*/)
+{
+  unsigned char initVect[8];
+
+  /* Privacy params length has to be 8  && Length has to be a multiple of 8 */
+  if (( buffer_len % 8 ) || (privacy_params_len != 8))
+    return SNMPv3_USM_DECRYPTION_ERROR;
+
+  for (int i=0; i<8; i++)
+    initVect[i] = privacy_params[i] ^ key[i+8];
+
+  memset((char*)outBuffer, 0, *outBuffer_len);
+
+#ifdef __DEBUG
+  debughexcprintf(21, "apDESDecryptData: Data to decrypt",
+                  buffer, buffer_len);
+  debughexcprintf(21, "apDESDecryptData: used key (only 8 bytes used)",
+                  key, 16);
+  debughexcprintf(21, "apDESDecryptData: used privacy_params",
+                  privacy_params, 8);
+  debughexcprintf(21, "apDESDecryptData: used iv",
+                  initVect, 8);
+#endif
+
+  DESCBCType symcbc;
+  DES_CBC_START_DECRYPT(cipher, initVect, key, 8, 16, symcbc);
+  for(unsigned int j=0; j<buffer_len; j+=8 ) {
+    DES_CBC_DECRYPT(buffer + j, outBuffer + j, symcbc, initVect, 8);
+  }
+  /* Clear context (paranoia!) */
+  DES_MEMSET(symcbc, 0, sizeof(symcbc));
+
+  *outBuffer_len = buffer_len;
+
+#ifdef __DEBUG
+  debughexcprintf(21, "apDESDecryptData: decrypted Data",
+                  outBuffer, *outBuffer_len);
+#endif
+
+  return SNMPv3_USM_OK;
+}
+
+
+/* ----------------------- PrivIDEA --------------------------------------*/
+
+#ifdef _USE_IDEA
+
+int PrivIDEA::encrypt(const unsigned char *key,
+                      const unsigned int   /*key_len*/,
+                      const unsigned char *buffer,
+                      const unsigned int   buffer_len,
+                      unsigned char       *out_buffer,
+                      unsigned int        *out_buffer_len,
+                      unsigned char       *privacy_params,
+                      unsigned int        *privacy_params_len,
+                      const unsigned long  engine_boots,
+                      const unsigned long  /*engine_time*/)
+{
+  IDEAContext CFB_Context;
+  pp_uint64 my_salt = (*salt)++;
+
+#ifdef INVALID_ENCRYPTION
+  debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
+  my_salt = 0;
+#endif
+
+  /* check space in privacy_params buffer */
+  if (*privacy_params_len < 8)
+  {
+    debugprintf(4, "Buffer too small: should be 8, is (%i).", *privacy_params_len);
+    return SNMPv3_USM_ENCRYPTION_ERROR;
+  }
+  /* Length is always 8 */
+  *privacy_params_len = 8;
+
+  // last 8 bytes of key are used as base for initialization vector
+  unsigned char iv[8];
+
+  memcpy((char*)iv, key+8, 8);
+
+  // put salt in privacy_params
+  for (int j=0; j<4; j++)
+  {
+    privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
+    privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
+  }
+  // xor iv with privacy_params
+  for (int i=0; i<8; i++)
+    iv[i] ^= privacy_params[i];
+
+  idea_set_key(&CFB_Context, key);
+
+  idea_cfb_encrypt(&CFB_Context, iv, out_buffer,
+                   buffer, buffer_len);
+
+  /* Clear context (paranoia!) */
+  idea_destroy_context(&CFB_Context);
+
+  *out_buffer_len = buffer_len;
+
+#ifdef __DEBUG
+  debughexcprintf(21, "apIDEAEncryptData: Data to encrypt",
+                  buffer, buffer_len);
+  debughexcprintf(21, "apIDEAEncryptData: key",
+                  key, 16);
+  debughexcprintf(21, "apIDEAEncryptData: privacy_params",
+                  privacy_params, 8);
+  debughexcprintf(21, "apIDEAEncryptData: encrypted Data",
+                  out_buffer, *out_buffer_len);
+#endif
+
+  return SNMPv3_USM_OK;
+}
+
+int PrivIDEA::decrypt(const unsigned char *key,
+                      const unsigned int   /*key_len*/,
+                      const unsigned char *buffer,
+                      const unsigned int   buffer_len,
+                      unsigned char *out_buffer,
+                      unsigned int  *out_buffer_len,
+                      const unsigned char *privacy_params,
+                      const unsigned int   privacy_params_len,
+                     const unsigned long  /*engine_boots*/,
+                     const unsigned long  /*engine_time*/)
+{
+  unsigned char iv[8];
+  IDEAContext CFB_Context;
+
+  /* privacy params length has to be 8 */
+  if (privacy_params_len != 8)
+    return SNMPv3_USM_DECRYPTION_ERROR;
+
+  idea_set_key(&CFB_Context, key);
+
+  memset((char*)out_buffer, 0, *out_buffer_len);
+
+  /* Initialize iv with last 8 bytes of key and xor with privacy_params */
+  memcpy((char*)iv, key+8, 8);
+  for (int i=0; i<8; i++)
+    iv[i] ^= privacy_params[i];
+
+  idea_cfb_decrypt(&CFB_Context, iv, out_buffer,
+                   buffer, buffer_len);
+
+  /* Clear context (paranoia!) */
+  idea_destroy_context(&CFB_Context);
+  memset((char*)iv, 0, 8);
+
+  *out_buffer_len = buffer_len;
+
+#ifdef __DEBUG
+  debughexcprintf(21, "apIDEADecryptData: Data to decrypt",
+                  buffer, buffer_len);
+  debughexcprintf(21, "apIDEADecryptData: key", key, 16);
+  debughexcprintf(21, "apIDEAEncryptData: privacy_params", privacy_params, 8);
+  debughexcprintf(21, "apIDEADecryptData: decrypted Data",
+                  out_buffer, *out_buffer_len);
+#endif
+
+  return SNMPv3_USM_OK;
+}
+
+#endif // _USE_IDEA
+
+#if defined(_USE_LIBTOMCRYPT) || defined(_USE_OPENSSL)
+
+PrivAES::PrivAES(const int aes_type_)
+  : aes_type(aes_type_)
+{
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+  cipher = find_cipher("rijndael");
+#endif
+
+  switch (aes_type)
+  {
+    case SNMP_PRIVPROTOCOL_AES128:
+      key_bytes = 16;
+      rounds = 10;
+      break;
+    case SNMP_PRIVPROTOCOL_AES192:
+      key_bytes = 24;
+      rounds = 12;
+      break;
+    case SNMP_PRIVPROTOCOL_AES256:
+      key_bytes = 32;
+      rounds = 14;
+      break;
+    default:
+      debugprintf(0, "Wrong AES type: %i.", aes_type);
+      key_bytes = 0;
+      rounds = 0;
+      aes_type = -1; // will cause an error in AuthPriv::add_priv()
+  }
+
+  unsigned int testswap = htonl(0x01020304);
+  if (testswap == 0x01020304)
+    need_byteswap = FALSE;
+  else
+    need_byteswap = TRUE;
+}
+
+const char *PrivAES::get_id_string() const
+{
+  switch (aes_type)
+  {
+    case SNMP_PRIVPROTOCOL_AES128: return "AES128";  break;
+    case SNMP_PRIVPROTOCOL_AES192: return "AES192";  break;
+    case SNMP_PRIVPROTOCOL_AES256: return "AES256";  break;
+    default:                       return "error";   break;
+  }
+};
+
+int PrivAES::encrypt(const unsigned char *key,
+                    const unsigned int   key_len,
+                    const unsigned char *buffer,
+                    const unsigned int   buffer_len,
+                    unsigned char       *out_buffer,
+                    unsigned int        *out_buffer_len,
+                    unsigned char       *privacy_params,
+                    unsigned int        *privacy_params_len,
+                    const unsigned long  engine_boots,
+                    const unsigned long  engine_time)
+{
+  unsigned char initVect[16];
+  pp_uint64 my_salt = (*salt)++;
+
+#ifdef INVALID_ENCRYPTION
+  debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
+  my_salt = 0;
+#endif
+
+  /* check space in privacy_params buffer */
+  if (*privacy_params_len < 8)
+  {
+    debugprintf(4, "Buffer too small: should be 8, is (%i).",
+                *privacy_params_len);
+    return SNMPv3_USM_ENCRYPTION_ERROR;
+  }
+  /* Length is always 8 */
+  *privacy_params_len = 8;
+
+  /* Set IV as engine_boots + engine_time + salt */
+  unsigned int *tmpi = (unsigned int *)initVect;
+  *tmpi++ = htonl(engine_boots);
+  *tmpi++ = htonl(engine_time);
+  if (need_byteswap)
+  {
+    *tmpi++ = htonl(my_salt & 0xFFFFFFFF);
+    *tmpi   = htonl((my_salt >> 32) & 0xFFFFFFFF);
+  }
+  else
+    memcpy(tmpi, &my_salt, 8);
+
+  /* put byteswapped salt in privacy_params */
+  memcpy(privacy_params, initVect + 8, 8);
+  debughexcprintf(21, "aes initVect:", initVect, 16);
+
+#ifdef _USE_OPENSSL
+  AES_KEY symcfb;
+  int dummy = 0;
+
+  if (AES_set_encrypt_key(key, key_len * 8, &symcfb) < 0)
+  {
+    
+    debugprintf(1, "AES_set_encrypt_key(%p, %d, %p) failed.",
+               key, key_len * 8, &symcfb);
+    return SNMPv3_USM_ERROR;
+  }
+
+  AES_cfb128_encrypt(buffer, out_buffer, buffer_len,
+                    &symcfb, initVect, &dummy, AES_ENCRYPT);
+#else
+  symmetric_CFB symcfb;
+
+  cfb_start(cipher, initVect, key, key_bytes, rounds, &symcfb);
+  cfb_encrypt((unsigned char*)buffer, out_buffer, buffer_len, &symcfb);
+#endif
+
+  /* Clear context and plaintext buffer (paranoia!)*/
+  memset(&symcfb, 0, sizeof(symcfb));
+
+  *out_buffer_len = buffer_len;
+
+#ifdef __DEBUG
+  debughexcprintf(21, "aes EncryptData: Data to encrypt", buffer, buffer_len);
+  debughexcprintf(21, "aes EncryptData: used key", key, key_len);
+  debughexcprintf(21, "aes EncryptData: created privacy_params",
+                  privacy_params, 8);
+  debughexcprintf(21, "aes EncryptData: encrypted Data",
+                  out_buffer, *out_buffer_len);
+#endif
+
+  return SNMPv3_USM_OK;
+}
+
+int PrivAES::decrypt(const unsigned char *key,
+                    const unsigned int   key_len,
+                    const unsigned char *buffer,
+                    const unsigned int   buffer_len,
+                    unsigned char       *out_buffer,
+                    unsigned int        *out_buffer_len,
+                    const unsigned char *privacy_params,
+                    const unsigned int   privacy_params_len,
+                    const unsigned long  engine_boots,
+                    const unsigned long  engine_time)
+{
+  unsigned char initVect[16];
+
+  /* Privacy params length has to be 8 */
+  if (privacy_params_len != 8)
+    return SNMPv3_USM_DECRYPTION_ERROR;
+
+  /* build IV */
+  unsigned int *tmp;
+  tmp = (unsigned int *)initVect;
+  *tmp++ = htonl(engine_boots);
+  *tmp = htonl(engine_time);
+  memcpy(initVect + 8, privacy_params, 8);
+  debughexcprintf(21, "aes initVect:", initVect, 16);
+
+#ifdef _USE_OPENSSL
+  int dummy = 0;
+  AES_KEY symcfb;
+
+  AES_set_encrypt_key(key, key_len * 8, &symcfb);
+  AES_cfb128_encrypt(buffer, out_buffer, buffer_len,
+                    &symcfb, initVect, &dummy, AES_DECRYPT);
+#else
+  symmetric_CFB symcfb;
+
+  cfb_start(cipher, initVect, key, key_bytes, rounds, &symcfb);
+  cfb_decrypt((unsigned char*)buffer, out_buffer, buffer_len, &symcfb);
+#endif
+
+  /* Clear context and plaintext buffer (paranoia!)*/
+  memset(&symcfb, 0, sizeof(symcfb));
+
+  *out_buffer_len = buffer_len;
+
+#ifdef __DEBUG
+  debughexcprintf(21, "aes DecryptData: Data to decrypt", buffer, buffer_len);
+  debughexcprintf(21, "aes DecryptData: used key", key, key_len);
+  debughexcprintf(21, "aes DecryptData: used privacy_params",
+                  privacy_params, 8);
+  debughexcprintf(21, "aes DecryptData: decrypted Data",
+                  out_buffer, *out_buffer_len);
+#endif
+
+  return SNMPv3_USM_OK;
+}
+
+int PrivAES::extend_short_key(const unsigned char *password,
+                              const unsigned int   password_len,
+                              const unsigned char *engine_id,
+                              const unsigned int   engine_id_len,
+                              unsigned char       *key,
+                              unsigned int        *key_len,
+                              const unsigned int   max_key_len,
+                              Auth                *auth)
+{
+  if (max_key_len < (unsigned)key_bytes)
+      return SNMPv3_USM_ERROR;
+
+  int res = 0;
+  unsigned char *hash_buf = new unsigned char[auth->get_hash_len()];
+
+  if (!hash_buf)
+  {
+    debugprintf(0, "Out of mem. Did not get %i bytes.", auth->get_hash_len());
+    return SNMPv3_USM_ERROR;
+  }
+
+  while (*key_len < (unsigned)key_bytes)
+  {
+    res = auth->hash(key, *key_len, hash_buf);
+    if (res != SNMPv3_USM_OK)
+      break;
+
+    int copy_bytes = key_bytes - *key_len;
+    if (copy_bytes > auth->get_hash_len())
+      copy_bytes = auth->get_hash_len();
+    if (*key_len + copy_bytes > max_key_len)
+       copy_bytes = max_key_len - *key_len;
+    memcpy(key + *key_len, hash_buf, copy_bytes);
+    *key_len += copy_bytes;
+  }
+
+  if (hash_buf) delete [] hash_buf;
+
+  return res;
+}
+
+
+#endif // _USE_LIBTOMCRYPT or _USE_OPENSSL
+
+
+#ifdef _USE_3DES_EDE
+
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+Priv3DES_EDE::Priv3DES_EDE()
+{
+  cipher = find_cipher("3des");
+  debugprintf(10, "tomcrypt returned cipher %d", cipher);
+}
+#endif
+
+
+int 
+Priv3DES_EDE::encrypt(const unsigned char *key,
+                     const unsigned int   key_len,
+                     const unsigned char *buffer,
+                     const unsigned int   buffer_len,
+                     unsigned char       *out_buffer,
+                     unsigned int        *out_buffer_len,
+                     unsigned char       *privacy_params,
+                     unsigned int        *privacy_params_len,
+                     const unsigned long  engine_boots,
+                     const unsigned long  engine_time)
+{
+  unsigned char initVect[8];
+  pp_uint64     my_salt = (*salt)++;
+  
+#ifdef INVALID_ENCRYPTION
+  debugprintf(-10, "\nWARNING: Encrypting with zeroed salt!\n");
+  my_salt = 0;
+#endif
+
+  /* check space in privacy_params buffer */
+  if (*privacy_params_len < 8)
+  {
+    debugprintf(4, "Buffer too small: should be 8, is (%i).",
+                *privacy_params_len);
+    return SNMPv3_USM_ENCRYPTION_ERROR;
+  }
+  /* Length is always 8 */
+  *privacy_params_len = 8;
+
+  /* check key length */
+  if (key_len < TRIPLEDES_EDE_KEY_LEN)
+  {
+    debugprintf(4, "Key too small: should be %d, is (%d).",
+                TRIPLEDES_EDE_KEY_LEN, key_len);
+    return SNMPv3_USM_ENCRYPTION_ERROR;
+  }
+
+  /* TODO: check if K1 != K2 != K3 */
+
+  // last 8 bytes of key are used as base for initialization vector
+  memcpy((char*)initVect, key+24, 8);
+
+  /* TODO: generate salt as specified in draft */
+
+  // put salt in privacy_params
+  for (int j=0; j<4; j++)
+  {
+    privacy_params[3-j] = (unsigned char) (0xFF & (engine_boots >> (8*j)));
+    privacy_params[7-j] = (unsigned char) (0xFF & (my_salt >> (8*j)));
+  }
+
+  // xor initVect with salt
+  for (int i=0; i<8; i++)
+    initVect[i] ^= privacy_params[i];
+
+
+#ifdef __DEBUG
+  debughexcprintf(21, "3DES Data to encrypt", buffer, buffer_len);
+  debughexcprintf(21, "3DES used iv", initVect, 8);
+  debughexcprintf(21, "3DES key", key, key_len);
+#endif
+
+  // The first 24 octets of the 32-octet secret are used as a 3DES-EDE
+  // key. Since 3DES-EDE uses only 168 bits the least significant bit
+  // in each octet is disregarded
+
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+  DESCBCType symcbc;
+  DES_CBC_START_ENCRYPT(cipher, initVect, key, 24, 16, symcbc);
+
+  for(unsigned int k = 0; k <= buffer_len - 8; k += 8) {
+    DES_CBC_ENCRYPT(buffer + k, out_buffer + k, symcbc, initVect, 8);
+  }
+
+  /* last part of buffer */
+  if (buffer_len % 8)
+  {
+    unsigned char tmp_buf[8];
+    unsigned char *tmp_buf_ptr = tmp_buf;
+    int start = buffer_len - (buffer_len % 8);
+    memset(tmp_buf, 0, 8);
+    for (unsigned int l = start; l < buffer_len; l++)
+      *tmp_buf_ptr++ = buffer[l];
+    DES_CBC_ENCRYPT(tmp_buf, out_buffer + start, symcbc, initVect, 8);
+    *out_buffer_len = buffer_len + 8 - (buffer_len % 8);
+  }
+  else
+    *out_buffer_len = buffer_len;
+
+  /* Clear context buffer (paranoia!)*/
+  DES_MEMSET(symcbc, 0, sizeof(symcbc));
+
+#else
+  DESCBCType ks1, ks2, ks3;
+
+  if ((des_key_sched((C_Block*)(key),     ks1) < 0) ||
+      (des_key_sched((C_Block*)(key +8),  ks2) < 0) ||
+      (des_key_sched((C_Block*)(key +16), ks3) < 0))
+  {
+      debugprintf(0, "Starting 3DES-EDE encryption failed.");
+      return SNMPv3_USM_ERROR;
+  }
+
+  if (buffer_len >= 8)
+    for(unsigned int k = 0; k <= (buffer_len - 8); k += 8) 
+    {
+      DES_EDE3_CBC_ENCRYPT(buffer+k, out_buffer+k, 8,
+                          ks1, ks2, ks3, initVect);
+    }
+
+  // Last part
+  if (buffer_len % 8)
+    {
+      unsigned char tmp_buf[8];
+      unsigned char *tmp_buf_ptr = tmp_buf;
+      int start = buffer_len - (buffer_len % 8);
+      memset(tmp_buf, 0, 8);
+      for (unsigned int l = start; l < buffer_len; l++)
+       *tmp_buf_ptr++ = buffer[l];
+      DES_EDE3_CBC_ENCRYPT(tmp_buf, out_buffer + start, 8,
+                          ks1, ks2, ks3, initVect);
+      
+      *out_buffer_len = buffer_len + 8 - (buffer_len % 8);
+    }
+  else
+    *out_buffer_len = buffer_len;
+
+  /* Clear context buffer (paranoia!)*/
+  DES_MEMSET(ks1, 0, sizeof(ks1));
+  DES_MEMSET(ks2, 0, sizeof(ks2));
+  DES_MEMSET(ks3, 0, sizeof(ks3));
+#endif
+
+#ifdef __DEBUG
+  debughexcprintf(21, "3DES created privacy_params", privacy_params, 8);
+  debughexcprintf(21, "3DES encrypted Data", out_buffer, *out_buffer_len);
+#endif
+
+  return SNMPv3_USM_OK;
+}
+
+
+int 
+Priv3DES_EDE::decrypt(const unsigned char *key,
+                     const unsigned int   key_len,
+                     const unsigned char *buffer,
+                     const unsigned int   buffer_len,
+                     unsigned char       *out_buffer,
+                     unsigned int        *out_buffer_len,
+                     const unsigned char *privacy_params,
+                     const unsigned int   privacy_params_len,
+                     const unsigned long  engine_boots,
+                     const unsigned long  engine_time)
+{
+  unsigned char initVect[8];
+
+  /* Privacy params length has to be 8  && Length has to be a multiple of 8 */
+  if (( buffer_len % 8 ) || (privacy_params_len != 8))
+    return SNMPv3_USM_DECRYPTION_ERROR;
+
+  for (int i=0; i<8; i++)
+    initVect[i] = privacy_params[i] ^ key[i+24];
+
+  memset((char*)out_buffer, 0, *out_buffer_len);
+
+#ifdef __DEBUG
+  debughexcprintf(21, "3DES Data to decrypt", buffer, buffer_len);
+  debughexcprintf(21, "3DES privacy_params",  privacy_params, 8);
+  debughexcprintf(21, "3DES used iv",   initVect, 8);
+  debughexcprintf(21, "3DES key", key, key_len);
+#endif
+
+#if defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+  DESCBCType symcbc;
+  DES_CBC_START_DECRYPT(cipher, initVect, key, 24, 16, symcbc);
+  for(unsigned int j=0; j<buffer_len; j+=8 ) {
+    DES_CBC_DECRYPT(buffer + j, out_buffer + j, symcbc, initVect, 8);
+  }
+  /* Clear context (paranoia!) */
+  DES_MEMSET(symcbc, 0, sizeof(symcbc));
+
+#else
+  DESCBCType ks1, ks2, ks3;
+
+  if ((des_key_sched((C_Block*)(key),     ks1) < 0) ||
+      (des_key_sched((C_Block*)(key+8),  ks2) < 0) ||
+      (des_key_sched((C_Block*)(key+16), ks3) < 0))
+    {
+      debugprintf(0, "Starting 3DES-EDE decryption failed.");
+      return SNMPv3_USM_ERROR;
+    }
+
+  for(unsigned int k=0; k<buffer_len; k+=8 ) 
+    {
+      DES_EDE3_CBC_DECRYPT(buffer+k, out_buffer+k, 8,
+                          ks1, ks2, ks3, initVect);
+    }
+  /* Clear context (paranoia!) */
+  DES_MEMSET(ks1, 0, sizeof(ks1));
+  DES_MEMSET(ks2, 0, sizeof(ks2));
+  DES_MEMSET(ks3, 0, sizeof(ks3));
+#endif
+
+  *out_buffer_len = buffer_len;
+
+#ifdef __DEBUG
+  debughexcprintf(21, "3DES decrypted Data", out_buffer, *out_buffer_len);
+#endif
+
+  return SNMPv3_USM_OK;  
+}
+
+
+int 
+Priv3DES_EDE::extend_short_key(const unsigned char *password,
+                              const unsigned int   password_len,
+                              const unsigned char *engine_id,
+                              const unsigned int   engine_id_len,
+                              unsigned char       *key,
+                              unsigned int        *key_len,
+                              const unsigned int   max_key_len,
+                              Auth                *auth)
+{
+  if (max_key_len < TRIPLEDES_EDE_KEY_LEN)
+    return SNMPv3_USM_ERROR;
+
+  unsigned int p2k_output_len = *key_len;
+  unsigned char *p2k_buf = new unsigned char[p2k_output_len];
+  int res = 0;
+
+  if (!p2k_buf) return SNMPv3_USM_ERROR;
+
+  while (*key_len < TRIPLEDES_EDE_KEY_LEN)
+  {
+    unsigned int p2k_buf_len = p2k_output_len;
+
+    res = auth->password_to_key(key, *key_len,
+                               engine_id, engine_id_len,
+                               p2k_buf, &p2k_buf_len);
+
+    if (res != SNMPv3_USM_OK)
+      break;
+
+    unsigned int copy_bytes = TRIPLEDES_EDE_KEY_LEN - *key_len;
+
+    if (copy_bytes > p2k_buf_len)
+       copy_bytes = p2k_buf_len;
+
+    if (*key_len + copy_bytes > max_key_len)
+       copy_bytes = max_key_len - *key_len;
+
+    memcpy(key + *key_len, p2k_buf, copy_bytes);
+
+    *key_len += copy_bytes;
+  }
+
+  if (p2k_buf) delete [] p2k_buf;
+
+  return res;
+}
+
+#ifdef _TEST
+bool Priv3DES_EDE::test()
+{
+  int status;
+  AuthPriv ap(status);
+  if (status != SNMPv3_USM_OK)
+      return false;
+
+  if (ap.add_auth(new AuthSHA()) != SNMP_ERROR_SUCCESS)
+  {
+      debugprintf(0, "Error: could not add AuthSHA.");
+      return false;
+  }
+
+  if (ap.add_auth(new AuthMD5()) != SNMP_ERROR_SUCCESS)
+  {
+      debugprintf(0, "Error: could not add AuthMD5.");
+      return false;
+  }
+
+  if (ap.add_priv(new Priv3DES_EDE()) != SNMP_ERROR_SUCCESS)
+  {
+      debugprintf(0, "Error: could not add Priv3DES_EDE.");
+      return false;
+  }
+
+  unsigned char password[11] = "maplesyrup";
+  unsigned char engine_id[12];
+
+  memset(engine_id, 0, 11);
+  engine_id[11] = 2;
+
+  unsigned char key[TRIPLEDES_EDE_KEY_LEN];
+  unsigned int key_len = TRIPLEDES_EDE_KEY_LEN;
+
+  status = ap.password_to_key_priv(SNMP_AUTHPROTOCOL_HMACSHA,
+                                   SNMP_PRIVPROTOCOL_3DESEDE,
+                                   password, 10,
+                                   engine_id, 12,
+                                   key,  &key_len);
+
+  debughexcprintf(1, "result key 3DES SHA",
+                  key, key_len);
+
+  key_len = TRIPLEDES_EDE_KEY_LEN;
+  status = ap.password_to_key_priv(SNMP_AUTHPROTOCOL_HMACMD5,
+                                   SNMP_PRIVPROTOCOL_3DESEDE,
+                                   password, 10,
+                                   engine_id, 12,
+                                   key,  &key_len);
+
+  debughexcprintf(1, "result key 3DES MD5",
+                  key, key_len);
+
+  unsigned char msg[80] = "This is the secret message, that has to be encrypted!";
+  unsigned char enc_buffer[80];
+  unsigned int enc_buffer_len = 80;
+  unsigned char dec_buffer[80];
+  unsigned int dec_buffer_len = 80;
+  unsigned char priv_params[64];
+  unsigned int priv_params_len = 64;
+
+
+  status = ap.encrypt_msg(SNMP_PRIVPROTOCOL_3DESEDE,
+                         key, key_len, msg, 53,
+                         enc_buffer, &enc_buffer_len,
+                         priv_params, &priv_params_len, 0x5abc, 0x6def);
+  
+  debughexcprintf(1, "encrypted text",
+                  enc_buffer, enc_buffer_len);
+
+  status = ap.decrypt_msg(SNMP_PRIVPROTOCOL_3DESEDE,
+                         key, key_len, enc_buffer, enc_buffer_len,
+                         dec_buffer, &dec_buffer_len,
+                         priv_params, priv_params_len, 0x5abc, 0x6def);
+
+  dec_buffer[dec_buffer_len] = 0;
+  debugprintf(1, "decrypted text: %s",
+                  dec_buffer);
+  // TODO: check keys and return real value
+  return true;
+}
+#endif
+
+#endif // _USE_3DES_EDE
+
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
+
+#endif // _SNMPv3
diff --git a/3rdparty/snmp++/src/counter.cpp b/3rdparty/snmp++/src/counter.cpp
new file mode 100644 (file)
index 0000000..42b2351
--- /dev/null
@@ -0,0 +1,97 @@
+/*_############################################################################
+  _## 
+  _##  counter.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+  C O U N T E R. C P P
+
+  COUNTER32 CLASS IMPLEMENTATION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  Class implementation for SMI Counter32 class.
+=====================================================================*/
+char counter_cpp_version[]="@(#) SNMP++ $Id: counter.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+#include "snmp_pp/counter.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// copy constructor
+Counter32::Counter32(const Counter32 &c)
+{
+  smival.value.uNumber = c.smival.value.uNumber;
+  smival.syntax = sNMP_SYNTAX_CNTR32;
+  m_changed = true;
+  valid_flag = true;
+}
+
+// general assignment from any Value
+SnmpSyntax& Counter32::operator=(const SnmpSyntax &in_val)
+{
+  if (this == &in_val) return *this; // handle assignement from itself
+
+  valid_flag = false;          // will get set true if really valid
+  if (in_val.valid())
+  {
+    switch (in_val.get_syntax())
+    {
+      case sNMP_SYNTAX_UINT32:
+   // case sNMP_SYNTAX_GAUGE32:        .. indistinquishable from UINT32
+      case sNMP_SYNTAX_CNTR32:
+      case sNMP_SYNTAX_TIMETICKS:
+      case sNMP_SYNTAX_INT32:          // implied cast int -> uint
+         smival.value.uNumber = ((Counter32 &)in_val).smival.value.uNumber;
+         valid_flag = true;
+         break;
+    }
+  }
+  m_changed = true; 
+  return *this;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/ctr64.cpp b/3rdparty/snmp++/src/ctr64.cpp
new file mode 100644 (file)
index 0000000..27e0733
--- /dev/null
@@ -0,0 +1,308 @@
+/*_############################################################################
+  _## 
+  _##  ctr64.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  C O U N T E R 6 4. C P P
+
+  COUNTER64 CLASS IMPLEMENTATION
+
+  DESIGN + AUTHOR:     Peter E. Mellquist
+
+  DESCRIPTION:         Implementation for Counter64 (64 bit counter class).
+=====================================================================*/
+char counter64_cpp_version[]="@(#) SNMP++ $Id: ctr64.cpp 1558 2009-07-03 20:16:53Z katz $";
+
+#include "snmp_pp/ctr64.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/v3.h"
+
+#include <stdio.h>   // for pretty printing...
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define MAX32 4294967295u
+
+
+//------------------[ constructor with no value ]------------------------
+Counter64::Counter64() : m_changed(true)
+{
+  smival.syntax = sNMP_SYNTAX_CNTR64;
+  smival.value.hNumber.hipart = 0;
+  smival.value.hNumber.lopart = 0;
+}
+
+//------------------[ constructor with values ]--------------------------
+Counter64::Counter64(unsigned long hi, unsigned long lo) : m_changed(true)
+{
+  smival.syntax = sNMP_SYNTAX_CNTR64;
+  smival.value.hNumber.hipart = hi;
+  smival.value.hNumber.lopart = lo;
+}
+
+//------------------[ constructor with low value only ]------------------
+Counter64::Counter64(unsigned long lo) : m_changed(true)
+{
+  smival.syntax = sNMP_SYNTAX_CNTR64;
+  smival.value.hNumber.hipart = 0;
+  smival.value.hNumber.lopart = lo;
+}
+
+//------------------[ copy constructor ]---------------------------------
+Counter64::Counter64(const Counter64 &ctr64 ) : m_changed(true)
+{
+  smival.syntax = sNMP_SYNTAX_CNTR64;
+  smival.value.hNumber.hipart = ctr64.high();
+  smival.value.hNumber.lopart = ctr64.low();
+}
+
+//------------------[ operator=(const Counter64 &ctr64) ]-------------
+// assign a ctr64 to a ctr64
+Counter64& Counter64::operator=(const Counter64 &ctr64)
+{
+  if (this == &ctr64) return *this;  // check for self assignment
+  smival.value.hNumber.hipart = ctr64.high();
+  smival.value.hNumber.lopart = ctr64.low();
+  m_changed = true;
+  return *this;
+}
+
+//-------------------[ operator=(const unsigned long int i) ]---------
+// assign a ul to a ctr64, clears the high part
+// and assugns the low part
+Counter64& Counter64::operator=(const unsigned long i)
+{
+  smival.value.hNumber.hipart = 0;
+  smival.value.hNumber.lopart = i;
+  m_changed = true;
+  return *this;
+}
+
+//-----------[ c64_to_ll(Counter64 c64) ]-----------------------------
+// convert a Counter 64 to a 64 bit integer
+pp_uint64 Counter64::c64_to_ll(const Counter64 &c64)
+{
+  pp_uint64 ll = c64.high();
+  ll *= (pp_uint64)MAX32 + (pp_uint64)1; // gotta be MAX32 + 1 to move it to next pos
+  ll += c64.low();
+  return ll;
+}
+
+//-----------[ c64_to_ll( ) ]------------------------------------------
+pp_uint64 Counter64::c64_to_ll() const
+{
+  pp_uint64 ll = high();
+  ll *= (pp_uint64)MAX32 + (pp_uint64)1; // gotta be MAX32 + 1 to move it to next pos
+  ll += low();
+  return ll;
+}
+
+//-----------[ ll_to_c64(pp_uint64 ll) ]----------------------------
+// convert a 64 bit integer to a Counter64
+Counter64 Counter64::ll_to_c64(const pp_uint64 &ll)
+{
+  pp_uint64 high = (pp_uint64)MAX32 + (pp_uint64)1; // look above
+  unsigned long h = (unsigned long)(ll / high);
+  return Counter64(h, (unsigned long)(ll - (h * high)));
+}
+
+//----------[ Counter64::operator+(const Counter64 &c) ]---------------
+// add two Counter64s
+Counter64 Counter64::operator+(const Counter64 &c) const
+{
+  pp_uint64 llsum = c64_to_ll() + c.c64_to_ll();
+  return ll_to_c64(llsum);
+}
+
+//------------[ Counter64::operator-(const Counter64 &c) ]-------------
+// subtract two Counter64s
+Counter64 Counter64::operator-(const Counter64 &c) const
+{
+  pp_uint64 lldiff = c64_to_ll() - c.c64_to_ll();
+  return ll_to_c64(lldiff);
+}
+
+//------------[ Counter64::operator*(const Counter64 &c) ]-------------
+// multiply two Counter64s
+Counter64 Counter64::operator*(const Counter64 &c) const
+{
+  pp_uint64 llmult = c64_to_ll() * c.c64_to_ll();
+  return ll_to_c64(llmult);
+}
+
+//------------[ Counter64::operator/(const Counter64 &c) ]--------------
+// divide two Counter64s
+Counter64 Counter64::operator/(const Counter64 &c) const
+{
+  pp_uint64 lldiv = c64_to_ll() / c.c64_to_ll();
+  return ll_to_c64(lldiv);
+}
+
+//-------[ overloaded equivlence test ]----------------------------------
+bool operator==(const Counter64 &lhs, const Counter64 &rhs)
+{
+  return ((lhs.high() == rhs.high()) && (lhs.low() == rhs.low()));
+}
+
+//-------[ overloaded not equal test ]-----------------------------------
+bool operator!=(const Counter64 &lhs, const Counter64 &rhs)
+{
+  return ((lhs.high() != rhs.high()) || (lhs.low() != rhs.low()));
+}
+
+//--------[ overloaded less than ]---------------------------------------
+bool operator<(const Counter64 &lhs, const Counter64 &rhs)
+{
+  return ( (lhs.high() < rhs.high()) ||
+          ((lhs.high() == rhs.high()) && (lhs.low() < rhs.low())));
+}
+
+//---------[ overloaded less than or equal ]-----------------------------
+bool operator<=(const Counter64 &lhs, const Counter64 &rhs)
+{
+  return ( (lhs.high() < rhs.high()) ||
+          ((lhs.high() == rhs.high()) && (lhs.low() <= rhs.low())));
+}
+
+//---------[ overloaded greater than ]-----------------------------------
+bool operator>(const Counter64 &lhs, const Counter64 &rhs)
+{
+  return ( (lhs.high() > rhs.high()) ||
+          ((lhs.high() == rhs.high()) && (lhs.low() > rhs.low())));
+}
+
+//----------[ overloaded greater than or equal ]-------------------------
+bool operator>=(const Counter64 &lhs, const Counter64 &rhs)
+{
+  return ( (lhs.high() > rhs.high()) ||
+          ((lhs.high() == rhs.high()) && (lhs.low() >= rhs.low())));
+}
+
+//----------[ return ASCII format ]-------------------------
+// TODO:  Fix up to do real 64bit decimal value printing...
+//        For now, print > 32-bit values in hex
+// 26Nov2002 M.Evstiounin - this method is not thread safe!
+const char *Counter64::get_printable() const
+{
+  if (m_changed == false)
+    return output_buffer;
+
+  char *buf = PP_CONST_CAST(char*, output_buffer);
+  if ( high() != 0 )
+    sprintf(buf, "0x%lX%08lX", high(), low());
+  else
+    sprintf(buf, "%lu", low());
+
+  Counter64 *nc_this = PP_CONST_CAST(Counter64*, this);
+  nc_this->m_changed = false;
+
+  return output_buffer;
+}
+
+
+//----------------[ general Value = operator ]---------------------
+SnmpSyntax& Counter64::operator=(const SnmpSyntax &val)
+{
+  if (this == &val) return *this;  // protect against assignment from itself
+
+  smival.value.hNumber.lopart = 0;     // pessimsitic - assume no mapping
+  smival.value.hNumber.hipart = 0;
+
+  // try to make assignment valid
+  if (val.valid())
+  {
+    switch (val.get_syntax())
+    {
+      case sNMP_SYNTAX_CNTR64:
+       smival.value.hNumber.hipart =
+               ((Counter64 &)val).smival.value.hNumber.hipart;
+       smival.value.hNumber.lopart =
+               ((Counter64 &)val).smival.value.hNumber.lopart;
+       break;
+
+      case sNMP_SYNTAX_CNTR32:
+      case sNMP_SYNTAX_TIMETICKS:
+      case sNMP_SYNTAX_GAUGE32:
+   // case sNMP_SYNTAX_UINT32:         .. indistinguishable from GAUGE32
+      case sNMP_SYNTAX_INT32:
+       // take advantage of union...
+       smival.value.hNumber.lopart = ((Counter64 &)val).smival.value.uNumber;
+       smival.value.hNumber.hipart = 0;
+       break;
+    }
+  }
+  m_changed = true;
+  return *this;
+}
+
+// Return the space needed for serialization
+int Counter64::get_asn1_length() const
+{
+  if (smival.value.hNumber.hipart == 0)
+  {
+    if (smival.value.hNumber.lopart < 0x80)
+      return 3;
+    else if (smival.value.hNumber.lopart < 0x8000)
+      return 4;
+    else if (smival.value.hNumber.lopart < 0x800000)
+      return 5;
+    else if (smival.value.hNumber.lopart < 0x80000000)
+      return 6;
+    return 7;
+  }
+  if (smival.value.hNumber.hipart < 0x80)
+    return 7;
+  else if (smival.value.hNumber.hipart < 0x8000)
+    return 8;
+  else if (smival.value.hNumber.hipart < 0x800000)
+    return 9;
+  else if (smival.value.hNumber.hipart < 0x80000000)
+    return 10;
+  return 11;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/eventlist.cpp b/3rdparty/snmp++/src/eventlist.cpp
new file mode 100644 (file)
index 0000000..60ce60b
--- /dev/null
@@ -0,0 +1,269 @@
+/*_############################################################################
+  _## 
+  _##  eventlist.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+      E V E N T L I S T . C P P
+
+      CEventList  CLASS DEFINITION
+
+      COPYRIGHT HEWLETT PACKARD COMPANY 1999
+
+      INFORMATION NETWORKS DIVISION
+
+      NETWORK MANAGEMENT SECTION
+
+      DESIGN + AUTHOR:        Tom Murray
+
+      DESCRIPTION:
+        Queue for holding all event sources (snmp messages, user
+        defined input sources, user defined timeouts, etc)
+=====================================================================*/
+char event_list_version[]="@(#) SNMP++ $Id: eventlist.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+//----[ snmp++ includes ]----------------------------------------------
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/eventlist.h"         // queue for holding all event sources
+#include "snmp_pp/msgqueue.h"          // queue for holding snmp event sources
+#include "snmp_pp/notifyqueue.h"       // queue for holding trap callbacks
+#include "snmp_pp/snmperrs.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//----[ CSNMPMessageQueueElt class ]--------------------------------------
+
+CEventList::CEventListElt::CEventListElt(CEvents *events,
+                                        CEventListElt *next,
+                                        CEventListElt *previous):
+  m_events(events), m_Next(next), m_previous(previous)
+{
+  /* Finish insertion into doubly linked list */
+  if (m_Next)     m_Next->m_previous = this;
+  if (m_previous) m_previous->m_Next = this;
+}
+
+CEventList::CEventListElt::~CEventListElt()
+{
+  /* Do deletion form doubly linked list */
+  if (m_Next)     m_Next->m_previous = m_previous;
+  if (m_previous) m_previous->m_Next = m_Next;
+  if (m_events)   delete m_events;
+}
+
+
+//----[ CEventList class ]--------------------------------------
+
+
+CEventList::~CEventList()
+{
+  CEventListElt *leftOver;
+
+  /* walk the list deleting any elements still on the queue */
+  lock();
+  while ((leftOver = m_head.GetNext()))
+    delete leftOver;
+  unlock();
+}
+
+CEvents * CEventList::AddEntry(CEvents *events) REENTRANT ({
+    /*---------------------------------------------------------*/
+    /* Insert entry at head of list, done automagically by the */
+    /* constructor function, so don't use the return value.    */
+    /*---------------------------------------------------------*/
+  (void) new CEventListElt(events, m_head.GetNext(), &m_head);
+  m_msgCount++;
+
+  return events;
+})
+
+int CEventList::GetNextTimeout(msec &sendTime) REENTRANT ({
+
+  CEventListElt *msgEltPtr = m_head.GetNext();
+  msec tmpTime(sendTime);
+
+  sendTime.SetInfinite();      // set sendtime out into future
+  while (msgEltPtr) {
+    if (msgEltPtr->GetEvents()->GetCount() &&
+       !msgEltPtr->GetEvents()->GetNextTimeout(tmpTime)) {
+      if (sendTime > tmpTime)
+       sendTime = tmpTime;
+    }
+
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+ return 0;
+})
+
+#ifdef HAVE_POLL_SYSCALL
+
+int CEventList::GetFdCount()
+{
+  SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+  int count = 0;
+  CEventListElt *msgEltPtr = m_head.GetNext();
+
+  while (msgEltPtr)
+  {
+    count += msgEltPtr->GetEvents()->GetFdCount();
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+  return count;
+}
+
+bool CEventList::GetFdArray(struct pollfd *readfds, int &remaining)
+{
+  SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+  CEventListElt *msgEltPtr = m_head.GetNext();
+
+  while (msgEltPtr)
+  {
+      int old_remaining = remaining;
+      if (msgEltPtr->GetEvents()->GetFdArray(readfds, remaining) == false)
+         return false;
+      readfds += (old_remaining - remaining);
+      msgEltPtr = msgEltPtr->GetNext();
+  }
+  return true;
+}
+
+int CEventList::HandleEvents(const struct pollfd *readfds, const int fds)
+{
+  lock();
+  CEventListElt *msgEltPtr = m_head.GetNext();
+  int status = SNMP_CLASS_SUCCESS;
+  while (msgEltPtr)
+  {
+    if (msgEltPtr->GetEvents()->GetCount())
+    {
+      unlock();
+      status = msgEltPtr->GetEvents()->HandleEvents(readfds, fds);
+      lock();
+    }
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+  unlock();
+  return status;
+}
+
+#else
+
+void CEventList::GetFdSets(int &maxfds, fd_set &readfds, fd_set &writefds,
+                          fd_set &exceptfds) REENTRANT ({
+
+  CEventListElt *msgEltPtr = m_head.GetNext();
+
+  maxfds = 0;
+  FD_ZERO(&readfds);
+  FD_ZERO(&writefds);
+  FD_ZERO(&exceptfds);
+  while (msgEltPtr) {
+    if (msgEltPtr->GetEvents()->GetCount()) {
+      msgEltPtr->GetEvents()->GetFdSets(maxfds, readfds, writefds, exceptfds);
+    }
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+})
+
+int CEventList::HandleEvents(const int maxfds,
+                            const fd_set &readfds,
+                            const fd_set &writefds,
+                            const fd_set &exceptfds)
+{
+  lock();
+  CEventListElt *msgEltPtr = m_head.GetNext();
+  int status = SNMP_CLASS_SUCCESS;
+  while (msgEltPtr){
+    if (msgEltPtr->GetEvents()->GetCount()) {
+      unlock();
+      status = msgEltPtr->GetEvents()->HandleEvents(maxfds, readfds, writefds,
+                                                   exceptfds);
+      lock();
+    }
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+  unlock();
+  return status;
+}
+
+#endif // HAVE_POLL_SYSCALL
+
+int CEventList::DoRetries(const msec &sendtime) REENTRANT ({
+
+  CEventListElt *msgEltPtr = m_head.GetNext();
+  int status = SNMP_CLASS_SUCCESS;
+  while (msgEltPtr){
+    if (msgEltPtr->GetEvents()->GetCount()) {
+      status = msgEltPtr->GetEvents()->DoRetries(sendtime);
+    }
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+  return status;
+})
+
+int CEventList::Done() REENTRANT ({
+
+  CEventListElt *msgEltPtr = m_head.GetNext();
+  int status = SNMP_CLASS_SUCCESS;
+
+  if (m_done) {
+    m_done--;
+    return 1;
+  }
+
+  while (msgEltPtr){
+    if (msgEltPtr->GetEvents()->GetCount()) {
+      status = msgEltPtr->GetEvents()->Done();
+      if (status)
+       break;
+    }
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+  return status;
+})
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/eventlistholder.cpp b/3rdparty/snmp++/src/eventlistholder.cpp
new file mode 100644 (file)
index 0000000..052b1ad
--- /dev/null
@@ -0,0 +1,367 @@
+/*_############################################################################
+  _## 
+  _##  eventlistholder.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+char event_list_holder_version[]="@(#) SNMP++ $Id: eventlistholder.cpp 342 2008-08-29 22:00:19Z katz $";
+
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/eventlist.h"
+#include "snmp_pp/msgqueue.h"
+#include "snmp_pp/notifyqueue.h"
+#include "snmp_pp/mp_v3.h"
+#include "snmp_pp/v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+EventListHolder::EventListHolder(Snmp *snmp_session)
+{
+  // Automaticly add the SNMP message queue
+  m_snmpMessageQueue = new CSNMPMessageQueue(this, snmp_session);
+  m_eventList.AddEntry(m_snmpMessageQueue);
+
+  // Automatically add the SNMP notification queue
+  m_notifyEventQueue = new CNotifyEventQueue(this, snmp_session);
+  m_eventList.AddEntry(m_notifyEventQueue);
+}
+
+//---------[ Block For Response ]-----------------------------------
+// Wait for the completion of an outstanding SNMP event (msg).
+// Handle any other events as they occur.
+int EventListHolder::SNMPBlockForResponse(const unsigned long req_id,
+                                         Pdu &pdu)
+{
+  CSNMPMessage *msg;
+  int status;
+
+  do {
+    SNMPProcessEvents(1000);
+  } while (!m_snmpMessageQueue->Done(req_id));
+
+  m_snmpMessageQueue->lock();
+  msg = m_snmpMessageQueue->GetEntry(req_id);
+  if (msg) {
+    // we found our response
+    msg->GetPdu(status, pdu);
+
+    // Dequeue the message
+    m_snmpMessageQueue->DeleteEntry(req_id);
+    m_snmpMessageQueue->unlock();
+    return  status;
+  }
+  else {
+    // not in the send queue...must have timed out
+    m_snmpMessageQueue->unlock();
+    return SNMP_CLASS_TIMEOUT;
+  }
+}
+
+//---------[ Process Pending Events ]-------------------------------
+#ifdef HAVE_POLL_SYSCALL
+// Pull all available events out of their sockets - do not block
+int EventListHolder::SNMPProcessPendingEvents()
+{
+  int fdcount;
+  int remaining;
+  struct pollfd *pollfds = 0;
+  int nfound = 0;
+  int timeout;
+  msec now(0, 0);
+  int status;
+
+  pevents_mutex.lock();
+
+  timeout = 1;  // chosen a very small timeout
+  // in order to avoid busy looping but keep overall performance
+
+  do
+  {
+    do
+    {
+      fdcount = m_eventList.GetFdCount();
+      if (pollfds) delete [] pollfds;
+      pollfds = new struct pollfd[fdcount + 1];
+      memset(pollfds, 0, (fdcount + 1) * sizeof(struct pollfd));
+      remaining = fdcount + 1;
+    } while (m_eventList.GetFdArray(pollfds, remaining) == false);
+
+    nfound = poll(pollfds, fdcount, timeout);
+
+    now.refresh();
+
+    if (nfound > 0)
+    {
+      status = m_eventList.HandleEvents(pollfds, fdcount);
+      // TM should we do anything with bad status?
+    }
+#ifdef WIN32
+    /* On Win32 select immediately returns -1 if all fd_sets are empty */
+    if (maxfds == 0)
+      Sleep(1); /* prevent 100% CPU utilization */
+#endif
+  } while (nfound > 0);
+
+  // go through the message queue and resend any messages
+  // which are past the timeout.
+  status = m_eventList.DoRetries(now);
+
+  pevents_mutex.unlock();
+
+  if (pollfds) delete [] pollfds;
+
+  return status;
+}
+
+// Block until an event shows up - then handle the event(s)
+int EventListHolder::SNMPProcessEvents(const int max_block_milliseconds)
+{
+  int fdcount;
+  int remaining;
+  struct pollfd *pollfds = 0;
+  struct timeval fd_timeout;
+  int timeout;
+  msec now; // automatcally calls msec::refresh()
+  msec sendTime;
+  int status = 0;
+
+  m_eventList.GetNextTimeout(sendTime);
+  now.GetDelta(sendTime, fd_timeout);
+
+  do
+  {
+    fdcount = m_eventList.GetFdCount();
+    if (pollfds) delete [] pollfds;
+    pollfds = new struct pollfd[fdcount + 1];
+    memset(pollfds, 0, (fdcount + 1) * sizeof(struct pollfd));
+    remaining = fdcount + 1;
+  } while (m_eventList.GetFdArray(pollfds, remaining) == false);
+
+  if ((max_block_milliseconds > 0) &&
+      ((fd_timeout.tv_sec > max_block_milliseconds / 1000) ||
+       ((fd_timeout.tv_sec == max_block_milliseconds / 1000) &&
+       (fd_timeout.tv_usec > (max_block_milliseconds % 1000) * 1000))))
+  {
+    fd_timeout.tv_sec = max_block_milliseconds / 1000;
+    fd_timeout.tv_usec = (max_block_milliseconds % 1000) * 1000;
+  }
+
+  /* Prevent endless sleep in case no fd is open */
+  if ((fdcount == 0) && (fd_timeout.tv_sec > 5))
+    fd_timeout.tv_sec = 5; /* sleep at max 5.99 seconds */
+
+  timeout = fd_timeout.tv_sec * 1000 + fd_timeout.tv_usec / 1000;
+
+  poll(pollfds, fdcount, timeout);
+
+  status = SNMPProcessPendingEvents();
+
+  if (pollfds) delete [] pollfds;
+
+  return status;
+}
+
+#else
+
+int EventListHolder::SNMPProcessPendingEvents()
+{
+  int maxfds;
+  fd_set readfds;
+  fd_set writefds;
+  fd_set exceptfds;
+  int nfound = 0;
+  struct timeval fd_timeout;
+  msec now(0, 0);
+  int status;
+
+  pevents_mutex.lock();
+
+  // do not allow select to block
+  fd_timeout.tv_sec = 0;
+  fd_timeout.tv_usec = 10;  // chosen a very small timeout
+  // in order to avoid busy looping but keep overall performance
+
+  do {
+
+    // Set up Select
+    m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
+
+    nfound = select(maxfds, &readfds, &writefds, &exceptfds, &fd_timeout);
+
+    now.refresh();
+
+    if (nfound > 0)
+    { // found something on select
+      status = m_eventList.HandleEvents(maxfds, readfds, writefds, exceptfds);
+      // TM should we do anything with bad status?
+    }
+#ifdef WIN32
+    /* On Win32 select immediately returns -1 if all fd_sets are empty */
+    if (maxfds == 0)
+      Sleep(1); /* prevent 100% CPU utilization */
+#endif
+  } while (nfound > 0);
+
+  // go through the message queue and resend any messages
+  // which are past the timeout.
+  status = m_eventList.DoRetries(now);
+
+  pevents_mutex.unlock();
+
+  return status;
+}
+
+//---------[ Process Events ]------------------------------------------
+// Block until an event shows up - then handle the event(s)
+int EventListHolder::SNMPProcessEvents(const int max_block_milliseconds)
+{
+  int maxfds;
+  fd_set readfds;
+  fd_set writefds;
+  fd_set exceptfds;
+  struct timeval fd_timeout;
+  msec now; // automatcally calls msec::refresh()
+  msec sendTime;
+  int status = 0;
+
+  m_eventList.GetNextTimeout(sendTime);
+  now.GetDelta(sendTime, fd_timeout);
+
+  m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
+
+  if ((max_block_milliseconds > 0) &&
+      ((fd_timeout.tv_sec > max_block_milliseconds / 1000) ||
+       ((fd_timeout.tv_sec == max_block_milliseconds / 1000) &&
+       (fd_timeout.tv_usec > (max_block_milliseconds % 1000) * 1000))))
+  {
+    fd_timeout.tv_sec = max_block_milliseconds / 1000;
+    fd_timeout.tv_usec = (max_block_milliseconds % 1000) * 1000;
+  }
+
+  /* Prevent endless sleep in case no fd is open */
+  if ((maxfds == 0) && (fd_timeout.tv_sec > 5))
+    fd_timeout.tv_sec = 5; /* sleep at max 5.99 seconds */
+
+  select(maxfds, &readfds, &writefds, &exceptfds, &fd_timeout);
+
+  status = SNMPProcessPendingEvents();
+
+  return status;
+}
+
+#endif
+
+//---------[ Main Loop ]------------------------------------------
+// Infinite loop which blocks when there is nothing to do and handles
+// any events as they occur.
+void EventListHolder::SNMPMainLoop(const int max_block_milliseconds)
+{
+  do {
+    SNMPProcessEvents(max_block_milliseconds);
+  } while (!m_eventList.Done());
+}
+
+//---------[ Exit Main Loop ]---------------------------------------
+// Force the SNMP Main Loop to terminate immediately
+void EventListHolder::SNMPExitMainLoop()
+{
+   m_eventList.SetDone();
+}
+
+#ifdef HAVE_POLL_SYSCALL
+
+int EventListHolder::GetFdCount()
+{
+  return m_eventList.GetFdCount();
+}
+
+bool EventListHolder::GetFdArray(struct pollfd *readfds, int &remaining)
+{
+    return m_eventList.GetFdArray(readfds, remaining);
+}
+
+#else
+
+void EventListHolder::SNMPGetFdSets(int    &maxfds,
+                                   fd_set &readfds,
+                                   fd_set &writefds,
+                                   fd_set &exceptfds)
+{
+  m_eventList.GetFdSets(maxfds, readfds, writefds, exceptfds);
+}
+
+#endif // HAVE_POLL_SYSCALL
+
+Uint32 EventListHolder::SNMPGetNextTimeout()
+{
+  msec now;
+  msec sendTime(now);
+
+//TM: This function used to have an argument of sendTime and
+//    would simply call eventList.GetNextTimeout(sendTime) and
+//    return the status.  However, to avoid exposing the msec
+//    class we now convert the msec to hundreths of seconds
+//    and return that as a unsigned long.
+// 25-Jan-96 TM
+
+  m_eventList.GetNextTimeout(sendTime);
+  if (sendTime.IsInfinite()) {
+    return UINT_MAX;
+  }
+  else {
+
+    // Kludge: When this was first designed the units were millisecs
+    // However, later on the units for the target class were changed
+    // to hundreths of secs.  Divide millisecs by 10 to create the
+    // hundreths of secs which the rest of the objects use.
+    // 25-Jan-96 TM
+
+    // 21-May-02 DLD: Add check to avoid returning a negative interval
+    // Long eventlists seem to end up with events that are greater
+    // than the time when the event loop is started, but less than the
+    // time when this function is called.  This check is analagous to
+    // what is done in msec::GetDelta() which is used in
+    // SNMPProcessEvents(), the library main loop.
+
+    // 21-May-02 DLD: Add 1/100 sec to time out to avoid returning a
+    // short time out interval.  A short interval can result due to
+    // truncation of the millisec value when dividing by 10.
+
+    if (sendTime > now)
+    {
+      sendTime -= now;
+      return ((((unsigned long) sendTime) / 10) + 1);
+    }
+    else
+      return 0;
+  }
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/gauge.cpp b/3rdparty/snmp++/src/gauge.cpp
new file mode 100644 (file)
index 0000000..17f9c8f
--- /dev/null
@@ -0,0 +1,72 @@
+/*_############################################################################
+  _## 
+  _##  gauge.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+  G A U G E. C P P
+
+  GAUGE32 CLASS IMPLEMTATION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  Class implemtation for SMI Gauge32 class.
+=====================================================================*/
+char gauge_cpp_version[]="@(#) SNMP++ $Id: gauge.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+#include "snmp_pp/gauge.h"       // header file for gauge class
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// copy constructor
+Gauge32::Gauge32(const Gauge32 &g32)
+  : SnmpUInt32()
+{
+  smival.value.uNumber = g32.smival.value.uNumber;
+  smival.syntax = sNMP_SYNTAX_GAUGE32;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/idea.cpp b/3rdparty/snmp++/src/idea.cpp
new file mode 100644 (file)
index 0000000..6229e2c
--- /dev/null
@@ -0,0 +1,274 @@
+/*_############################################################################
+  _## 
+  _##  idea.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+char idea_cpp_version[]="#(@) SNMP++ $Id: idea.cpp 43 2004-03-03 23:11:21Z katz $";
+/*
+
+idea.c
+
+Author: Tatu Ylonen <ylo@cs.hut.fi>
+
+Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
+                   All rights reserved
+
+Created: Sun Jun 25 02:59:39 1995 ylo
+
+This code is based on Xuejia Lai: On the Design and Security of Block
+Ciphers, ETH Series in Information Processing, vol. 1, Hartung-Gorre
+Verlag, Konstanz, Switzerland, 1992.  Another source was Bruce
+Schneier: Applied Cryptography, John Wiley & Sons, 1994.
+
+The IDEA mathematical formula may be covered by one or more of the
+following patents: PCT/CH91/00117, EP 0 482 154 B1, US Pat. 5,214,703.
+
+*/
+
+//#include "snmp_pp/includes.h"
+//#include "snmp_pp/getput.h"
+#include "snmp_pp/idea.h"
+#include <string.h>
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#ifdef _USE_IDEA
+
+/* Sets idea key for encryption. */
+
+void idea_set_key(IDEAContext *c, const unsigned char key[16])
+{
+  int i;
+  word16 *keys;
+
+  /* Get pointer to the keys. */
+  keys = c->key_schedule;
+
+  /* Keys for the first round are directly taken from the user-supplied key. */
+  for (i = 0; i < 8; i++)
+    keys[i] = (word16)GET_16BIT(key + 2 * i);
+
+  /* Each round uses the key of the previous key, rotated to the left by 25
+     bits.  The last four keys (output transform) are the first four keys
+     from what would be the ninth round. */
+  for (i = 8; i < 52; i++)
+    {
+      if ((i & 7) == 0)
+       keys += 8;
+      keys[i & 7] = ((keys[((i + 1) & 7) - 8] << 9) |
+                    (keys[((i + 2) & 7) - 8] >> 7)) & 0xffff;
+    }
+}
+
+/* Destroys any sensitive data in the context. */
+
+void idea_destroy_context(IDEAContext *c)
+{
+  memset(&c, 0, sizeof(c));
+}
+
+/* Performs the "multiplication" operation of IDEA: returns a*b mod 65537,
+   where a and b are first converted to 65536 if they are zero, and result
+   65536 is converted to zero.  Both inputs should be less than 65536.
+   Only the lower 16 bits of result are significant; other bits are garbage.
+   */
+
+static inline word32 mulop(word32 a, word32 b)
+{
+  word32 ab = a * b;
+  if (ab != 0)
+    {
+      word32 lo = ab & 0xffff;
+      word32 hi = (ab >> 16) & 0xffff;
+      return (lo - hi) + (lo < hi);
+    }
+  if (a == 0)
+    return 1 - b;
+  return  1 - a;
+}
+
+/* Performs the IDEA cipher transform on a block of data. */
+
+void idea_transform(IDEAContext *c, word32 l, word32 r, word32 *output)
+{
+  unsigned int round;
+  word16 *keys;
+  word32 t1, t2, x1, x2, x3, x4;
+
+  keys = c->key_schedule;
+  x1 = l >> 16;
+  x2 = l;
+  x3 = r >> 16;
+  x4 = r;
+  for (round = 0; round < 8; round++)
+    {
+      x1 = mulop(x1 & 0xffff, keys[0]);
+      x3 = x3 + keys[2];
+      x4 = mulop(x4 & 0xffff, keys[3]);
+      x2 = x2 + keys[1];
+      t1 = x1 ^ x3;
+      t2 = x2 ^ x4;
+      t1 = mulop(t1 & 0xffff, keys[4]);
+      t2 = t1 + t2;
+      t2 = mulop(t2 & 0xffff, keys[5]);
+      t1 = t1 + t2;
+      x1 = x1 ^ t2;
+      x4 = x4 ^ t1;
+      t1 = t1 ^ x2;
+      x2 = t2 ^ x3;
+      x3 = t1;
+      keys += 6;
+    }
+
+  x1 = mulop(x1 & 0xffff, keys[0]);
+  x3 = (x2 + keys[2]) & 0xffff;
+  x2 = t1 + keys[1]; /* t1 == old x3 */
+  x4 = mulop(x4 & 0xffff, keys[3]);
+  output[0] = (x1 << 16) | (x2 & 0xffff);
+  output[1] = (x3 << 16) | (x4 & 0xffff);
+}
+
+/* Encrypts len bytes from src to dest in CFB mode.  Len need not be a multiple
+   of 8; if it is not, iv at return will contain garbage.
+   Otherwise, iv will be modified at end to a value suitable for continuing
+   encryption. */
+
+void idea_cfb_encrypt(IDEAContext *c, unsigned char *iv, unsigned char *dest,
+                     const unsigned char *src, unsigned int len)
+{
+  word32 iv0, iv1, out[2];
+  unsigned int i;
+
+  iv0 = GET_32BIT(iv);
+  iv1 = GET_32BIT(iv + 4);
+
+  for (i = 0; i < len; i += 8)
+    {
+      idea_transform(c, iv0, iv1, out);
+      iv0 = out[0] ^ GET_32BIT(src + i);
+      iv1 = out[1] ^ GET_32BIT(src + i + 4);
+      if (i + 8 <= len)
+       {
+         PUT_32BIT(dest + i, iv0);
+         PUT_32BIT(dest + i + 4, iv1);
+       }
+      else
+       {
+         switch (len - i)
+           {
+           case 7:
+             dest[i + 6] = iv1 >> 8;
+             /*FALLTHROUGH*/
+           case 6:
+             dest[i + 5] = iv1 >> 16;
+             /*FALLTHROUGH*/
+           case 5:
+             dest[i + 4] = iv1 >> 24;
+             /*FALLTHROUGH*/
+           case 4:
+             dest[i + 3] = iv0;
+             /*FALLTHROUGH*/
+           case 3:
+             dest[i + 2] = iv0 >> 8;
+             /*FALLTHROUGH*/
+           case 2:
+             dest[i + 1] = iv0 >> 16;
+             /*FALLTHROUGH*/
+           case 1:
+             dest[i] = iv0 >> 24;
+             /*FALLTHROUGH*/
+           }
+       }
+    }
+  PUT_32BIT(iv, iv0);
+  PUT_32BIT(iv + 4, iv1);
+}
+
+/* Decrypts len bytes from src to dest in CFB mode.  Len need not be a multiple
+   of 8; if it is not, iv at return will contain garbage.
+   Otherwise, iv will be modified at end to a value suitable for continuing
+   decryption. */
+
+void idea_cfb_decrypt(IDEAContext *c, unsigned char *iv, unsigned char *dest,
+                     const unsigned char *src, unsigned int len)
+{
+  word32 iv0, iv1, out[2], plain0, plain1;
+  unsigned int i;
+
+  iv0 = GET_32BIT(iv);
+  iv1 = GET_32BIT(iv + 4);
+
+  for (i = 0; i < len; i += 8)
+    {
+      idea_transform(c, iv0, iv1, out);
+      iv0 = GET_32BIT(src + i);
+      iv1 = GET_32BIT(src + i + 4);
+      plain0 = out[0] ^ iv0;
+      plain1 = out[1] ^ iv1;
+      if (i + 8 <= len)
+       {
+         PUT_32BIT(dest + i, plain0);
+         PUT_32BIT(dest + i + 4, plain1);
+       }
+      else
+       {
+         switch (len - i)
+           {
+           case 7:
+             dest[i + 6] = plain1 >> 8;
+             /*FALLTHROUGH*/
+           case 6:
+             dest[i + 5] = plain1 >> 16;
+             /*FALLTHROUGH*/
+           case 5:
+             dest[i + 4] = plain1 >> 24;
+             /*FALLTHROUGH*/
+           case 4:
+             dest[i + 3] = plain0;
+             /*FALLTHROUGH*/
+           case 3:
+             dest[i + 2] = plain0 >> 8;
+             /*FALLTHROUGH*/
+           case 2:
+             dest[i + 1] = plain0 >> 16;
+             /*FALLTHROUGH*/
+           case 1:
+             dest[i] = plain0 >> 24;
+             /*FALLTHROUGH*/
+           }
+       }
+    }
+  PUT_32BIT(iv, iv0);
+  PUT_32BIT(iv + 4, iv1);
+}
+
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/integer.cpp b/3rdparty/snmp++/src/integer.cpp
new file mode 100644 (file)
index 0000000..096657c
--- /dev/null
@@ -0,0 +1,257 @@
+/*_############################################################################
+  _## 
+  _##  integer.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+  I N T E G E R . C P P
+
+  SMI INTEGER CLASS IMPLEMTATION
+
+  DESIGN + AUTHOR: Jeff Meyer
+
+  DESCRIPTION:
+  Class implemtation for SMI Integer classes.
+=====================================================================*/
+char integer_cpp_version[]="#(@) SNMP++ $Id: integer.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+#include <stdio.h>             // for sprintf()
+#include "snmp_pp/integer.h"   // header file for gauge class
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// constructor no value
+SnmpUInt32::SnmpUInt32() : valid_flag(true), m_changed(true)
+{
+  smival.value.uNumber = 0;
+  smival.syntax = sNMP_SYNTAX_UINT32;
+}
+
+// constructor with value
+SnmpUInt32::SnmpUInt32 (const unsigned long i)
+  : valid_flag(true), m_changed(true)
+{
+  smival.value.uNumber = i;
+  smival.syntax = sNMP_SYNTAX_UINT32;
+}
+
+// copy constructor
+SnmpUInt32::SnmpUInt32(const SnmpUInt32 &c) : valid_flag(true), m_changed(true)
+{
+  smival.value.uNumber=c.smival.value.uNumber;
+  smival.syntax = sNMP_SYNTAX_UINT32;
+}
+
+// overloaded assignment
+SnmpUInt32& SnmpUInt32::operator=(const unsigned long i)
+{
+  smival.value.uNumber = i;
+  valid_flag = true;
+  m_changed = true;
+  return *this;
+}
+
+// general assignment from any Value
+SnmpSyntax& SnmpUInt32::operator=(const SnmpSyntax &in_val)
+{
+  if (this == &in_val) return *this; // handle assignement from itself
+
+  valid_flag = false;          // will get set true if really valid
+  if (in_val.valid())
+  {
+    switch (in_val.get_syntax())
+    {
+      case sNMP_SYNTAX_UINT32:
+   // case sNMP_SYNTAX_GAUGE32:        .. indistinquishable from UINT32
+      case sNMP_SYNTAX_CNTR32:
+      case sNMP_SYNTAX_TIMETICKS:
+      case sNMP_SYNTAX_INT32:          // implied cast int -> uint
+         smival.value.uNumber =
+             ((SnmpUInt32 &)in_val).smival.value.uNumber;
+         valid_flag = true;
+         break;
+    }
+  }
+  m_changed = true;
+  return *this;
+}
+
+// overloaded assignment
+SnmpUInt32& SnmpUInt32::operator=(const SnmpUInt32 &uli)
+{
+  if (this == &uli) return *this;  // check for self assignment
+
+  smival.value.uNumber = uli.smival.value.uNumber;
+  valid_flag = uli.valid_flag;
+  m_changed = true;
+  return *this;
+}
+
+// ASCII format return
+const char *SnmpUInt32::get_printable() const
+{
+  if (m_changed == false) return output_buffer;
+
+  SnmpUInt32 *nc_this = PP_CONST_CAST(SnmpUInt32*, this);
+  sprintf(nc_this->output_buffer, "%lu", smival.value.uNumber);
+
+  nc_this->m_changed = false;
+
+  return output_buffer;
+}
+
+// Return the space needed for serialization
+int SnmpUInt32::get_asn1_length() const
+{
+  if (smival.value.uNumber < 0x80)
+    return 3;
+  else if (smival.value.uNumber < 0x8000)
+    return 4;
+  else if (smival.value.uNumber < 0x800000)
+    return 5;
+  else if (smival.value.uNumber < 0x80000000)
+    return 6;
+  return 7;
+}
+
+//====================================================================
+//  INT 32 Implementation
+//====================================================================
+
+// constructor no value
+SnmpInt32::SnmpInt32() : valid_flag(true), m_changed(true)
+{
+  smival.value.sNumber = 0;
+  smival.syntax = sNMP_SYNTAX_INT32;
+}
+
+// constructor with value
+SnmpInt32::SnmpInt32(const long i) : valid_flag(true), m_changed(true)
+{
+  smival.value.sNumber = i;
+  smival.syntax = sNMP_SYNTAX_INT32;
+}
+
+// constructor with value
+SnmpInt32::SnmpInt32(const SnmpInt32 &c) : valid_flag(true), m_changed(true)
+{
+  smival.value.sNumber = c.smival.value.sNumber;
+  smival.syntax = sNMP_SYNTAX_INT32;
+}
+
+// overloaded assignment
+SnmpInt32& SnmpInt32::operator=(const long i)
+{
+  smival.value.sNumber = (unsigned long) i;
+  valid_flag = true;
+  m_changed = true;
+  return *this;
+}
+
+// overloaded assignment
+SnmpInt32& SnmpInt32::operator=(const SnmpInt32 &uli)
+{
+  if (this == &uli) return *this;  // check for self assignment
+
+  smival.value.sNumber = uli.smival.value.sNumber;
+  valid_flag = uli.valid_flag;
+  m_changed = true;
+  return *this;
+}
+
+// general assignment from any Value
+SnmpSyntax& SnmpInt32::operator=(const SnmpSyntax &in_val)
+{
+  if (this == &in_val) return *this; // handle assignement from itself
+
+  valid_flag = false;          // will get set true if really valid
+  if (in_val.valid())
+  {
+    switch (in_val.get_syntax())
+    {
+      case sNMP_SYNTAX_INT32:
+      case sNMP_SYNTAX_UINT32:         // implied cast uint -> int
+   // case sNMP_SYNTAX_GAUGE32:        .. indistinquishable from UINT32
+      case sNMP_SYNTAX_CNTR32:         // implied cast uint -> int
+      case sNMP_SYNTAX_TIMETICKS:      // implied cast uint -> int
+         smival.value.sNumber =
+               ((SnmpInt32 &)in_val).smival.value.sNumber;
+         valid_flag = true;
+         break;
+    }
+  }
+  m_changed = true;
+  return *this;
+}
+
+// ASCII format return
+const char *SnmpInt32::get_printable() const
+{
+  if (m_changed == false) return output_buffer;
+
+  SnmpInt32 *nc_this = PP_CONST_CAST(SnmpInt32*, this);
+  sprintf(nc_this->output_buffer, "%ld", (long)smival.value.sNumber);
+
+  nc_this->m_changed = false;
+
+  return output_buffer;
+}
+
+// Return the space needed for serialization
+int SnmpInt32::get_asn1_length() const
+{
+  if ((smival.value.sNumber <   0x80) &&
+      (smival.value.sNumber >= -0x80))
+    return 3;
+  else if ((smival.value.sNumber <   0x8000) &&
+          (smival.value.sNumber >= -0x8000))
+    return 4;
+  else if ((smival.value.sNumber <   0x800000) &&
+          (smival.value.sNumber >= -0x800000))
+    return 5;
+  return 6;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/log.cpp b/3rdparty/snmp++/src/log.cpp
new file mode 100644 (file)
index 0000000..df16708
--- /dev/null
@@ -0,0 +1,410 @@
+/*_############################################################################
+  _## 
+  _##  log.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <process.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <signal.h>
+#include <string.h>
+
+#include <snmp_pp/log.h>
+
+#ifdef WIN32
+#ifdef __BCPLUSPLUS__
+#define _getpid getpid
+#endif
+#endif
+
+#if defined (CPU) && CPU == PPC603
+#include <taskLib.h>
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+using namespace Snmp_pp;
+#endif
+
+// default log filter: logs with level less or equal filter value are logged
+// error, warning, event, info, debug:
+static unsigned char default_logfilter[] = { 9, 9, 4, 6, 7, 15};
+
+#undef   LOG_INDENT
+
+
+/*--------------------------- class LogEntry --------------------------*/
+
+ /**
+  * Initialize a log entry, showing timestamp, class, and level.
+  * 
+  */  
+void LogEntry::init(void)
+{
+#ifdef WIN32
+       int pid = _getpid();
+#elif defined (CPU) && CPU == PPC603
+       int pid = taskIdSelf();
+#else
+       int pid = getpid();
+#endif
+
+       add_timestamp();
+       add_string(": ");
+       add_integer(pid);
+       add_string(": ");
+
+       char buf[20];
+       sprintf(buf, "(%X)", get_level());
+       add_string(buf);
+
+       switch (type & 0xF0) {
+       case DEBUG_LOG:   add_string("DEBUG  : "); break;
+       case INFO_LOG:    add_string("INFO   : "); break;
+       case WARNING_LOG: add_string("WARNING: "); break;
+       case ERROR_LOG:   add_string("ERROR  : "); break;
+       case EVENT_LOG:   add_string("EVENT  : "); break;
+       case USER_LOG:    add_string("USER   : "); break;
+       }
+
+#ifdef LOG_INDENT
+       // indent log by level
+       for (int i=0; i<(type & 0x0F); i++) 
+               add_string(" ");
+#endif
+}
+
+/**
+ * Add a string value to the log entry.
+ *
+ * @param l - A numeric value.
+ */
+LogEntry& LogEntry::operator+=(const char* s)
+{
+       // The convention for Agent++ log messages is that the
+       // timestamp, etc. is followed by the class and method name,
+       // then by the list of arguments.
+       if (count == 0) 
+               add_string(s);
+       else {
+         if (count == 1) 
+               add_string(": ");
+         else 
+               add_string(", ");
+
+         add_string("(");
+         add_string(s);
+         add_string(")");
+       }
+       count++;
+       return *this;
+}
+
+/**
+ * Add a numeric value to the log entry.
+ *
+ * @param l - A numeric value.
+ */
+LogEntry& LogEntry::operator+=(const long l)
+{
+       if (count == 1) 
+               add_string(": ");
+       else 
+               add_string(", ");
+
+       count++;
+       add_string("(");
+       add_integer(l);
+       add_string(")");
+       return *this;
+}
+
+/**
+ * Add an integer to the log.
+ *
+ * @param s - An integer value.
+ * @return TRUE if the value has been added and FALSE if the log
+ *         entry is full.
+ */
+bool LogEntry::add_integer(long l)
+{
+       char buf[40];
+       sprintf(buf, "%ld", l);
+       return add_string(buf);
+}
+
+/**
+ * Add the current time to the log entry.
+ */
+bool LogEntry::add_timestamp(void)
+{
+       return add_string(DefaultLog::log()->now());
+}
+
+
+/*------------------------- class LogEntryImpl ------------------------*/
+
+/**
+ * Constructor for the standard log entry implementation.
+ */  
+LogEntryImpl::LogEntryImpl(unsigned char t) : LogEntry(t)
+{
+       value = new char[MAX_LOG_SIZE];
+        value[0] = '\0';
+       ptr = value;
+       output_stopped = FALSE;
+}
+
+/**
+ * Destructor for the standard log entry implementation.
+ */  
+LogEntryImpl::~LogEntryImpl()
+{
+       delete [] value;
+}
+
+/**
+ * Add a string to the log.
+ *
+ * @param s - A string value.
+ * @return TRUE if the value has been added and FALSE if the log
+ *         entry is full.
+ */
+bool LogEntryImpl::add_string(const char* s)
+{
+       if (output_stopped)
+               return FALSE;
+
+       size_t len = strlen(s);
+       if (len <= bytes_left()) {
+               strcat(ptr, s);
+               ptr += len;
+               return TRUE;
+       }
+
+       if (bytes_left() >= 3) {
+               strcat(ptr, "...");
+               ptr += 3;
+       }
+       output_stopped = TRUE;
+       return FALSE;
+}      
+
+
+/*-------------------------- class AgentLog ---------------------------*/
+
+/**
+ * Default constructor.
+ */
+AgentLog::AgentLog()
+{
+       for (int i=0; i<LOG_TYPES; i++)
+               logfilter[i] = default_logfilter[i];
+}
+
+void AgentLog::set_filter(int logclass, unsigned char filter)
+{ 
+       int idx = (logclass/16)-1;
+       if ((idx >=0) && (idx < LOG_TYPES) && (filter<16)) 
+               logfilter[idx] = filter; 
+}
+
+unsigned char AgentLog::get_filter(int logclass) const
+{
+       int idx = (logclass/16)-1;      
+       if ((idx >= 0) && (idx < LOG_TYPES)) { 
+               return logfilter[idx]; 
+       }
+       return 0;
+}
+
+const char* AgentLog::now(char* buf)
+{
+       if (buf == NULL) buf = static_buf;
+
+       time_t t;
+       time(&t);
+       struct tm *stm = localtime(&t);
+       if (stm)
+               strftime(buf, 18, "%Y%m%d.%H:%M:%S", localtime(&t));
+       else
+               buf[0] = 0;
+       return buf;
+}      
+
+/*static*/ const char* AgentLog::get_current_time() 
+{
+       char* buf = new char[18];
+        strcpy(buf, DefaultLog::log()->now());
+       return buf;
+}      
+
+
+/*------------------------ class AgentLogImpl -------------------------*/
+
+/**
+ * Default constructor. Log is directed to stdout.
+ */
+AgentLogImpl::AgentLogImpl(FILE* fp) : AgentLog()
+{
+       set_dest(fp);
+}
+
+/**
+ * Constructor with file name of a log file. Log is directed
+ * to the given file.
+ *
+ * @param fname - The file name of a log file.
+ */ 
+AgentLogImpl::AgentLogImpl(const char* fname) : AgentLog()
+{
+       set_dest(fname);
+}
+
+/**
+ * Destructor.
+ */
+AgentLogImpl::~AgentLogImpl()
+{
+       if (close_needed) fclose(logfile);
+}
+
+/**
+ * Set destination of logs to a given file.
+ * 
+ * @param fname - A file name. "" directs logs to stdout.
+ */
+void AgentLogImpl::set_dest(const char* fname)
+{
+       close_needed = FALSE;
+       if ((!fname) || (strlen(fname) == 0)) 
+               logfile = stdout;
+       else {
+               logfile = fopen(fname, "a");
+               if (logfile == NULL)
+                       logfile = stdout;
+               else
+                       close_needed = TRUE;
+       }
+}
+
+/**
+ * Set destination of logs to a given file.
+ * 
+ * @param fname - A pointer to an open log file. 0 directs logs to stdout.
+ */
+void AgentLogImpl::set_dest(FILE* fp)
+{
+       logfile = fp ? fp : stdout;
+       close_needed = FALSE;
+}
+
+/**
+ * Create a new LogEntry.
+ *
+ * @param t - The type of the log entry.
+ * @return A new instance of LogEntry (or of a derived class).
+ */
+LogEntry* AgentLogImpl::create_log_entry(unsigned char t) const
+{
+       return new LogEntryImpl(t);
+}
+
+/**
+ * Add a LogEntry to the receiver Log.
+ *
+ * @param log - A log entry.
+ * @return The receiver log itself.
+ */
+AgentLog& AgentLogImpl::operator+=(const LogEntry* log)
+{
+       fprintf(logfile, "%s\n", log->get_value());
+
+       // check if critical error
+       if ((log->get_class() == ERROR_LOG) && (log->get_level() == 0))
+       {
+         fprintf(logfile, "Exiting now\n");
+         raise(SIGTERM);
+       }
+
+       return *this;
+}
+
+
+// define the default logs
+
+#ifdef _THREADS
+#ifndef _WIN32THREADS
+#if !(defined (CPU) && CPU == PPC603)
+pthread_mutex_t logmutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+#endif
+#endif
+
+AgentLog* DefaultLog::instance = 0;
+LogEntry* DefaultLog::entry = 0;
+SnmpSynchronized DefaultLog::mutex;
+
+/*------------------------ class DefaultLog -------------------------*/
+
+void DefaultLog::cleanup() 
+{
+  mutex.lock(); 
+  if (instance) delete instance; 
+  instance = 0; 
+  mutex.unlock();
+}
+
+AgentLog* DefaultLog::init_ts(AgentLog* logger)
+{ 
+  AgentLog* r = instance;
+  if (!instance) { 
+    mutex.lock(); 
+    if (!instance) { 
+      instance = logger;
+      r = instance;
+    } 
+    mutex.unlock(); 
+  }
+  return r;
+}
+
+AgentLog* DefaultLog::log() 
+{ 
+  AgentLog* r = instance;
+  if (!r) {
+    r = new AgentLogImpl();
+    AgentLog* l = init_ts(r);
+    if (r != l) delete r;
+    r = l;
+  } 
+  return r; 
+}
diff --git a/3rdparty/snmp++/src/md5c.cpp b/3rdparty/snmp++/src/md5c.cpp
new file mode 100644 (file)
index 0000000..80140e4
--- /dev/null
@@ -0,0 +1,364 @@
+/*_############################################################################
+  _## 
+  _##  md5c.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+char md5c_cpp_version[]="#(@) SNMP++ $Id: md5c.cpp 43 2004-03-03 23:11:21Z katz $";
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm */
+
+/* Copyright (C) 1991, RSA Data Security, Inc. All rights reserved.
+
+   License to copy and use this software is granted provided that it
+   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+   Algorithm" in all material mentioning or referencing this software
+   or this function.
+
+   License is also granted to make and use derivative works provided
+   that such works are identified as "derived from the RSA Data
+   Security, Inc. MD5 Message-Digest Algorithm" in all material
+   mentioning or referencing the derived work.
+
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.
+
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.
+ */
+
+#include "snmp_pp/md5.h"
+
+#if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
+static void Encode PROTO_LIST ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST ((UINT4 *, const unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+   Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+    (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+    (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+    (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+    (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (MD5_CTX *context)
+{
+  context->count[0] = context->count[1] = 0;
+
+  /* Load magic initialization constants.
+   */
+  context->state[0] = 0x67452301;
+  context->state[1] = 0xefcdab89;
+  context->state[2] = 0x98badcfe;
+  context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest operation,
+     processing another message block, and updating the context.
+ */
+void MD5Update (MD5_CTX *context,                /* context */
+               const unsigned char *input,      /* input block */
+               const unsigned int inputLen)     /* length of input block */
+{
+  unsigned int i, index, partLen;
+
+  /* Compute number of bytes mod 64 */
+  index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+  /* Update number of bits */
+  if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3))
+    context->count[1]++;
+  context->count[1] += ((UINT4)inputLen >> 29);
+
+  partLen = 64 - index;
+
+  /* Transform as many times as possible.
+   */
+  if (inputLen >= partLen) {
+    MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+    MD5Transform (context->state, context->buffer);
+
+    for (i = partLen; i + 63 < inputLen; i += 64)
+      MD5Transform (context->state, &input[i]);
+
+    index = 0;
+  }
+  else
+    i = 0;
+
+  /* Buffer remaining input */
+  MD5_memcpy
+    ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+     the message digest and zeroizing the context.
+ */
+void MD5Final (
+unsigned char digest[16],                                 /* message digest */
+MD5_CTX *context)                                                /* context */
+{
+  unsigned char bits[8];
+  unsigned int index, padLen;
+
+  /* Save number of bits */
+  Encode (bits, context->count, 8);
+
+  /* Pad out to 56 mod 64.
+   */
+  index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+  padLen = (index < 56) ? (56 - index) : (120 - index);
+  MD5Update (context, PADDING, padLen);
+
+  /* Append length (before padding) */
+  MD5Update (context, bits, 8);
+
+  /* Store state in digest */
+  Encode (digest, context->state, 16);
+
+  /* Zeroize sensitive information.
+   */
+  MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (
+UINT4 state[4],
+const unsigned char block[64])
+{
+  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+  Decode (x, block, 64);
+
+  /* Round 1 */
+  FF ( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+  FF ( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+  FF ( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+  FF ( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+  FF ( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+  FF ( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+  FF ( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+  FF ( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+  FF ( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+  FF ( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+  FF ( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+  FF ( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+  FF ( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+  FF ( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+  FF ( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+  FF ( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+  /* Round 2 */
+  GG ( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+  GG ( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+  GG ( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+  GG ( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+  GG ( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+  GG ( d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+  GG ( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+  GG ( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+  GG ( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+  GG ( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+  GG ( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+  GG ( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+  GG ( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+  GG ( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+  GG ( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+  GG ( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+  /* Round 3 */
+  HH ( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+  HH ( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+  HH ( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+  HH ( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+  HH ( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+  HH ( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+  HH ( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+  HH ( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+  HH ( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+  HH ( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+  HH ( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+  HH ( b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+  HH ( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+  HH ( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+  HH ( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+  HH ( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+  II ( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+  II ( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+  II ( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+  II ( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+  II ( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+  II ( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+  II ( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+  II ( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+  II ( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+  II ( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+  II ( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+  II ( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+  II ( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+  II ( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+  II ( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+  II ( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+  state[0] += a;
+  state[1] += b;
+  state[2] += c;
+  state[3] += d;
+
+  /* Zeroize sensitive information.
+   */
+  MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+     a multiple of 4.
+ */
+static void Encode (
+                   unsigned char *output,
+                   UINT4 *input,
+                   unsigned int len)
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4) {
+    output[j] = (unsigned char)(input[i] & 0xff);
+    output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+    output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+    output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+  }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+     a multiple of 4.
+ */
+static void Decode (
+                   UINT4 *output,
+                   const unsigned char *input,
+                   unsigned int len)
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4)
+    output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+      (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+static void MD5_memcpy (
+                       POINTER output,
+                       POINTER input,
+                       unsigned int len)
+{
+  memcpy(output, input, len);
+}
+
+static void MD5_memset (
+                       POINTER output,
+                       int value,
+                       unsigned int len)
+{
+  memset(output, value, len);
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
diff --git a/3rdparty/snmp++/src/mp_v3.cpp b/3rdparty/snmp++/src/mp_v3.cpp
new file mode 100644 (file)
index 0000000..0ca4d98
--- /dev/null
@@ -0,0 +1,1523 @@
+/*_############################################################################
+  _## 
+  _##  mp_v3.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+char mp_v3_cpp_version[]="@(#) SNMP++ $Id: mp_v3.cpp 1686 2009-11-24 13:47:44Z katz $";
+
+#include <stdlib.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+#include "snmp_pp/v3.h"
+#include "snmp_pp/mp_v3.h"
+#include "snmp_pp/usm_v3.h"
+#include "snmp_pp/notifyqueue.h"
+#include "snmp_pp/snmpmsg.h"
+#include "snmp_pp/uxsnmp.h"
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/vb.h"
+#include "snmp_pp/log.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define MAX_MPMSGID 2147483647
+
+#define CACHE_LOCAL_REQ true
+#define CACHE_REMOTE_REQ false
+
+v3MP *v3MP::I = 0;
+
+// Use locking on access methods in an multithreaded environment.
+#ifdef _THREADS
+#define BEGIN_REENTRANT_CODE_BLOCK SnmpSynchronize auto_lock(lock)
+#define BEGIN_REENTRANT_CODE_BLOCK_CONST  \
+          SnmpSynchronize auto_lock(*(PP_CONST_CAST(SnmpSynchronized*, &lock)))
+#else
+#define BEGIN_REENTRANT_CODE_BLOCK
+#define BEGIN_REENTRANT_CODE_BLOCK_CONST
+#endif
+
+// ========================[ Engine id table ]=============================
+
+// Construct engine id table
+v3MP::EngineIdTable::EngineIdTable(int initial_size)
+{
+  if (initial_size < 1)
+    initial_size = 10;
+
+  if (!initialize_table(initial_size))
+  {
+    LOG_BEGIN(ERROR_LOG | 0);
+    LOG("v3MP::EngineIdTable: Error creating empty table.");
+    LOG_END;
+  }
+}
+
+// Destruct enigne id table
+v3MP::EngineIdTable::~EngineIdTable()
+{
+  if (table)
+    delete [] table;
+  table = 0;
+}
+
+// Add an entry to the table.
+int v3MP::EngineIdTable::add_entry(const OctetStr &engine_id,
+                                   const OctetStr &host, int port)
+{
+  if (!table)
+    return SNMPv3_MP_NOT_INITIALIZED;
+
+  LOG_BEGIN(INFO_LOG | 9);
+  LOG("v3MP::EngineIdTable: adding new entry (id) (host) (port)");
+  LOG(engine_id.get_printable());
+  LOG(host.get_printable());
+  LOG(port);
+  LOG_END;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i = 0; i < entries; i++)
+    if (((table[i].port == port) &&
+         (table[i].host == host)) ||
+       (table[i].engine_id == engine_id))
+    {
+      LOG_BEGIN(INFO_LOG | 2);
+      LOG("v3MP::EngineIdTable: replace entry (old id) (old host) (old port) (id) (host) (port)");
+      LOG(table[i].engine_id.get_printable());
+      LOG(table[i].host.get_printable());
+      LOG(table[i].port);
+      LOG(engine_id.get_printable());
+      LOG(host.get_printable());
+      LOG(port);
+      LOG_END;
+
+      table[i].engine_id = engine_id;
+      table[i].host = host;
+      table[i].port = port;
+
+      return SNMPv3_MP_OK;         // host is in table
+    }
+
+  table[entries].engine_id = engine_id;
+  table[entries].host = host;
+  table[entries].port = port;
+
+  entries++;
+  if (entries == max_entries)
+  {
+    // resize Table
+    struct Entry_T *tmp;
+    tmp = new struct Entry_T[2 * max_entries];
+    if (!tmp)
+    {
+      entries--;
+      return SNMPv3_MP_ERROR;
+    }
+    for (int i = 0; i < entries; i++)
+      tmp[i] = table[i];
+
+    delete [] table;
+    table = tmp;
+    max_entries *= 2;
+  }
+
+  return SNMPv3_MP_OK;
+}
+
+// Get the engine_id of the SNMP entity at the given host/port.
+int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
+                                   const OctetStr &hostport) const
+{
+  int port;
+  char host[MAX_HOST_NAME_LENGTH + 1];
+  char *ptr;
+
+  /* Check length */
+  if (hostport.len() > MAX_HOST_NAME_LENGTH)
+    return SNMPv3_MP_ERROR;
+
+  /* split up port from hostport */
+  strcpy(host, hostport.get_printable());
+
+  ptr = strstr((char*)host,"/");
+  if (!ptr)
+    return SNMPv3_MP_ERROR;
+
+  *ptr = '\0';
+  port = atol(ptr + 1);
+
+  /* Check for IPv6 address with [] */
+  if (host[0] == '[')
+  {
+    if (*(ptr -1) == ']')
+    {
+      *(ptr-1) = '\0';
+      return get_entry(engine_id, &(host[1]), port);
+    }
+    else
+      return SNMPv3_MP_ERROR;
+  }
+  return get_entry(engine_id, host, port);
+}
+
+// Get the engineID of the SNMP entity at the given host/port.
+int v3MP::EngineIdTable::get_entry(OctetStr &engine_id,
+                                   const OctetStr &host, int port) const
+{
+  if (!table)
+    return SNMPv3_MP_NOT_INITIALIZED;
+
+  BEGIN_REENTRANT_CODE_BLOCK_CONST;
+
+  int i, found = 0;
+
+  for (i = 0; i < entries; i++)
+    if ((table[i].port == port) &&
+        (table[i].host == host))
+    {
+      found=1;
+      break;
+    }
+  if (!found)
+  {
+    LOG_BEGIN(INFO_LOG | 4);
+    LOG("v3MP::EngineIdTable: Dont know engine id for (host) (port)");
+    LOG(host.get_printable());
+    LOG(port);
+    LOG_END;
+
+    return SNMPv3_MP_ERROR;
+  }
+
+  engine_id = table[i].engine_id;
+
+  return SNMPv3_MP_OK;
+}
+
+// Remove all entries from the engine id table.
+int v3MP::EngineIdTable::reset()
+{
+  if (!table)
+    return SNMPv3_MP_NOT_INITIALIZED;
+
+  LOG_BEGIN(INFO_LOG | 1);
+  LOG("v3MP::EngineIdTable: Resetting table.");
+  LOG_END;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  entries = 0;
+
+  return SNMPv3_MP_OK;
+}
+
+// Remove the given engine id from the table.
+int v3MP::EngineIdTable::delete_entry(const OctetStr &engine_id)
+{
+  if (!table)
+    return SNMPv3_MP_NOT_INITIALIZED;
+
+  int i, found = 0;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (i = 0; i < entries; i++)
+    if (table[i].engine_id == engine_id)
+    {
+      found=1;
+      break;
+    }
+  if (!found)
+  {
+    LOG_BEGIN(WARNING_LOG | 4);
+    LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (engine id)");
+    LOG(engine_id.get_printable());
+    LOG_END;
+
+    return SNMPv3_MP_ERROR;
+  }
+
+  /* i is the entry to remove */
+  if (i != entries - 1)
+    table[i] = table[entries-1];
+
+  entries--;
+
+  return SNMPv3_MP_OK;
+}
+
+// Remove the entry for the given address/port from the table.
+int v3MP::EngineIdTable::delete_entry(const OctetStr &host, int port)
+{
+  if (!table)
+    return SNMPv3_MP_NOT_INITIALIZED;
+
+  int i, found = 0;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (i = 0; i < entries; i++)
+    if ((table[i].port == port) &&
+        (table[i].host == host))
+    {
+      found=1;
+      break;
+    }
+  if (!found)
+  {
+    LOG_BEGIN(WARNING_LOG | 4);
+    LOG("v3MP::EngineIdTable: cannot remove nonexisting entry (host) (port)");
+    LOG(host.get_printable());
+    LOG(port);
+    LOG_END;
+
+    return SNMPv3_MP_ERROR;
+  }
+
+  /* i is the entry to remove */
+  if (i != entries - 1)
+    table[i] = table[entries-1];
+
+  entries--;
+
+  return SNMPv3_MP_OK;
+}
+
+int v3MP::EngineIdTable::initialize_table(const int size)
+{
+  table = new struct Entry_T[size];
+  entries = 0;
+  if (!table)
+  {
+    max_entries = 0;
+    return FALSE;
+  }
+  max_entries = size;
+  return TRUE;
+}
+
+// ===============================[ Cache ]==================================
+
+v3MP::Cache::Cache()
+{
+  // init cache
+  table = new struct Entry_T[5];
+  if (!table)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("v3MP::Cache: could not create empty table.");
+    LOG_END;
+
+    max_entries = 0;
+  }
+  else
+    max_entries = 5;
+
+  entries = 0;
+}
+
+v3MP::Cache::~Cache()
+{
+  if (table)
+  {
+    for (int i = 0; i < entries; i++)
+      usm->delete_sec_state_reference(table[i].sec_state_ref);
+    entries = 0;
+    delete [] table;
+    table = 0;
+    max_entries = 0;
+  }
+}
+
+// Add an entry to the cache.
+int v3MP::Cache::add_entry(int msg_id, unsigned long req_id,
+                           const OctetStr &sec_engine_id,
+                           int sec_model,
+                           const OctetStr &sec_name,
+                           int sec_level,
+                           const OctetStr &context_engine_id,
+                           const OctetStr &context_name,
+                           struct SecurityStateReference *sec_state_ref,
+                           int error_code, bool local_request)
+{
+  if (!table)
+    return SNMPv3_MP_ERROR;
+
+  LOG_BEGIN(INFO_LOG | 8);
+  LOG("v3MP::Cache: adding new entry (n) (msg id) (req id) (type)");
+  LOG(entries);
+  LOG(msg_id);
+  LOG(req_id);
+  LOG(local_request ? "local" : "remote");
+  LOG_END;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i = 0; i < entries; i++)
+    if ((table[i].msg_id == msg_id) &&
+        (table[i].req_id == req_id) &&
+        (table[i].local_request == local_request) &&
+        (table[i].sec_engine_id == sec_engine_id) &&
+        (table[i].sec_model == sec_model) &&
+        (table[i].sec_name == sec_name) &&
+        (table[i].sec_level == sec_level) &&
+        (table[i].context_engine_id == context_engine_id) &&
+        (table[i].context_name == context_name))
+    {
+      LOG_BEGIN(WARNING_LOG | 3);
+      LOG("v3MP::Cache: Dont add doubled entry (msg id) (req id)");
+      LOG(msg_id);
+      LOG(req_id);
+      LOG_END;
+
+      return SNMPv3_MP_DOUBLED_MESSAGE;
+    }
+
+  table[entries].msg_id            = msg_id;
+  table[entries].req_id            = req_id;
+  table[entries].local_request     = local_request;
+  table[entries].sec_engine_id     = sec_engine_id;
+  table[entries].sec_model         = sec_model;
+  table[entries].sec_name          = sec_name;
+  table[entries].sec_level         = sec_level;
+  table[entries].context_engine_id = context_engine_id;
+  table[entries].context_name      = context_name;
+  table[entries].sec_state_ref     = sec_state_ref;
+  table[entries].error_code        = error_code;
+
+  entries++;
+  if (entries == max_entries)
+  {
+    // resize Table
+    struct Entry_T *tmp;
+    tmp = new struct Entry_T[2 * max_entries];
+    if (!tmp)
+    {
+      entries--;
+      return SNMPv3_MP_ERROR;
+    }
+    for (int i=0; i<entries;i++)
+      tmp[i] = table[i];
+    delete [] table;
+    table = tmp;
+    max_entries *= 2;
+  }
+  return SNMPv3_MP_OK;
+}
+
+// Search the cache for a message id, return the error code and
+int v3MP::Cache::get_entry(int msg_id, bool local_request, int *error_code,
+                           struct SecurityStateReference **sec_state_ref)
+{
+  if (!table) return SNMPv3_MP_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i=0; i < entries; i++)
+  {
+    if ((msg_id == table[i].msg_id) &&
+        (local_request == table[i].local_request))
+    {
+      *error_code = table[i].error_code;
+      *sec_state_ref = table[i].sec_state_ref;
+      entries--;
+
+      LOG_BEGIN(INFO_LOG | 8);
+      LOG("v3MP::Cache: Found entry (n) (msg id) (type)");
+      LOG(i);
+      LOG(msg_id);
+      LOG(local_request ? "local" : "remote");
+      LOG_END;
+
+      if (entries > i)
+      {
+        table[i] = table[entries];
+
+       LOG_BEGIN(INFO_LOG | 10);
+       LOG("v3MP::Cache: Moving entry (from) (to)");
+       LOG(entries);
+       LOG(i);
+       LOG_END;
+      }
+      return SNMPv3_MP_OK;
+    }
+  }
+
+  LOG_BEGIN(WARNING_LOG | 5);
+  LOG("v3MP::Cache: Entry not found (msg id) (type)");
+  LOG(msg_id);
+  LOG(local_request ? "local" : "remote");
+  LOG_END;
+
+  return SNMPv3_MP_ERROR;
+}
+
+// Delete the entry with the given request id from the cache.
+void v3MP::Cache::delete_entry(unsigned long req_id, bool local_request)
+{
+  if (!table) return;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i=0; i<entries; i++)
+    if ((table[i].req_id == req_id) &&
+        (table[i].local_request == local_request))
+    {
+      LOG_BEGIN(INFO_LOG | 8);
+      LOG("v3MP::Cache: Delete unprocessed entry (n) (req id) (type)");
+      LOG(i);
+      LOG(req_id);
+      LOG(local_request ? "local" : "remote");
+      LOG_END;
+
+      usm->delete_sec_state_reference(table[i].sec_state_ref);
+      entries--;
+      if (entries > i)
+      {
+        table[i] = table[entries];
+
+       LOG_BEGIN(INFO_LOG | 10);
+       LOG("v3MP::Cache: Moving entry (from) (to)");
+       LOG(entries);
+       LOG(i);
+       LOG_END;
+      }
+      return;
+    }
+
+  LOG_BEGIN(INFO_LOG | 8);
+  LOG("v3MP::Cache: Entry to delete not found (req id) (type)");
+  LOG(req_id);
+  LOG(local_request ? "local" : "remote");
+  LOG_END;
+
+  return;
+}
+
+// Delete the entry with the given request ans message id from the cache.
+void v3MP::Cache::delete_entry(unsigned long req_id, int msg_id,
+                              bool local_request)
+{
+  if (!table) return;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i=0; i<entries; i++)
+    if ((table[i].req_id == req_id) &&
+       (table[i].msg_id == msg_id) &&
+        (table[i].local_request == local_request))
+    {
+      LOG_BEGIN(INFO_LOG | 8);
+      LOG("v3MP::Cache: Delete unprocessed entry (n) (req id) (msg id) (type)");
+      LOG(i);
+      LOG(req_id);
+      LOG(msg_id);
+      LOG(local_request ? "local" : "remote");
+      LOG_END;
+
+      usm->delete_sec_state_reference(table[i].sec_state_ref);
+      entries--;
+      if (entries > i)
+      {
+        table[i] = table[entries];
+
+       LOG_BEGIN(INFO_LOG | 10);
+       LOG("v3MP::Cache: Moving entry (from) (to)");
+       LOG(entries);
+       LOG(i);
+       LOG_END;
+      }
+      return;
+    }
+
+  LOG_BEGIN(INFO_LOG | 8);
+  LOG("v3MP::Cache: Entry to delete not found (req id) (msg id) (type)");
+  LOG(req_id);
+  LOG(msg_id);
+  LOG(local_request ? "local" : "remote");
+  LOG_END;
+
+  return;
+}
+
+// Search the cache for a message id, return it and remove it from the cache
+int v3MP::Cache::get_entry(int searchedID, bool local_request,
+                           struct Cache::Entry_T *res)
+{
+  if ((!table) || (!res)) return SNMPv3_MP_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i=0; i < entries; i++)
+    if ((table[i].msg_id == searchedID) &&
+        (table[i].local_request == local_request))
+    {
+      res->msg_id            = table[i].msg_id;
+      res->req_id            = table[i].req_id;
+      res->local_request     = table[i].local_request;
+      res->sec_engine_id     = table[i].sec_engine_id;
+      res->sec_model         = table[i].sec_model;
+      res->sec_name          = table[i].sec_name;
+      res->sec_level         = table[i].sec_level;
+      res->context_engine_id = table[i].context_engine_id;
+      res->context_name      = table[i].context_name;
+      res->sec_state_ref     = table[i].sec_state_ref;
+      res->error_code        = table[i].error_code;
+
+      LOG_BEGIN(INFO_LOG | 8);
+      LOG("v3MP::Cache: Found entry (n) (msg id) (type)");
+      LOG(i);
+      LOG(searchedID);
+      LOG(local_request ? "local" : "remote");
+      LOG_END;
+
+      entries--;
+
+      if (entries > i)
+      {
+        table[i] = table[entries];
+
+       LOG_BEGIN(INFO_LOG | 10);
+       LOG("v3MP::Cache: Moving entry (from) (to)");
+       LOG(entries);
+       LOG(i);
+       LOG_END;
+      }
+      return SNMPv3_MP_OK;
+    }
+
+  LOG_BEGIN(WARNING_LOG | 5);
+  LOG("v3MP::Cache: Entry not found (msg id) (type)");
+  LOG(searchedID);
+  LOG(local_request ? "local" : "remote");
+  LOG_END;
+
+  return SNMPv3_MP_ERROR;
+}
+
+void v3MP::Cache::delete_content(struct v3MP::Cache::Entry_T &ce)
+{
+  if (ce.sec_state_ref)
+    usm->delete_sec_state_reference(ce.sec_state_ref);
+}
+
+// ==========================[ class v3MP ]===============================
+
+// Initialize the v3MP.
+v3MP::v3MP(const OctetStr& snmpEngineID,
+           unsigned int engineBoots, int &construct_status)
+  : own_engine_id(0), usm(0)
+{
+  if (I)
+  {
+    debugprintf(0, "v3MP: You must not create two objects of this class!");
+    construct_status = SNMPv3_MP_ERROR;
+    return;
+  }
+
+  I = this;
+
+  snmpUnknownSecurityModels = 0;
+  snmpInvalidMsgs = 0;
+  snmpUnknownPDUHandlers = 0;
+
+  int length = snmpEngineID.len();
+  if (length > MAXLENGTH_ENGINEID)
+    length = MAXLENGTH_ENGINEID;
+
+  own_engine_id = v3strcpy(snmpEngineID.data(), length);
+  own_engine_id_len = length;
+  own_engine_id_oct = snmpEngineID;
+
+  int result;
+  usm = new USM(engineBoots, snmpEngineID, this, &cur_msg_id, result);
+
+  if (cur_msg_id >= MAX_MPMSGID)
+    cur_msg_id = 1;
+
+  if ((!own_engine_id) || (!usm) || (result != SNMPv3_USM_OK))
+  {
+    construct_status = SNMPv3_MP_ERROR;
+    return;
+  }
+
+  cache.set_usm(usm);
+  construct_status = SNMPv3_MP_OK;
+}
+
+// Free all allocated ressources of the v3MP.
+v3MP::~v3MP()
+{
+  if (own_engine_id)
+    delete [] own_engine_id;
+  own_engine_id = 0;
+
+  if (usm)
+  {
+    delete usm;
+    usm = 0;
+  }
+
+  I = 0;
+}
+
+// Remove all occurences of this engine id from v3MP and USM.
+int v3MP::remove_engine_id(const OctetStr &engine_id)
+{
+  int retval1, retval2;
+
+  retval1 = engine_id_table.delete_entry(engine_id);
+
+  retval2 = usm->remove_engine_id(engine_id);
+
+  if ((retval1 == SNMPv3_MP_NOT_INITIALIZED) ||
+      (retval2 == SNMPv3_USM_ERROR))
+    return SNMPv3_MP_NOT_INITIALIZED;
+
+  return SNMPv3_MP_OK;
+}
+
+// Send a report message.
+int v3MP::send_report(unsigned char* scopedPDU, int scopedPDULength,
+                     struct snmp_pdu *pdu, int errorCode, int sLevel,
+                     int sModel, OctetStr &sName,
+                     UdpAddress &destination, Snmp *snmp_session)
+{
+  debugprintf(2, "v3MP::send_report: Sending report message.");
+
+  unsigned char *data;
+  int dataLength;
+  int pdu_type = 0;
+  unsigned char cEngineID[MAXLENGTH_ENGINEID+1];
+  unsigned char cName[MAXLENGTH_CONTEXT_NAME+1];
+  int cEngineIDLength = MAXLENGTH_ENGINEID+1;
+  int cNameLength = MAXLENGTH_CONTEXT_NAME+1;
+
+  if (scopedPDULength != MAX_SNMP_PACKET)
+  {
+    // try to get scopedPDU and PDU
+    data = asn1_parse_scoped_pdu(scopedPDU, &scopedPDULength,
+                                cEngineID, &cEngineIDLength,
+                                cName, &cNameLength);
+    if (data == NULL) {
+      debugprintf(1, "mp: Error while trying to parse  scopedPDU!");
+      cEngineID[0] = '\0';
+      cEngineIDLength = 0;
+      cName[0] = '\0';
+      cNameLength = 0;
+      // Dont send encrypted report if decryption failed:
+      if (sLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
+        sLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV;
+    }
+    else { // data != NULL
+      dataLength = scopedPDULength;
+
+      // parse data of scopedPDU
+      snmp_parse_data_pdu(pdu, data, dataLength);
+      pdu_type = pdu->command;
+
+      if (!data) {
+        debugprintf(0, "mp: Error while trying to parse PDU!");
+      }
+    } // end of: if (data == NULL)
+  } // end if (scopedPDULength != MAX_SNMP_PACKET)
+  else { // scopedPDULength == MAX_SNMP_PACKET
+    cEngineID[0] = '\0';
+    cEngineIDLength = 0;
+    cName[0] = '\0';
+    cNameLength = 0;
+    pdu->reqid = 0;
+  }
+
+  clear_pdu(pdu);   // Clear pdu and free all content
+
+  debugprintf(4, "pdu->reqid = %ld",pdu->reqid);
+  pdu->errstat = 0;
+  pdu->errindex = 0;
+  pdu->command = REPORT_MSG;
+
+  Vb counterVb;
+  Oid counterOid;
+  SmiLPOID smioid;
+  SmiVALUE smival;
+
+  switch (errorCode) {
+    case SNMPv3_MP_INVALID_MESSAGE:
+    case SNMPv3_USM_PARSE_ERROR: {
+      counterVb.set_oid(oidSnmpInvalidMsgs);
+      counterVb.set_value(Counter32(get_stats_invalid_msgs()));
+      break;
+    }
+    case SNMPv3_USM_NOT_IN_TIME_WINDOW:
+    case SNMPv3_MP_NOT_IN_TIME_WINDOW: {
+      counterVb.set_oid(oidUsmStatsNotInTimeWindows);
+      counterVb.set_value(Counter32(usm->get_stats_not_in_time_windows()));
+      break;
+    }
+    case SNMPv3_USM_DECRYPTION_ERROR: {
+      counterVb.set_oid(oidUsmStatsDecryptionErrors);
+      counterVb.set_value(Counter32(usm->get_stats_decryption_errors()));
+      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+      break;
+    }
+    case SNMPv3_USM_AUTHENTICATION_ERROR:
+    case SNMPv3_USM_AUTHENTICATION_FAILURE: {
+      counterVb.set_oid(oidUsmStatsWrongDigests);
+      counterVb.set_value(Counter32(usm->get_stats_wrong_digests()));
+      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+      break;
+    }
+    case SNMPv3_USM_UNKNOWN_ENGINEID:
+    case SNMPv3_MP_INVALID_ENGINEID: {
+      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+      counterVb.set_oid(oidUsmStatsUnknownEngineIDs);
+      counterVb.set_value(Counter32(usm->get_stats_unknown_engine_ids()));
+      break;
+    }
+    case SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL: {
+      counterVb.set_oid(oidSnmpUnknownSecurityModels);
+      counterVb.set_value(Counter32(get_stats_unknown_security_models()));
+      sModel = SNMP_SECURITY_MODEL_USM;
+      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+    break;
+    }
+    case SNMPv3_USM_UNKNOWN_SECURITY_NAME: {
+      counterVb.set_oid(oidUsmStatsUnknownUserNames);
+      counterVb.set_value(Counter32(usm->get_stats_unknown_user_names()));
+      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+      debugprintf(2, "Report: SecurityName: %s",sName.get_printable());
+      break;
+    }
+    case SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL: {
+      counterVb.set_oid(oidUsmStatsUnsupportedSecLevels);
+      counterVb.set_value(Counter32(usm->get_stats_unsupported_sec_levels()));
+      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+      break;
+    }
+    default: {
+      counterVb.set_oid(oidSnmpInvalidMsgs);
+      counterVb.set_value(Counter32(get_stats_invalid_msgs()));
+      sModel = SNMP_SECURITY_MODEL_USM;
+      sLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+      sName.set_data(0, 0);
+
+      debugprintf(2, "ErrorCode was %i in snmp_parse", errorCode);
+    }
+  } // end switch
+
+  counterVb.get_oid(counterOid);
+  smioid = counterOid.oidval();
+
+  int status = convertVbToSmival(counterVb, &smival);
+  if (status != SNMP_CLASS_SUCCESS) {
+    return SNMPv3_MP_ERROR;
+  }
+  snmp_add_var(pdu, smioid->ptr,
+               (int) smioid->len, &smival);
+  freeSmivalDescriptor(&smival);
+
+  Buffer<unsigned char> sendbuffer(MAX_SNMP_PACKET);
+  int sendbufferlen= MAX_SNMP_PACKET;
+  status = snmp_build( pdu, sendbuffer.get_ptr(), &sendbufferlen,
+                      own_engine_id_oct, sName, sModel, sLevel,
+                      OctetStr(cEngineID, cEngineIDLength),
+                      OctetStr(cName, cNameLength));
+  if (status != SNMPv3_MP_OK) {
+    debugprintf(2, "v3MP::send_report: error serializing message (mpSnmpBuild returns: %i).", status);
+    return SNMPv3_MP_ERROR;
+  }
+  SnmpSocket send_fd = INVALID_SOCKET;
+  if (pdu_type == sNMP_PDU_INFORM)
+  {
+    debugprintf(4, "Received a snmpInform pdu.");
+    if (snmp_session->get_eventListHolder()->notifyEventList())
+      send_fd = snmp_session->get_eventListHolder()->notifyEventList()->get_notify_fd();
+  }
+
+  status = snmp_session->send_raw_data(sendbuffer.get_ptr(),
+                                       (size_t)sendbufferlen,// pdu to send
+                                      destination,          // target address
+                                      send_fd);             // the fd to use
+  if ( status != 0)
+  {
+    debugprintf(1, "v3MP::send_report: error sending message (%i)", status);
+    return SNMPv3_MP_ERROR;
+  }
+  debugprintf(3, "v3MP::send_report: Report sent.");
+  return SNMPv3_MP_OK;
+}
+
+// Parse the given buffer as a SNMPv3-Message.
+int v3MP::snmp_parse(Snmp *snmp_session,
+                     struct snmp_pdu *pdu,
+                     unsigned char *inBuf,
+                     int inBufLength,
+                     OctetStr &securityEngineID,
+                     OctetStr &securityName,
+                     OctetStr &contextEngineID,
+                     OctetStr &contextName,
+                     long     &securityLevel,
+                     long     &msgSecurityModel,
+                     snmp_version &spp_version,
+                     UdpAddress from_address)
+{
+  debugprintf(3, "mp is parsing incoming message:");
+  debughexprintf(25, inBuf, inBufLength);
+
+  if (inBufLength > MAX_SNMP_PACKET)
+    return  SNMPv3_MP_ERROR;
+
+  unsigned char type;
+  long version;
+  int origLength = inBufLength;
+  unsigned char *inBufPtr = inBuf;
+  long msgID, msgMaxSize;
+  unsigned char msgFlags;
+  Buffer<unsigned char> msgSecurityParameters(MAX_SNMP_PACKET);
+  Buffer<unsigned char> msgData(MAX_SNMP_PACKET);
+  int msgSecurityParametersLength = inBufLength,   msgDataLength = inBufLength;
+  Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
+  int scopedPDULength = MAX_SNMP_PACKET;
+  long  maxSizeResponseScopedPDU = 0;
+  struct SecurityStateReference *securityStateReference = NULL;
+  int securityParametersPosition;
+  int rc;
+  int errorCode = 0;
+
+  // get the type
+  inBuf = asn_parse_header( inBuf, &inBufLength, &type);
+  if (inBuf == NULL){
+    debugprintf(0, "snmp_parse: bad header");
+    return SNMPv3_MP_PARSE_ERROR;
+  }
+
+  if (type != (ASN_SEQ_CON)){
+    debugprintf(0, "snmp_parse: wrong auth header type");
+    return SNMPv3_MP_PARSE_ERROR;
+  }
+
+  if (origLength != inBufLength + (inBuf - inBufPtr)) {
+    debugprintf(0, "snmp_parse: wrong length of received packet");
+    return SNMPv3_MP_PARSE_ERROR;
+  }
+
+  // get the version
+  inBuf = asn_parse_int(inBuf, &inBufLength, &type, &version);
+  if (inBuf == NULL){
+    debugprintf(0, "snmp_parse: bad parse of version");
+    return SNMPv3_MP_PARSE_ERROR;
+  }
+
+  debugprintf(3, "Parsed length(%x), version(0x%lx)", inBufLength, version);
+
+  if ( version != SNMP_VERSION_3 )
+    return SNMPv3_MP_PARSE_ERROR;
+
+  spp_version = (snmp_version) version;
+
+  inBuf = asn1_parse_header_data(inBuf, &inBufLength,
+                                &msgID, &msgMaxSize,
+                                &msgFlags, &msgSecurityModel);
+
+  if (inBuf == NULL){
+    debugprintf(0, "snmp_parse: bad parse of msgHeaderData");
+    return SNMPv3_MP_PARSE_ERROR;
+  }
+
+  pdu->msgid = msgID;
+  if ((msgMaxSize < 484) || (msgMaxSize > 0x7FFFFFFF)) {
+    debugprintf(0, "snmp_parse: bad parse of msgMaxSize");
+    return SNMPv3_MP_PARSE_ERROR;
+  }
+
+  // do not allow larger messages than this entity can handle
+  if (msgMaxSize > MAX_SNMP_PACKET) msgMaxSize = MAX_SNMP_PACKET;
+  pdu->maxsize_scopedpdu = msgMaxSize;
+
+  inBuf = asn_parse_string( inBuf, &inBufLength, &type,
+                            msgSecurityParameters.get_ptr(),
+                            &msgSecurityParametersLength);
+
+  if (inBuf == NULL){
+    debugprintf(0, "snmp_parse: bad parse of msgSecurityParameters");
+    return SNMPv3_MP_PARSE_ERROR;
+  }
+
+  securityParametersPosition= SAFE_INT_CAST(inBuf - inBufPtr) - msgSecurityParametersLength;
+
+  // the rest of the message is passed directly to the security module
+
+  msgDataLength = origLength - SAFE_INT_CAST(inBuf - inBufPtr);
+  memcpy(msgData.get_ptr(), inBuf, msgDataLength);
+
+  debugprintf(3, "Parsed msgdata length(0x%x), "
+             "msgSecurityParameters length(0x%x)", msgDataLength,
+             msgSecurityParametersLength);
+
+  switch (msgFlags & 0x03) {
+    case 3:  { securityLevel = SNMP_SECURITY_LEVEL_AUTH_PRIV;     break;}
+    case 0:  { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV; break;}
+    case 1:  { securityLevel = SNMP_SECURITY_LEVEL_AUTH_NOPRIV;   break;}
+    default: { securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+               snmpInvalidMsgs++;
+               // do not send back report
+               return SNMPv3_MP_INVALID_MESSAGE;
+               break;
+             }
+  }
+
+  bool reportableFlag;
+
+  if (msgFlags & 0x04) reportableFlag = TRUE;
+  else                 reportableFlag = FALSE;
+
+  securityStateReference = usm->get_new_sec_state_reference();
+  if (!securityStateReference)
+    return SNMPv3_MP_ERROR;
+
+  switch (msgSecurityModel) {
+    case SNMP_SECURITY_MODEL_USM:
+      {
+        rc = usm->process_msg(
+                           msgMaxSize,
+                           msgSecurityParameters.get_ptr(),
+                          msgSecurityParametersLength,
+                           securityParametersPosition,
+                           securityLevel,
+                           inBufPtr, origLength, //wholeMsg
+                           msgData.get_ptr(), msgDataLength,
+                           securityEngineID,
+                           securityName,
+                           scopedPDU.get_ptr(), &scopedPDULength,
+                           &maxSizeResponseScopedPDU,
+                           securityStateReference,
+                          from_address);
+        pdu->maxsize_scopedpdu = maxSizeResponseScopedPDU;
+        if (rc != SNMPv3_USM_OK) {
+          if (rc == SNMPv3_USM_NOT_IN_TIME_WINDOW) {
+            errorCode = SNMPv3_MP_NOT_IN_TIME_WINDOW;
+          }
+          else {
+            // error handling! rfc2262 page 31
+            debugprintf(0, "mp: error while executing USM::process_msg");
+            errorCode = rc;
+          }
+        }
+        if (errorCode != SNMPv3_USM_PARSE_ERROR)
+          if (securityEngineID.len() == 0)
+            errorCode = SNMPv3_MP_INVALID_ENGINEID;
+        break;
+      }
+    default: {
+        snmpUnknownSecurityModels++;
+       usm->delete_sec_state_reference(securityStateReference);
+        debugprintf(0, "SecurityModel of incomming Message not supported!");
+        // Message should be dropped without a report
+        return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
+      }
+  }
+  // process scopedPDU
+  debughexcprintf(21, "scoped PDU", scopedPDU.get_ptr(), scopedPDULength);
+
+  unsigned char *scopedPDUPtr= scopedPDU.get_ptr();
+  unsigned char tmp_contextEngineID[MAXLENGTH_ENGINEID];
+  unsigned char tmp_contextName[MAXLENGTH_CONTEXT_NAME];
+  int tmp_contextEngineIDLength = MAXLENGTH_ENGINEID;
+  int tmp_contextNameLength     = MAXLENGTH_CONTEXT_NAME;
+
+  unsigned char *data;
+  int dataLength;
+
+  debugprintf(1,"ErrorCode is %i",errorCode);
+
+  if (!errorCode) {
+    data = asn1_parse_scoped_pdu(scopedPDUPtr, &scopedPDULength,
+                                tmp_contextEngineID,
+                                &tmp_contextEngineIDLength,
+                                tmp_contextName, &tmp_contextNameLength);
+    if (data == NULL) {
+      debugprintf(0, "mp: Error Parsing scopedPDU!");
+      usm->delete_sec_state_reference(securityStateReference);
+      return SNMPv3_MP_PARSE_ERROR;
+    }
+    dataLength = scopedPDULength;
+    contextEngineID.set_data(tmp_contextEngineID, tmp_contextEngineIDLength);
+    contextName.set_data(tmp_contextName, tmp_contextNameLength);
+
+    // parse data of scopedPDU
+    if (snmp_parse_data_pdu(pdu, data, dataLength) != SNMP_CLASS_SUCCESS) {
+      debugprintf(0, "mp: Error parsing PDU!");
+      usm->delete_sec_state_reference(securityStateReference);
+      return SNMPv3_MP_PARSE_ERROR;
+    }
+    if (SNMP_CLASS_SUCCESS != snmp_parse_vb(pdu, data, dataLength)) {
+      debugprintf(0, "mp: Error parsing Vb");
+      usm->delete_sec_state_reference(securityStateReference);
+      return SNMPv3_MP_PARSE_ERROR;
+    }
+    if ((tmp_contextEngineIDLength == 0) &&
+        ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
+         (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
+         (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG)  ||
+         (pdu->command == TRP2_REQ_MSG)))
+    {
+      //  RFC 2572 ï¿½ 4.2.2.1 (2a)
+      debugprintf(2, "mp: received request message with zero length"
+                  " contextEngineID -> unknownPduHandlers.");
+      inc_stats_unknown_pdu_handlers();
+      errorCode = SNMPv3_MP_UNKNOWN_PDU_HANDLERS;
+    }
+  }
+  if (errorCode) {
+    if ((reportableFlag) && (errorCode != SNMPv3_USM_PARSE_ERROR)) {
+      // error occured: prepare reportpdu in agent
+      cache.add_entry(msgID, pdu->reqid, securityEngineID,
+                      msgSecurityModel,
+                      securityName, securityLevel, "", "",
+                      securityStateReference, errorCode, CACHE_REMOTE_REQ);
+
+      send_report(scopedPDUPtr, scopedPDULength, pdu, errorCode,
+                 securityLevel, msgSecurityModel, securityName,
+                 from_address, snmp_session);
+      clear_pdu(pdu, true);   // Clear pdu and free all content AND IDs!
+    }
+    else {
+      usm->delete_sec_state_reference(securityStateReference);
+    }
+    return errorCode;
+  }
+
+  struct Cache::Entry_T centry;
+
+  if ((pdu->command == GET_RSP_MSG) || (pdu->command == REPORT_MSG)) {
+    rc = cache.get_entry(msgID, true, &centry);
+    if (rc != SNMPv3_MP_OK) {
+      // RFC 2572 ï¿½ 4
+      debugprintf(2, "Received rspMsg without outstanding request."
+                  " -> SnmpUnknownPduHandler");
+      usm->delete_sec_state_reference(securityStateReference);
+      inc_stats_unknown_pdu_handlers();
+      return SNMPv3_MP_UNKNOWN_PDU_HANDLERS;
+    }
+    if (((pdu->reqid == 0) || (pdu->reqid == 0x7fffffff))
+       && (pdu->command == REPORT_MSG))
+      pdu->reqid = centry.req_id;
+#ifdef BUGGY_REPORT_REQID
+    if ((pdu->reqid != centry.req_id) && (pdu->command == REPORT_MSG))
+    {
+      debugprintf(0, "WARNING: setting reqid of REPORT PDU (from) (to): (%ld) (%ld)",  pdu->reqid, centry.req_id);
+      pdu->reqid = centry.req_id;
+    }
+#endif
+  }
+
+  if (pdu->command == REPORT_MSG) {
+    // !! rfc2262 page 33
+
+    debugprintf(2, "*** Receiving a ReportPDU ***");
+    if (/*((securityEngineID != centry.sec_engine_id)
+         && (centry.sec_engine_id.len() != 0)) ||*/
+        ((msgSecurityModel != centry.sec_model)
+         && (msgSecurityModel != SNMP_SECURITY_MODEL_USM)) ||
+        ((securityName != centry.sec_name)
+         && (securityName.len() != 0)))
+    {
+      debugprintf(0, "Received report message doesn't match sent message!");
+      usm->delete_sec_state_reference(securityStateReference);
+      return SNMPv3_MP_MATCH_ERROR;
+    }
+    usm->delete_sec_state_reference(securityStateReference);
+    cache.delete_content(centry);
+    debugprintf(1, "mp finished (OK)");
+    return SNMPv3_MP_OK;
+  }
+
+  if (pdu->command == GET_RSP_MSG) {
+    if (((securityEngineID != centry.sec_engine_id)
+         && (centry.sec_engine_id.len() != 0)) ||
+        (msgSecurityModel != centry.sec_model) ||
+        (securityName != centry.sec_name) ||
+        (securityLevel != centry.sec_level) ||
+        ((contextEngineID != centry.context_engine_id)
+         && (centry.context_engine_id.len() != 0))||
+        ((contextName != centry.context_name)
+         && (centry.context_name.len() != 0))) {
+      debugprintf(0, "Received response message doesn't match sent message!");
+      usm->delete_sec_state_reference(securityStateReference);
+      cache.delete_content(centry);
+      return SNMPv3_MP_MATCH_ERROR;
+    }
+    usm->delete_sec_state_reference(securityStateReference);
+    cache.delete_content(centry);
+    debugprintf(1, "mp finished (OK)");
+    return SNMPv3_MP_OK;
+  }
+
+  if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
+      (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
+      (pdu->command == INFORM_REQ_MSG)) {
+    if (securityEngineID.len() == 0) {
+      debugprintf(2, "Received Message with engineID = 0.");
+    }
+    else {
+      if (!(unsignedCharCompare(securityEngineID.data(), securityEngineID.len(),
+                                own_engine_id, own_engine_id_len))) {
+        debugprintf(0, "snmp_parse: securityEngineID doesn't match own_engine_id.");
+       /* we are authoritative but engine id of message is wrong
+          if discovery in USM is enabled:
+          - remove automatically added illegal engine id from USM tables
+          - send a report
+       */
+       if (usm->is_discovery_enabled())
+       {
+         // TODO: try to remove engine id from USM
+         if (reportableFlag)
+         {
+           cache.add_entry(msgID, pdu->reqid, securityEngineID,
+                           msgSecurityModel,
+                           securityName, securityLevel, "", "",
+                           securityStateReference,
+                           SNMPv3_MP_INVALID_ENGINEID,
+                           CACHE_REMOTE_REQ);
+
+           send_report(0, MAX_SNMP_PACKET, pdu, SNMPv3_MP_INVALID_ENGINEID,
+                       SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV, msgSecurityModel,
+                       securityName, from_address, snmp_session);
+           clear_pdu(pdu, true);  // Clear pdu and free all content AND IDs!
+         }
+         else
+         {
+           usm->delete_sec_state_reference(securityStateReference);
+         }
+         return SNMPv3_MP_INVALID_ENGINEID;
+       }
+
+        usm->delete_sec_state_reference(securityStateReference);
+        return SNMPv3_MP_MATCH_ERROR;
+      }
+    }
+    int ret = cache.add_entry(msgID, pdu->reqid, securityEngineID,
+                              msgSecurityModel, securityName,
+                              securityLevel, contextEngineID,
+                              contextName, securityStateReference,
+                              SNMPv3_MP_OK, CACHE_REMOTE_REQ);
+    if (ret == SNMPv3_MP_DOUBLED_MESSAGE) {
+      debugprintf(0, "*** received doubled message ***");
+      // message will be ignored so return OK
+      usm->delete_sec_state_reference(securityStateReference);
+    }
+
+    debugprintf(1, "mp: parsing finished (ok).");
+    return SNMPv3_MP_OK;
+  }
+
+  if ((pdu->command == TRP_REQ_MSG) || (pdu->command == TRP2_REQ_MSG))
+  {
+    usm->delete_sec_state_reference(securityStateReference);
+    return SNMPv3_MP_OK;
+  }
+
+  debugprintf(0, "mp error: This line should not be executed.");
+  usm->delete_sec_state_reference(securityStateReference);
+  return SNMPv3_MP_ERROR;
+}
+
+
+// Tests if the given buffer contains a SNMPv3-Message.
+bool v3MP::is_v3_msg(unsigned char *buffer, int length)
+{
+  unsigned char type;
+  long version;
+
+  // get the type
+  buffer = asn_parse_header(buffer, &length, &type);
+  if (!buffer)
+  {
+    LOG_BEGIN(WARNING_LOG | 1);
+    LOG("Testing for v3 message: Bad header");
+    LOG_END;
+
+    return FALSE;
+  }
+
+  if (type != ASN_SEQ_CON)
+  {
+    LOG_BEGIN(WARNING_LOG | 1);
+    LOG("Testing for v3 message: Wrong auth header type");
+    LOG((int)type);
+    LOG_END;
+
+    return FALSE;
+  }
+
+  // get the version
+  buffer = asn_parse_int(buffer, &length, &type, &version);
+  if (!buffer)
+  {
+    LOG_BEGIN(WARNING_LOG | 1);
+    LOG("Testing for v3 message: Bad parse of version");
+    LOG_END;
+
+    return 0;
+  }
+
+  return (version == SNMP_VERSION_3);
+}
+
+
+
+// Do the complete process of encoding the given values into the buffer
+// ready to send to the target.
+int v3MP::snmp_build(struct snmp_pdu *pdu,
+                    unsigned char *packet,
+                    int *out_length,             // maximum Bytes in packet
+                    const OctetStr &securityEngineID,
+                    const OctetStr &securityName,
+                    int securityModel,
+                    int securityLevel,
+                    const OctetStr &contextEngineID,
+                    const OctetStr &contextName)
+{
+  Buffer<unsigned char> scopedPDU(MAX_SNMP_PACKET);
+  unsigned char *scopedPDUPtr = scopedPDU.get_ptr();
+  unsigned char globalData[MAXLENGTH_GLOBALDATA];
+  int globalDataLength = MAXLENGTH_GLOBALDATA;
+  int scopedPDULength, maxLen = *out_length;
+  Buffer<unsigned char> buf(MAX_SNMP_PACKET);
+  unsigned char *bufPtr = buf.get_ptr();
+  long bufLength = 0, rc;
+  int msgID;
+  int cachedErrorCode = SNMPv3_MP_OK;
+  struct SecurityStateReference *securityStateReference = NULL;
+  int isRequestMessage = 0;
+
+  if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
+      (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
+      (pdu->command == TRP_REQ_MSG) || (pdu->command == INFORM_REQ_MSG)  ||
+      (pdu->command == TRP2_REQ_MSG))
+    isRequestMessage = 1;
+
+  if (isRequestMessage) {
+    if (securityEngineID.len() == 0) {
+      // First Contact => use user  noAuthNoPriv and USM
+      securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+      securityModel = SNMP_SECURITY_MODEL_USM;
+    }
+
+    cur_msg_id_lock.lock();
+    msgID = cur_msg_id;
+    cur_msg_id++;
+    if (cur_msg_id >= MAX_MPMSGID)
+      cur_msg_id = 1;
+    cur_msg_id_lock.unlock();
+
+#ifdef INVALID_MSGID
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("*** WARNING: Using constant MessageID! ***");
+    LOG_END;
+
+    msgID = 0xdead;
+#endif
+
+    if (securityEngineID.len() == 0) {
+      // length==0 => SecurityLevel == noAuthNoPriv
+      //  => we do not send any management information
+      //  => delete VariableBinding
+      clear_pdu(pdu);
+    }
+  }
+  else {
+    // it is a response => search for request
+    debugprintf(3, "Looking up cache");
+    msgID = pdu->msgid;
+    rc = cache.get_entry(msgID, CACHE_REMOTE_REQ,
+                         &cachedErrorCode, &securityStateReference);
+
+    if (rc != SNMPv3_MP_OK) {
+
+      debugprintf(0, "mp: Cache lookup error");
+      return SNMPv3_MP_MATCH_ERROR;
+    }
+  }
+
+  LOG_BEGIN(DEBUG_LOG | 5);
+  LOG("v3MP: Building message with (SecurityEngineID) (securityName) (securityLevel) (contextEngineID) (contextName)");
+  LOG(securityEngineID.get_printable());
+  LOG(securityName.get_printable());
+  LOG(securityLevel);
+  LOG(contextEngineID.get_printable());
+  LOG(contextName.get_printable());
+  LOG_END;
+
+  // encode vb in buf
+  scopedPDUPtr = build_vb(pdu, scopedPDUPtr, &maxLen);
+  if (!scopedPDUPtr)
+  {
+    LOG_BEGIN(WARNING_LOG | 1);
+    LOG("v3MP: Error encoding vbs into buffer");
+    LOG_END;
+
+    return SNMPv3_MP_BUILD_ERROR;
+  }
+  scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());
+
+  //build dataPDU in buf
+  maxLen = *out_length;
+  scopedPDUPtr = scopedPDU.get_ptr();
+  bufPtr = build_data_pdu(pdu, bufPtr, &maxLen, scopedPDUPtr, scopedPDULength);
+
+  if (!bufPtr)
+  {
+    LOG_BEGIN(WARNING_LOG | 1);
+    LOG("v3MP: Error encoding data pdu into buffer");
+    LOG_END;
+
+    return SNMPv3_MP_BUILD_ERROR;
+  }
+
+  bufLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());
+
+  //  serialize scopedPDU
+  maxLen = *out_length;
+  scopedPDUPtr = asn1_build_scoped_pdu(scopedPDUPtr, &maxLen,
+                                      contextEngineID.data(),
+                                      contextEngineID.len(),
+                                      contextName.data(), contextName.len(),
+                                      buf.get_ptr(), bufLength);
+
+  if (!scopedPDUPtr)
+  {
+    LOG_BEGIN(WARNING_LOG | 1);
+    LOG("v3MP: Error encoding scoped pdu into buffer");
+    LOG_END;
+
+    return SNMPv3_MP_BUILD_ERROR;
+  }
+
+  scopedPDULength = SAFE_INT_CAST(scopedPDUPtr - scopedPDU.get_ptr());
+
+  // build msgGlobalData
+  unsigned char *globalDataPtr = (unsigned char *)&globalData;
+  unsigned char msgFlags;
+  switch (securityLevel) {
+    case SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV:
+      { msgFlags = 0 ; break;}
+    case SNMP_SECURITY_LEVEL_AUTH_NOPRIV:
+      { msgFlags = SNMPv3_AUTHFLAG; break;}
+    case SNMP_SECURITY_LEVEL_AUTH_PRIV:
+      { msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG; break;}
+    default:
+    {
+      LOG_BEGIN(WARNING_LOG | 1);
+      LOG("v3MP: Unknown security level requested, will use authPriv");
+      LOG(securityLevel);
+      LOG_END;
+
+      msgFlags = SNMPv3_AUTHFLAG | SNMPv3_PRIVFLAG;
+    }
+  }
+
+  if ((pdu->command == GET_REQ_MSG) || (pdu->command == GETNEXT_REQ_MSG) ||
+      (pdu->command == SET_REQ_MSG) || (pdu->command == GETBULK_REQ_MSG) ||
+      (pdu->command == INFORM_REQ_MSG))
+    msgFlags = msgFlags | SNMPv3_REPORTABLEFLAG;
+
+  globalDataPtr = asn1_build_header_data(globalDataPtr, &globalDataLength,
+                                        msgID, *out_length,  // maxMessageSize
+                                        msgFlags, securityModel);
+  if (!globalDataPtr)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("v3MP: Error building header data");
+    LOG_END;
+
+    return SNMPv3_MP_BUILD_ERROR;
+  }
+  globalDataLength = SAFE_INT_CAST(globalDataPtr - (unsigned char *)&globalData);
+
+  switch (securityModel) {
+    case SNMP_SECURITY_MODEL_USM: {
+      int use_own_engine_id = 0;
+      if ((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
+          (pdu->command == REPORT_MSG)  || (pdu->command == TRP2_REQ_MSG)) {
+        use_own_engine_id = 1;
+      }
+
+      rc = usm->generate_msg(globalData, globalDataLength, *out_length,
+                             (use_own_engine_id ?
+                                        own_engine_id_oct : securityEngineID),
+                             securityName, securityLevel,
+                             scopedPDU.get_ptr(), scopedPDULength,
+                             securityStateReference, packet, out_length);
+
+      if ( rc == SNMPv3_USM_OK ) {
+        // build cache
+        if (!((pdu->command == TRP_REQ_MSG) || (pdu->command == GET_RSP_MSG) ||
+              (pdu->command == REPORT_MSG) || (pdu->command == TRP2_REQ_MSG)))
+          cache.add_entry(msgID, pdu->reqid, securityEngineID,
+                          securityModel, securityName, securityLevel,
+                          contextEngineID, contextName, securityStateReference,
+                          SNMPv3_MP_OK, CACHE_LOCAL_REQ);
+
+       LOG_BEGIN(INFO_LOG | 3);
+       LOG("v3MP: Message built OK");
+       LOG_END;
+
+        return SNMPv3_MP_OK;
+      }
+      else
+      {
+       LOG_BEGIN(WARNING_LOG | 1);
+       LOG("v3MP: Returning error for building message");
+       LOG(rc);
+       LOG_END;
+
+        return rc;
+      }
+    }
+    default:
+    {
+      LOG_BEGIN(WARNING_LOG | 1);
+      LOG("v3MP: Should build message with unsupported securityModel");
+      LOG(securityModel);
+      LOG_END;
+
+      return SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL;
+    }
+  }
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
+
+#endif
diff --git a/3rdparty/snmp++/src/msec.cpp b/3rdparty/snmp++/src/msec.cpp
new file mode 100644 (file)
index 0000000..ec7ea22
--- /dev/null
@@ -0,0 +1,280 @@
+/*_############################################################################
+  _## 
+  _##  msec.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+*/
+char msec_cpp_version[]="@(#) SNMP++ $Id: msec.cpp 318 2007-11-02 19:25:56Z katz $";
+
+#include "snmp_pp/msec.h"
+#include "snmp_pp/smival.h"
+#include "snmp_pp/config_snmp_pp.h"
+
+#include <stdio.h>  // for sprintf
+#include <string.h> // for strcat
+
+#ifdef WIN32
+#include <sys/types.h> // for _timeb
+#include <sys/timeb.h> // and _ftime
+
+#ifdef __BCPLUSPLUS__
+#define _timeb timeb
+#define _ftime ftime
+#endif
+
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#if !defined HAVE_LOCALTIME_R && !defined HAVE_REENTRANT_LOCALTIME
+#ifdef _THREADS
+SnmpSynchronized msec::m_localtime_mutex;
+#endif
+#endif
+
+int operator==(const msec &t1, const msec &t2)
+{
+  return((t1.m_time.tv_sec == t2.m_time.tv_sec) &&
+        (t1.m_time.tv_usec == t2.m_time.tv_usec));
+}
+
+int operator!=(const msec &t1, const msec &t2)
+{
+  return((t1.m_time.tv_sec != t2.m_time.tv_sec) ||
+        (t1.m_time.tv_usec != t2.m_time.tv_usec));
+}
+
+int operator<(const msec &t1, const msec &t2)
+{
+  if (t1.IsInfinite()) return 0;
+  if (t2.IsInfinite()) return 1;
+  if ((t1.m_time.tv_sec < t2.m_time.tv_sec) ||
+      ((t1.m_time.tv_sec == t2.m_time.tv_sec) &&
+       (t1.m_time.tv_usec < t2.m_time.tv_usec)))
+    return 1;
+  return 0;
+}
+
+int operator>(const msec &t1, const msec &t2)
+{
+  if (t2.IsInfinite()) return 0;
+  if (t1.IsInfinite()) return 1;
+  if ((t1.m_time.tv_sec > t2.m_time.tv_sec) ||
+      ((t1.m_time.tv_sec == t2.m_time.tv_sec) &&
+       (t1.m_time.tv_usec > t2.m_time.tv_usec)))
+    return 1;
+  return 0;
+}
+
+msec &msec::operator-=(const long millisec)
+{
+  timeval t1;
+
+  // create a timeval
+  t1.tv_sec = millisec / 1000;
+  t1.tv_usec = (millisec % 1000) * 1000;
+  // subtract it from this
+  *this -= t1; // add m_changed = true if this line is removed!
+  return *this;
+}
+
+msec &msec::operator-=(const timeval &t1)
+{
+  long tmp_usec = t1.tv_usec/1000;// convert usec to millisec
+  if (!this->IsInfinite())
+  {
+    if (m_time.tv_usec < t1.tv_usec) {
+      // borrow
+      m_time.tv_sec--;
+      m_time.tv_usec += 1000;
+    }
+    m_time.tv_usec -= tmp_usec;
+    m_time.tv_sec -= t1.tv_sec;
+  }
+  m_changed = true;
+  return *this;
+}
+
+msec &msec::operator+=(const long millisec)
+{
+  timeval t1;
+
+  // create a timeval
+  t1.tv_sec = millisec / 1000;
+  t1.tv_usec = (millisec % 1000) * 1000;
+  // add it to this
+  *this += t1; // add m_changed = true if this line is removed!
+  return *this;
+}
+
+msec &msec::operator+=(const timeval &t1)
+{
+  long tmp_usec = t1.tv_usec/1000;// convert usec to millisec
+  if (!this->IsInfinite())
+  {
+    m_time.tv_usec += tmp_usec;
+    if (m_time.tv_usec > 1000) {
+      // carry
+      m_time.tv_sec +=  m_time.tv_usec / 1000;
+      m_time.tv_usec = m_time.tv_usec % 1000;
+    }
+    m_time.tv_sec += t1.tv_sec;
+  }
+  m_changed = true;
+  return *this;
+}
+
+msec &msec::operator=(const timeval &t1)
+{
+  m_time.tv_sec  = t1.tv_sec;
+  m_time.tv_usec = t1.tv_usec/1000; // convert usec to millisec
+  m_changed = true;
+  return *this;
+}
+
+#if defined (CPU) && CPU == PPC603
+
+  struct SCommTimer
+  {
+       unsigned long NumMS;
+       unsigned long FractMS;
+  };
+
+  extern "C"
+  {
+  // The GetTime call is not part of the VxWorks library!
+  // If it is not already available in your environment,
+  // you will need to implement it!
+  void GetTime (struct SCommTimer *  Time);
+  }
+#endif
+
+void msec::refresh()
+{
+#ifdef WIN32
+  struct _timeb timebuffer;
+  _ftime( &timebuffer );
+  m_time.tv_usec = timebuffer.millitm;
+  m_time.tv_sec  = SAFE_ULONG_CAST(timebuffer.time);
+#elif defined (CPU) && CPU == PPC603
+
+  SCommTimer theTime;
+
+  GetTime(&theTime);
+
+  m_time.tv_sec = theTime.NumMS/1000;
+  m_time.tv_usec = theTime.NumMS % 1000;
+
+#else
+  class timezone tzone;
+  gettimeofday((timeval *)&m_time, &tzone);
+  m_time.tv_usec /= 1000; // convert usec to millisec
+#endif
+  m_changed = true;
+}
+
+#ifndef MAX_ALARM
+#define MAX_ALARM 1000000000L
+#endif
+
+void msec::GetDelta(const msec &future, timeval &timeout) const
+{
+  if (future.IsInfinite())
+  {
+    timeout.tv_sec = MAX_ALARM; // max allowable select timeout
+    timeout.tv_usec = 0;
+  }
+  else if (future > *this)
+  {
+    if (future.m_time.tv_usec < m_time.tv_usec)
+    {
+      timeout.tv_sec  = future.m_time.tv_sec  - 1    - m_time.tv_sec;
+      timeout.tv_usec = future.m_time.tv_usec + 1000 - m_time.tv_usec;
+    }
+    else
+    {
+      timeout.tv_sec  = future.m_time.tv_sec  - m_time.tv_sec;
+      timeout.tv_usec = future.m_time.tv_usec - m_time.tv_usec;
+    }
+    timeout.tv_usec *= 1000 ;// convert back to usec
+  }
+  else // Never give back negative timeval's they make select() hurl
+  {
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 0;
+  }
+}
+
+// FIXME: does not print years and days!
+const char *msec::get_printable() const
+{
+  if (m_changed == false) return m_output_buffer;
+
+  char msec_buffer[5];
+  msec *nc_this = PP_CONST_CAST(msec*, this);
+
+#ifdef HAVE_LOCALTIME_R
+  struct tm stm;
+  localtime_r((const time_t *)&m_time.tv_sec, &stm);
+  strftime(nc_this->m_output_buffer, sizeof(m_output_buffer),
+           "%H:%M:%S.", &stm);
+#else
+#if defined _THREADS && !defined HAVE_REENTRANT_LOCALTIME
+  SnmpSynchronize s(m_localtime_mutex);  // Serialize all calls to localtime!
+#endif
+  struct tm *tmptr;
+  tmptr = localtime((time_t *)&m_time.tv_sec);
+  strftime(nc_this->m_output_buffer, sizeof(m_output_buffer),
+           "%H:%M:%S.", tmptr);
+#endif
+
+  sprintf(msec_buffer, "%.3ld", (long)m_time.tv_usec);
+  strcat(nc_this->m_output_buffer, msec_buffer);
+
+  nc_this->m_changed = false;
+
+  return m_output_buffer;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/msgqueue.cpp b/3rdparty/snmp++/src/msgqueue.cpp
new file mode 100644 (file)
index 0000000..ea05766
--- /dev/null
@@ -0,0 +1,789 @@
+/*_############################################################################
+  _## 
+  _##  msgqueue.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+      M S G Q U E U E . C P P
+
+      MSG QUEUE CLASS DECLARATION
+
+      Author:           Peter E Mellquist
+
+=====================================================================*/
+char msgqueue_version[]="#(@) SNMP++ $Id: msgqueue.cpp 1826 2010-08-29 20:19:59Z katz $";
+
+//-----[ includes ]----------------------------------------------------
+
+//----[ snmp++ includes ]----------------------------------------------
+
+#include "snmp_pp/msgqueue.h"  // queue for holding outstanding messages
+#include "snmp_pp/snmpmsg.h"
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/log.h"
+#include "snmp_pp/vb.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+
+#define SNMP_PORT 161
+
+//--------[ externs ]---------------------------------------------------
+extern int send_snmp_request(SnmpSocket sock, unsigned char *send_buf,
+                             size_t send_len, Address &address);
+extern int receive_snmp_response(SnmpSocket sock, Snmp &snmp_session,
+                                 Pdu &pdu, UdpAddress &fromaddress,
+                                OctetStr &engine_id, bool process_msg = true);
+
+//----[ CSNMPMessage class ]-------------------------------------------
+
+CSNMPMessage::CSNMPMessage(unsigned long id,
+                          Snmp * snmp,
+                          SnmpSocket socket,
+                          const SnmpTarget &target,
+                          Pdu &pdu,
+                          unsigned char * rawPdu,
+                          size_t rawPduLen,
+                          const Address & address,
+                          snmp_callback callBack,
+                          void * callData):
+  m_uniqueId(id), m_snmp(snmp), m_socket(socket), m_pdu(pdu),
+  m_rawPduLen(rawPduLen), m_callBack(callBack), m_callData(callData),
+  m_reason(0), m_received(0)
+{
+  // reset pdu mvs
+  m_pdu.set_error_index(0);
+  m_pdu.set_error_status(0);
+  m_pdu.set_request_id(m_uniqueId);
+
+  m_rawPdu = new unsigned char [rawPduLen];
+  memcpy(m_rawPdu, rawPdu, rawPduLen);
+  m_address = (Address *)address.clone();
+  m_target = target.clone();
+
+  SetSendTime();
+}
+
+CSNMPMessage::~CSNMPMessage()
+{
+  delete [] m_rawPdu;
+  delete m_address;
+  delete m_target;
+}
+
+void CSNMPMessage::SetSendTime()
+{
+  m_sendTime.refresh();
+
+  // Kludge: When this was first designed the units were millisecs
+  // However, later on the units for the target class were changed
+  // to hundreths of secs.  Multiply the hundreths of secs by 10
+  // to create the millisecs which the rest of the objects use.
+  // 11-Dec-95 TM
+  m_sendTime += (m_target->get_timeout() * 10);
+}
+
+int CSNMPMessage::SetPdu(const int reason, const Pdu &pdu,
+                        const UdpAddress &fromaddress)
+{
+  if (Pdu::match_type(m_pdu.get_type(), pdu.get_type()) == false)
+  {
+    LOG_BEGIN(INFO_LOG | 1);
+    LOG("MsgQueue: Response pdu type does not match, pdu is ignored: (id) (type1) (type2)");
+    LOG(m_uniqueId);
+    LOG(m_pdu.get_type());
+    LOG(pdu.get_type());
+    LOG_END;
+
+    return -1;
+  }
+
+  unsigned short orig_type = m_pdu.get_type();
+  if (m_received)
+  {
+    LOG_BEGIN(WARNING_LOG | 1);
+    LOG("MsgQueue: Message is already marked as received (id) (reason) (new reason)");
+    LOG(m_uniqueId);
+    LOG(reason);
+    LOG(m_reason);
+    LOG_END;
+
+    // TODO: better check based on error codes
+    if (reason || !m_reason)
+    {
+      LOG_BEGIN(WARNING_LOG | 1);
+      LOG("MsgQueue: ignoring the second pdu");
+      LOG_END;
+
+      return 0;
+    }
+  }
+  m_received = 1;
+  m_pdu = pdu;
+  m_reason = reason;
+
+  LOG_BEGIN(DEBUG_LOG | 10);
+  LOG("MsgQueue: Response received (req id) (status) (msg id)");
+  LOG(pdu.get_request_id());
+  LOG(reason);
+#ifdef _SNMPv3
+  LOG(pdu.get_message_id());
+#endif
+  LOG_END;
+
+  if ((orig_type == sNMP_PDU_INFORM) &&
+      (m_pdu.get_type() == sNMP_PDU_RESPONSE))
+  {
+    // remove the first two vbs of the pdu if sysUpTime and notify_id
+    if (m_pdu.get_vb_count() < 2)
+      return 0;
+
+    const Vb &vb1 = m_pdu.get_vb(0);
+    if (vb1.get_syntax() != sNMP_SYNTAX_TIMETICKS)   return 0;
+    if (vb1.get_oid()    != SNMP_MSG_OID_SYSUPTIME)  return 0;
+
+    const Vb &vb2 = m_pdu.get_vb(1);
+    if (vb2.get_syntax() != sNMP_SYNTAX_OID)         return 0;
+    if (vb2.get_oid()    != SNMP_MSG_OID_TRAPID)     return 0;
+
+    TimeTicks timeticks;
+    Oid oid;
+
+    vb1.get_value(timeticks);
+    m_pdu.set_notify_timestamp(timeticks);
+
+    vb2.get_value(oid);
+    m_pdu.set_notify_id(oid);
+
+    m_pdu.delete_vb(1);
+    m_pdu.delete_vb(0);
+  }
+  return 0;
+}
+
+int CSNMPMessage::ResendMessage()
+{
+  if (m_received)
+  {
+    // Don't bother to resend if we already have the response
+    SetSendTime();
+    return SNMP_CLASS_SUCCESS;
+  }
+
+  LOG_BEGIN(DEBUG_LOG | 10);
+  LOG("MsgQueue: Message (msg id) (req id) (info)");
+#ifdef _SNMPv3
+  LOG(m_pdu.get_message_id());
+#endif
+  LOG(m_pdu.get_request_id());
+  LOG((m_target->get_retry() <= 0) ? "TIMEOUT" : "RESEND");
+  LOG_END;
+
+  if (m_target->get_retry() <= 0)
+  {
+    // This message has timed out
+    Callback(SNMP_CLASS_TIMEOUT);   // perform callback with the error
+
+    return SNMP_CLASS_TIMEOUT;
+  }
+
+  m_target->set_retry(m_target->get_retry() - 1);
+  SetSendTime();
+  int status = send_snmp_request(m_socket, m_rawPdu, m_rawPduLen, *m_address);
+  if (status != 0)
+    return SNMP_CLASS_TL_FAILED;
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+int CSNMPMessage::Callback(const int reason)
+{
+  snmp_callback          tmp_callBack;
+  if (m_callBack) {
+    // prevent callbacks from using this message
+    tmp_callBack = m_callBack;
+    m_callBack = NULL;
+
+    tmp_callBack(reason, m_snmp, m_pdu, *m_target, m_callData);
+    return 0;
+  }
+  return 1;
+}
+
+//----[ CSNMPMessageQueueElt class ]--------------------------------------
+
+CSNMPMessageQueue::CSNMPMessageQueueElt::CSNMPMessageQueueElt(
+                                           CSNMPMessage *message,
+                                          CSNMPMessageQueueElt *next,
+                                          CSNMPMessageQueueElt *previous):
+  m_message(message), m_Next(next), m_previous(previous)
+{
+  /* Finish insertion into doubly linked list */
+  if (m_Next)     m_Next->m_previous = this;
+  if (m_previous) m_previous->m_Next = this;
+}
+
+CSNMPMessageQueue::CSNMPMessageQueueElt::~CSNMPMessageQueueElt()
+{
+  /* Do deletion form doubly linked list */
+  if (m_Next)     m_Next->m_previous = m_previous;
+  if (m_previous) m_previous->m_Next = m_Next;
+  if (m_message)  delete m_message;
+}
+
+CSNMPMessage *CSNMPMessageQueue::CSNMPMessageQueueElt::TestId(const unsigned long uniqueId)
+{
+  if (m_message && (m_message->GetId() == uniqueId))
+    return m_message;
+  return 0;
+}
+
+
+
+//----[ CSNMPMessageQueue class ]--------------------------------------
+
+CSNMPMessageQueue::CSNMPMessageQueue(EventListHolder *holder, Snmp *session)
+  : m_head(0, 0, 0), m_msgCount(0), my_holder(holder), m_snmpSession(session)
+{
+}
+
+CSNMPMessageQueue::~CSNMPMessageQueue()
+{
+  CSNMPMessageQueueElt *leftOver;
+  lock();
+    /*--------------------------------------------------------*/
+    /* walk the list deleting any elements still on the queue */
+    /*--------------------------------------------------------*/
+  while ((leftOver = m_head.GetNext()))
+    delete leftOver;
+
+  unlock();
+}
+
+CSNMPMessage * CSNMPMessageQueue::AddEntry(unsigned long id,
+                                          Snmp * snmp,
+                                          SnmpSocket socket,
+                                          const SnmpTarget &target,
+                                          Pdu &pdu,
+                                          unsigned char * rawPdu,
+                                          size_t rawPduLen,
+                                          const Address & address,
+                                          snmp_callback callBack,
+                                          void * callData)
+{
+  if (snmp != m_snmpSession)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("MsgQueue: Adding message for other Snmp object.");
+    LOG_END;
+  }
+
+  CSNMPMessage *newMsg = new CSNMPMessage(id, snmp, socket, target, pdu,
+                                         rawPdu, rawPduLen, address,
+                                         callBack, callData);
+
+  lock();
+    /*---------------------------------------------------------*/
+    /* Insert entry at head of list, done automagically by the */
+    /* constructor function, so don't use the return value.    */
+    /*---------------------------------------------------------*/
+  (void) new CSNMPMessageQueueElt(newMsg, m_head.GetNext(), &m_head);
+  ++m_msgCount;
+
+  LOG_BEGIN(DEBUG_LOG | 10);
+  LOG("MsgQueue: Adding entry (req id) (count)");
+  LOG(id);
+  LOG(m_msgCount);
+  LOG_END;
+
+  unlock();
+  return newMsg;
+}
+
+
+CSNMPMessage *CSNMPMessageQueue::GetEntry(const unsigned long uniqueId)
+{
+  CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+  CSNMPMessage *returnVal = NULL;
+
+  while (msgEltPtr){
+    if ((returnVal = msgEltPtr->TestId(uniqueId)))
+      return returnVal;
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+  return 0;
+}
+
+int CSNMPMessageQueue::DeleteEntry(const unsigned long uniqueId)
+{
+  CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+
+  while (msgEltPtr){
+    if (msgEltPtr->TestId(uniqueId)) {
+      delete msgEltPtr;
+      m_msgCount--;
+      LOG_BEGIN(DEBUG_LOG | 10);
+      LOG("MsgQueue: Removed entry (req id)");
+      LOG(uniqueId);
+      LOG_END;
+      return SNMP_CLASS_SUCCESS;
+    }
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+  return SNMP_CLASS_INVALID_REQID;
+}
+
+void CSNMPMessageQueue::DeleteSocketEntry(const SnmpSocket socket)
+REENTRANT({
+  CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+  CSNMPMessageQueueElt *tmp_msgEltPtr;
+  CSNMPMessage *msg = NULL;
+
+  while (msgEltPtr){
+    msg = msgEltPtr->GetMessage();
+    if (socket == msg->GetSocket()) {
+      // Make a callback with an error
+      (void) msg->Callback(SNMP_CLASS_SESSION_DESTROYED);
+      tmp_msgEltPtr = msgEltPtr;
+      msgEltPtr = tmp_msgEltPtr->GetNext();
+      // delete the entry
+      delete tmp_msgEltPtr;
+    }
+    else
+      msgEltPtr = msgEltPtr->GetNext();
+  }
+})
+
+CSNMPMessage * CSNMPMessageQueue::GetNextTimeoutEntry()
+{
+  CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+  msec bestTime;
+  msec sendTime(bestTime);
+  CSNMPMessage *msg;
+  CSNMPMessage *bestmsg = NULL;
+
+  if (msgEltPtr) {
+    bestmsg = msgEltPtr->GetMessage();
+    bestmsg->GetSendTime(bestTime);
+  }
+
+  // This would be much simpler if the queue was an ordered list!
+  while (msgEltPtr){
+    msg = msgEltPtr->GetMessage();
+    msg->GetSendTime(sendTime);
+    if (bestTime  > sendTime) {
+      bestTime = sendTime;
+      bestmsg = msg;
+    }
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+  return bestmsg;
+}
+
+int CSNMPMessageQueue::GetNextTimeout(msec &sendTime)
+{
+  CSNMPMessage *msg = GetNextTimeoutEntry();
+
+  if (!msg)  return 1;    // nothing in the queue...
+
+  msg->GetSendTime(sendTime);
+  return 0;
+}
+
+#ifdef HAVE_POLL_SYSCALL
+
+int CSNMPMessageQueue::GetFdCount()
+{
+  SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+
+  CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+
+  if (!msgEltPtr) return 0;
+
+#ifndef SNMP_PP_IPv6
+  // we have at least one message in the queue and Snmp class
+  // can only have one socket, so
+  return 1;
+#else
+  // we can have max 2 sockets
+  SnmpSocket firstSocket = msgEltPtr->GetMessage()->GetSocket();
+
+  msgEltPtr = msgEltPtr->GetNext();
+
+  while (msgEltPtr)
+  {
+      if (msgEltPtr->GetMessage()->GetSocket() != firstSocket)
+         return 2;
+      msgEltPtr = msgEltPtr->GetNext();
+  }
+  return 1;
+#endif
+}
+
+bool CSNMPMessageQueue::GetFdArray(struct pollfd *readfds, int &remaining)
+{
+  SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+
+  CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+  if (!msgEltPtr) return true;
+
+  if (remaining <= 0) return false;
+
+  SnmpSocket firstSocket = msgEltPtr->GetMessage()->GetSocket();
+  readfds[0].fd = firstSocket;
+  readfds[0].events = POLLIN;
+  remaining--;
+
+#ifndef SNMP_PP_IPv6
+  // we have at least one message in the queue and Snmp class
+  // can only have one socket, so we are done
+  return true;
+#else
+  // we can have max 2 sockets
+  msgEltPtr = msgEltPtr->GetNext();
+
+  while (msgEltPtr)
+  {
+      if (msgEltPtr->GetMessage()->GetSocket() != firstSocket)
+      {
+         if (remaining <= 0) return false;
+         readfds[1].fd = msgEltPtr->GetMessage()->GetSocket();
+         readfds[1].events = POLLIN;
+         remaining--;
+
+         return true;
+      }
+      msgEltPtr = msgEltPtr->GetNext();
+  }
+  return true;
+#endif
+}
+
+int CSNMPMessageQueue::HandleEvents(const struct pollfd *readfds,
+                                   const int fds)
+{
+  for (int i=0; i < fds ; i++)
+  {
+    if (readfds[i].revents & POLLIN)
+    {
+      CSNMPMessage *msg;
+      UdpAddress fromaddress;
+      Pdu tmppdu;
+      unsigned long temp_req_id;
+      int status;
+      int recv_status;
+      OctetStr engine_id;
+
+      tmppdu.set_request_id(0);
+
+      // get the response and put it into a Pdu
+      recv_status = receive_snmp_response(readfds[i].fd, *m_snmpSession,
+                                          tmppdu, fromaddress, engine_id);
+
+      lock();
+      // find the corresponding msg in the message queue
+      temp_req_id = tmppdu.get_request_id();
+      msg = GetEntry(temp_req_id);
+      if (!msg)
+      {
+       unlock();
+       LOG_BEGIN(INFO_LOG | 7);
+       LOG("MsgQueue: Ignore received message without outstanding request (req id)");
+       LOG(tmppdu.get_request_id());
+       LOG_END;
+       // the sent message is gone! probably was canceled, ignore it
+       continue;
+      }
+
+      if (tmppdu.get_request_id())
+      {
+       // we correctly received the pdu
+
+       // save it back into the message
+       status = msg->SetPdu(recv_status, tmppdu, fromaddress);
+
+       if (status != 0)
+       {
+         // received pdu does not match
+         // @todo if version is SNMPv3 we must return a report
+         //       unknown pdu handler!
+         unlock();
+         continue;
+       }
+
+#ifdef _SNMPv3
+       if (engine_id.len() > 0)
+       {
+         SnmpTarget *target = msg->GetTarget();
+         if ((target->get_type() == SnmpTarget::type_utarget) &&
+             (target->get_version() == version3))
+         {
+           UdpAddress addr = target->get_address();
+
+           LOG_BEGIN(DEBUG_LOG | 14);
+           LOG("MsgQueue: Adding engine id to table (addr) (id)");
+           LOG(addr.get_printable());
+           LOG(engine_id.get_printable());
+           LOG_END;
+
+           v3MP::I->add_to_engine_id_table(engine_id,
+                                           (char*)addr.IpAddress::get_printable(),
+                                           addr.get_port());
+         }
+       }
+#endif
+
+       // Do the callback
+       unlock();
+       status = msg->Callback(SNMP_CLASS_ASYNC_RESPONSE);
+       lock();
+
+       if (!status)
+       {
+         // this is an asynch response and the callback is done.
+         // no need to keep this message around;
+         // Dequeue the message
+         DeleteEntry(temp_req_id);
+       }
+      }
+      unlock();
+    }
+  }
+  return SNMP_CLASS_SUCCESS;
+}
+
+#else // HAVE_POLL_SYSCALL
+
+void CSNMPMessageQueue::GetFdSets(int &maxfds, fd_set &readfds,
+                                  fd_set &, fd_set &)
+{
+  SnmpSynchronize _synchronize(*this); // REENTRANT
+  CSNMPMessageQueueElt *msgEltPtr = m_head.GetNext();
+  SnmpSocket sock;
+
+  while (msgEltPtr){
+    sock = msgEltPtr->GetMessage()->GetSocket();
+    FD_SET(sock, &readfds);
+    if (maxfds < SAFE_INT_CAST(sock+1))
+      maxfds = SAFE_INT_CAST(sock+1);
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+}
+
+int CSNMPMessageQueue::HandleEvents(const int maxfds,
+                                   const fd_set &readfds,
+                                   const fd_set &,
+                                   const fd_set &)
+{
+  CSNMPMessage *msg;
+  UdpAddress fromaddress;
+  Pdu tmppdu;
+  unsigned long temp_req_id;
+  int status;
+  int recv_status;
+  fd_set snmp_readfds, snmp_writefds, snmp_errfds;
+  int tmp_maxfds = maxfds;
+
+  // Only read from our own fds
+  FD_ZERO(&snmp_readfds);
+  FD_ZERO(&snmp_writefds);
+  FD_ZERO(&snmp_errfds);
+  GetFdSets(tmp_maxfds, snmp_readfds, snmp_writefds, snmp_errfds);
+
+  for (int fd = 0; fd < maxfds; fd++)
+  {
+    if ((FD_ISSET(fd, &snmp_readfds)) &&
+       (FD_ISSET(fd, (fd_set*)&readfds)))
+    {
+      OctetStr engine_id;
+
+      tmppdu.set_request_id(0);
+
+      // get the response and put it into a Pdu
+      recv_status = receive_snmp_response(fd, *m_snmpSession,
+                                          tmppdu, fromaddress, engine_id);
+
+      lock();
+      // find the corresponding msg in the message queue
+      temp_req_id = tmppdu.get_request_id();
+      msg = GetEntry(temp_req_id);
+      if (!msg) {
+            unlock();
+            LOG_BEGIN(INFO_LOG | 7);
+            LOG("MsgQueue: Ignore received message without outstanding "
+                "request (req id)");
+            LOG(tmppdu.get_request_id());
+            LOG_END;
+            // the sent message is gone! probably was canceled, ignore it
+            continue;
+      }
+
+      if (tmppdu.get_request_id()) {
+            // we correctly received the pdu
+
+            // save it back into the message
+            status = msg->SetPdu(recv_status, tmppdu, fromaddress);
+
+             if (status != 0)
+             {
+               // received pdu does not match
+               // @todo if version is SNMPv3 we must return a report
+               //       unknown pdu handler!
+               unlock();
+               continue;
+             }
+
+#ifdef _SNMPv3
+            if (engine_id.len() > 0)
+            {
+                SnmpTarget *target = msg->GetTarget();
+                if ((target->get_type() == SnmpTarget::type_utarget) &&
+                    (target->get_version() == version3))
+                {
+                  UdpAddress addr = target->get_address();
+
+                  LOG_BEGIN(DEBUG_LOG | 14);
+                  LOG("MsgQueue: Adding engine id to table (addr) (id)");
+                  LOG(addr.get_printable());
+                  LOG(engine_id.get_printable());
+                  LOG_END;
+
+                  v3MP::I->add_to_engine_id_table(engine_id,
+                              (char*)addr.IpAddress::get_printable(),
+                              addr.get_port());
+                }
+            }
+#endif
+
+            // Do the callback
+             unlock();
+            status = msg->Callback(SNMP_CLASS_ASYNC_RESPONSE);
+             lock();
+
+            if (!status) {
+              // this is an asynch response and the callback is done.
+              // no need to keep this message around;
+              // Dequeue the message
+              DeleteEntry(temp_req_id);
+            }
+      }
+      unlock();
+    } // if socket has data
+  } // for all sockets
+  return SNMP_CLASS_SUCCESS;
+}
+
+#endif // HAVE_POLL_SYSCALL
+
+int CSNMPMessageQueue::DoRetries(const msec &now)
+{
+  CSNMPMessage *msg;
+  msec sendTime(0, 0);
+  int status = SNMP_CLASS_SUCCESS;
+  lock();
+  while ((msg = GetNextTimeoutEntry())) {
+
+    msg->GetSendTime(sendTime);
+
+    if (sendTime <= now)
+    {
+      // send out the message again
+      unlock();
+      status = msg->ResendMessage();
+      lock();
+      if (status != 0)
+      {
+       if (status == SNMP_CLASS_TIMEOUT)
+       {
+         unsigned long req_id = msg->GetId();
+
+         // Dequeue the message
+         DeleteEntry(req_id);
+#ifdef _SNMPv3
+         // delete entry in cache
+         if (v3MP::I)
+           v3MP::I->delete_from_cache(req_id);
+
+          LOG_BEGIN(INFO_LOG | 6);
+          LOG("MsgQueue: Message timed out, removed id from v3MP cache (rid)");
+          LOG(req_id);
+          LOG_END;
+#endif
+       }
+       else {
+         // Some other send error, should we dequeue the message?
+         // do we really want to return without processing the rest?
+          unlock();
+         return status;
+       }
+      }
+    }
+    else {
+      break;  // the next timeout is still in the future...so we are done
+    }
+  }
+  unlock();
+  return status;
+}
+
+
+int CSNMPMessageQueue::Done()
+{
+    return 0;
+}
+
+int CSNMPMessageQueue::Done(unsigned long id) REENTRANT ({
+  // FF: This is much more efficient than the above
+  CSNMPMessage *msg = GetEntry(id);
+
+  if (!msg) return 1; // the message is not in the queue...must have timed out
+
+  if (msg->GetReceived())
+      return 1;
+
+  return 0;
+})
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/notifyqueue.cpp b/3rdparty/snmp++/src/notifyqueue.cpp
new file mode 100644 (file)
index 0000000..87dd499
--- /dev/null
@@ -0,0 +1,755 @@
+/*_############################################################################
+  _## 
+  _##  notifyqueue.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+      N O T I F Y Q U E U E . C P P
+
+      CNotifyEventQueue CLASS DEFINITION
+
+      COPYRIGHT HEWLETT PACKARD COMPANY 1999
+
+      INFORMATION NETWORKS DIVISION
+
+      NETWORK MANAGEMENT SECTION
+
+      DESIGN + AUTHOR:        Tom Murray
+
+      DESCRIPTION:
+        Queue for holding callback associated with user defined
+        timeouts
+
+=====================================================================*/
+char notifyqueue_version[]="#(@) SNMP++ $Id: notifyqueue.cpp 1826 2010-08-29 20:19:59Z katz $";
+
+//-----[ includes ]----------------------------------------------------
+#include <errno.h>
+
+#if defined (CPU) && CPU == PPC603
+#include <sockLib.h> 
+#endif
+
+#if defined(__APPLE__)
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#endif
+
+//----[ snmp++ includes ]----------------------------------------------
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/notifyqueue.h" // queue for holding sessions waiting for async notifications
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/uxsnmp.h"
+#include "snmp_pp/snmperrs.h"
+#include "snmp_pp/pdu.h"
+#include "snmp_pp/log.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//--------[ externs ]---------------------------------------------------
+extern int receive_snmp_notification(SnmpSocket sock, Snmp &snmp_session,
+                                     Pdu &pdu, SnmpTarget **target);
+
+//-----[ macros ]------------------------------------------------------
+// should be in snmp.h...
+#define SNMP_PORT 161        // standard port # for SNMP
+#define SNMP_TRAP_PORT 162    // standard port # for SNMP traps
+
+#ifdef WIN32
+#define close closesocket
+#elif defined(_AIX)
+#include <unistd.h>
+#endif
+
+//----[ CNotifyEvent class ]------------------------------------------------
+
+CNotifyEvent::CNotifyEvent(Snmp *snmp,
+                          const OidCollection &trapids,
+                          const TargetCollection &targets)
+  : m_snmp(snmp)
+{
+  // create new collections using parms passed in
+  notify_ids       = new OidCollection(trapids);
+  notify_targets   = new TargetCollection(targets);
+}
+
+CNotifyEvent::~CNotifyEvent()
+{
+  // free up local collections
+  if (notify_ids)       { delete notify_ids;       notify_ids       = 0; }
+  if (notify_targets)   { delete notify_targets;   notify_targets   = 0; }
+}
+
+int CNotifyEvent::notify_filter(const Oid &trapid, SnmpTarget &target) const
+{
+  int target_count, has_target = FALSE, target_matches = FALSE;
+  int trapid_count, has_trapid = FALSE, trapid_matches = FALSE;
+  GenAddress targetaddr, tmpaddr;
+
+  // figure out how many targets, handle empty case as all targets
+  if ((notify_targets) && ((target_count = notify_targets->size())))
+  {
+    SnmpTarget *tmptarget = 0;
+    has_target = TRUE;
+
+    target.get_address(targetaddr);
+
+    if (targetaddr.valid()) {
+      // loop through all targets in the collection
+      SnmpTarget::target_type target_type = target.get_type();
+      SnmpTarget::target_type tmptarget_type;
+
+      for ( int x = 0; x < target_count; x++)       // for all targets
+      {
+       if (notify_targets->get_element(tmptarget, x))
+         continue;
+
+       tmptarget->get_address(tmpaddr);
+       if ((tmpaddr.valid())) {
+          int addr_equal = 0;
+
+          /* check for types of Address */
+          if ((tmpaddr.get_type() == Address::type_ip) &&
+              (targetaddr.get_type() == Address::type_udp))
+          {
+            /* special case that works for UdpAddress == IpAddress */
+            IpAddress ip1(targetaddr);
+            IpAddress ip2(tmpaddr);
+
+            addr_equal = (ip1.valid() && ip2.valid() && (ip1 == ip2));
+          }
+          else
+          {
+            addr_equal = (targetaddr == tmpaddr);
+          }
+
+          if (addr_equal) {
+            tmptarget_type = tmptarget->get_type();
+            if (target_type == SnmpTarget::type_utarget) {
+              // target is a UTarget
+              if (tmptarget_type == SnmpTarget::type_utarget) {
+                // both are UTarget
+                if ((((UTarget*)(&target))->get_security_name() ==
+                     ((UTarget*)tmptarget)->get_security_name()) &&
+                    (((UTarget*)(&target))->get_security_model() ==
+                     ((UTarget*)tmptarget)->get_security_model())) {
+                 target_matches = TRUE;
+                  break;
+                }
+              }
+              else
+                if (tmptarget_type == SnmpTarget::type_ctarget)
+                  // in case utarget is used with v1 or v2:
+                  if ((tmptarget->get_version() == target.get_version()) &&
+                      (((UTarget*)(&target))->get_security_name() ==
+                       OctetStr(((CTarget*)tmptarget)->
+                                get_readcommunity()))) {
+                    target_matches = TRUE;
+                    break;
+                  }
+            }
+            else {
+              if (target_type == SnmpTarget::type_ctarget) {
+                // target is a CTarget
+                if (tmptarget_type == SnmpTarget::type_ctarget) {
+                  // both are CTarget
+                  if (!strcmp(((CTarget*)(&target))->get_readcommunity(),
+                              ((CTarget*)tmptarget)->get_readcommunity())) {
+                    target_matches = TRUE;
+                    break;
+                  }
+                }
+                else
+                  if (tmptarget_type == SnmpTarget::type_utarget) {
+                    if ((tmptarget->get_version() == target.get_version()) &&
+                        (OctetStr(((CTarget*)(&target))->get_readcommunity()) ==
+                         ((UTarget*)tmptarget)->get_security_name())) {
+                      target_matches = TRUE;
+                      break;
+                    }
+                  }
+              }
+            }
+          } // end if (add_equal)
+        } // end if tmpaddr.valid()...
+      }
+    }
+  }
+  // else no targets means all targets
+
+  // figure out how many trapids, handle empty case as all trapids
+  if ((notify_ids) && ((trapid_count = notify_ids->size()))) {
+    Oid tmpoid;
+    has_trapid = TRUE;
+    // loop through all trapids in the collection
+    for (int y=0; y < trapid_count; y++)       // for all trapids
+    {
+      if (notify_ids->get_element(tmpoid, y))
+       continue;
+      if (trapid == tmpoid) {
+       trapid_matches = TRUE;
+       break;
+      }
+    }
+  }
+  // else no trapids means all traps
+
+  // Make the callback if the trap passed the filters
+  if ((has_target && !target_matches) || (has_trapid && !trapid_matches))
+    return FALSE;
+  return TRUE;
+}
+
+
+int CNotifyEvent::Callback(SnmpTarget &target, Pdu &pdu, SnmpSocket fd, int status)
+{
+  Oid trapid;
+  pdu.get_notify_id(trapid);
+
+  // Make the callback if the trap passed the filters
+  if ((m_snmp) && (notify_filter(trapid, target)))
+  {
+    int reason;
+
+    if (SNMP_CLASS_TL_FAILED == status)
+      reason = SNMP_CLASS_TL_FAILED;
+    else
+      reason = SNMP_CLASS_NOTIFICATION;
+
+    //------[ call into the callback function ]-------------------------
+    if (m_snmp->get_notify_callback())
+      (m_snmp->get_notify_callback())(
+         reason,
+         m_snmp,                       // snmp++ session who owns the req
+         pdu,                  // trap pdu
+         target,                       // target
+         m_snmp->get_notify_callback_data()); // callback data
+  }
+  return SNMP_CLASS_SUCCESS;
+}
+
+
+//----[ CNotifyEventQueueElt class ]--------------------------------------
+
+CNotifyEventQueue::CNotifyEventQueueElt::CNotifyEventQueueElt(
+                                           CNotifyEvent *notifyevent,
+                                          CNotifyEventQueueElt *next,
+                                          CNotifyEventQueueElt *previous)
+  : m_notifyevent(notifyevent), m_Next(next), m_previous(previous)
+{
+  /* Finish insertion into doubly linked list */
+  if (m_Next)     m_Next->m_previous = this;
+  if (m_previous) m_previous->m_Next = this;
+}
+
+CNotifyEventQueue::CNotifyEventQueueElt::~CNotifyEventQueueElt()
+{
+  /* Do deletion form doubly linked list */
+  if (m_Next)        m_Next->m_previous = m_previous;
+  if (m_previous)    m_previous->m_Next = m_Next;
+  if (m_notifyevent) delete m_notifyevent;
+}
+
+CNotifyEvent *CNotifyEventQueue::CNotifyEventQueueElt::TestId(Snmp *snmp)
+{
+  if (m_notifyevent && (m_notifyevent->GetId() == snmp))
+    return m_notifyevent;
+  return 0;
+}
+
+
+//----[ CNotifyEventQueue class ]--------------------------------------
+CNotifyEventQueue::CNotifyEventQueue(EventListHolder *holder, Snmp *session)
+  : m_head(NULL,NULL,NULL), m_msgCount(0), m_notify_fd(INVALID_SOCKET),
+    m_listen_port(SNMP_TRAP_PORT),
+    my_holder(holder), m_snmpSession(session)
+{
+//TM: could do the trap registration setup here but seems better to
+//wait until the app actually requests trap receives by calling
+//notify_register().
+}
+
+CNotifyEventQueue::~CNotifyEventQueue()
+{
+  CNotifyEventQueueElt *leftOver;
+
+  /* walk the list deleting any elements still on the queue */
+  lock();
+  while ((leftOver = m_head.GetNext()))
+    delete leftOver;
+  unlock();
+}
+
+SnmpSocket CNotifyEventQueue::get_notify_fd() const
+{
+  return m_notify_fd;
+}
+
+int CNotifyEventQueue::AddEntry(Snmp *snmp,
+                               const OidCollection &trapids,
+                               const TargetCollection &targets)
+{
+  SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+
+  if (snmp != m_snmpSession)
+  {
+    debugprintf(0, "WARNING: Adding notification event for other Snmp object");
+  }
+
+  if (!m_msgCount)
+  {
+    m_notify_addr = snmp->get_listen_address();
+    m_notify_addr.set_port(m_listen_port);
+
+    int status = SNMP_CLASS_SUCCESS;
+
+    // This is the first request to receive notifications
+    // Set up the socket for the snmp trap port (162) or the
+    // specified port through set_listen_port()
+    bool is_v4_address = (m_notify_addr.get_ip_version() == Address::version_ipv4);
+    if (is_v4_address)
+    {
+      struct sockaddr_in mgr_addr;
+
+      // open a socket to be used for the session
+      if ((m_notify_fd = socket(AF_INET, SOCK_DGRAM,0)) < 0)
+      {
+#ifdef WIN32
+       int werr = WSAGetLastError();
+       if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
+         status = SNMP_CLASS_RESOURCE_UNAVAIL;
+       else if (WSAEHOSTDOWN == werr)
+         status = SNMP_CLASS_TL_FAILED;
+       else
+         status = SNMP_CLASS_TL_UNSUPPORTED;
+#else
+       if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
+         status = SNMP_CLASS_RESOURCE_UNAVAIL;
+       else if (EHOSTDOWN == errno)
+         status = SNMP_CLASS_TL_FAILED;
+       else
+         status = SNMP_CLASS_TL_UNSUPPORTED;
+#endif
+       cleanup();
+       return status;
+      }
+
+      // set up the manager socket attributes
+      unsigned long inaddr = inet_addr(IpAddress(m_notify_addr).get_printable());
+      memset(&mgr_addr, 0, sizeof(mgr_addr));
+      mgr_addr.sin_family = AF_INET;
+      mgr_addr.sin_addr.s_addr = inaddr; // was htonl( INADDR_ANY);
+      mgr_addr.sin_port = htons(m_notify_addr.get_port());
+#ifdef CYGPKG_NET_OPENBSD_STACK
+      mgr_addr.sin_len = sizeof(mgr_addr);
+#endif
+
+      // bind the socket
+      if (bind(m_notify_fd, (struct sockaddr *) &mgr_addr,
+              sizeof(mgr_addr)) < 0)
+      {
+#ifdef WIN32
+       int werr = WSAGetLastError();
+       if (WSAEADDRINUSE  == werr)
+         status = SNMP_CLASS_TL_IN_USE;
+       else if (WSAENOBUFS == werr)
+         status = SNMP_CLASS_RESOURCE_UNAVAIL;
+       else if (werr == WSAEAFNOSUPPORT)
+         status = SNMP_CLASS_TL_UNSUPPORTED;
+       else if (werr == WSAENETUNREACH)
+         status = SNMP_CLASS_TL_FAILED;
+       else if (werr == EACCES)
+         status = SNMP_CLASS_TL_ACCESS_DENIED;
+       else
+         status = SNMP_CLASS_INTERNAL_ERROR;
+#else
+       if (EADDRINUSE  == errno)
+         status = SNMP_CLASS_TL_IN_USE;
+       else if (ENOBUFS == errno)
+         status = SNMP_CLASS_RESOURCE_UNAVAIL;
+       else if (errno == EAFNOSUPPORT)
+         status = SNMP_CLASS_TL_UNSUPPORTED;
+       else if (errno == ENETUNREACH)
+         status = SNMP_CLASS_TL_FAILED;
+       else if (errno == EACCES)
+         status = SNMP_CLASS_TL_ACCESS_DENIED;
+       else
+       {
+         debugprintf(0, "Uncatched errno value %d, returning internal error.",
+                     errno);
+         status = SNMP_CLASS_INTERNAL_ERROR;
+       }
+#endif
+       debugprintf(0, "Fatal: could not bind to %s",
+                   m_notify_addr.get_printable());
+       cleanup();
+       return status;
+      }
+
+      debugprintf(3, "Bind to %s for notifications, fd %d.",
+                 m_notify_addr.get_printable(), m_notify_fd);
+    } // is_v4_address
+    else
+    {
+      // not is_v4_address
+#ifdef SNMP_PP_IPv6
+      // open a socket to be used for the session
+      if ((m_notify_fd = socket(AF_INET6, SOCK_DGRAM,0)) < 0)
+      {
+#ifdef WIN32
+       int werr = WSAGetLastError();
+       if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
+         status = SNMP_CLASS_RESOURCE_UNAVAIL;
+       else if (WSAEHOSTDOWN == werr)
+         status = SNMP_CLASS_TL_FAILED;
+       else
+         status = SNMP_CLASS_TL_UNSUPPORTED;
+#else
+       if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
+         status = SNMP_CLASS_RESOURCE_UNAVAIL;
+       else if (EHOSTDOWN == errno)
+         status = SNMP_CLASS_TL_FAILED;
+       else
+         status = SNMP_CLASS_TL_UNSUPPORTED;
+#endif
+       cleanup();
+       return status;
+      }
+
+      // set up the manager socket attributes
+      struct sockaddr_in6 mgr_addr;
+      memset(&mgr_addr, 0, sizeof(mgr_addr));
+
+      unsigned int scope = 0;
+
+      OctetStr addrstr = ((IpAddress &)m_notify_addr).IpAddress::get_printable();
+
+      if (m_notify_addr.has_ipv6_scope())
+      {
+       scope = m_notify_addr.get_scope();
+
+       int y = addrstr.len() - 1;
+       while ((y>0) && (addrstr[y] != '%'))
+       {
+         addrstr.set_len(addrstr.len() - 1);
+         y--;
+       }
+       if (addrstr[y] == '%')
+         addrstr.set_len(addrstr.len() - 1);
+      }
+
+      if (inet_pton(AF_INET6, addrstr.get_printable(),
+                   &mgr_addr.sin6_addr) < 0)
+      {
+       LOG_BEGIN(ERROR_LOG | 1);
+       LOG("Notify transport: inet_pton returns (errno) (str)");
+       LOG(errno);
+       LOG(strerror(errno));
+       LOG_END;
+       cleanup();
+       return SNMP_CLASS_INVALID_ADDRESS;
+      }
+
+      mgr_addr.sin6_family = AF_INET6;
+      mgr_addr.sin6_port = htons(m_notify_addr.get_port());
+      mgr_addr.sin6_scope_id = scope;
+
+      // bind the socket
+      if (bind(m_notify_fd, (struct sockaddr *) &mgr_addr,
+              sizeof(mgr_addr)) < 0)
+      {
+#ifdef WIN32
+       int werr = WSAGetLastError();
+       if (WSAEADDRINUSE  == werr)
+         status = SNMP_CLASS_TL_IN_USE;
+       else if (WSAENOBUFS == werr)
+         status = SNMP_CLASS_RESOURCE_UNAVAIL;
+       else if (werr == WSAEAFNOSUPPORT)
+         status = SNMP_CLASS_TL_UNSUPPORTED;
+       else if (werr == WSAENETUNREACH)
+         status = SNMP_CLASS_TL_FAILED;
+       else if (werr == EACCES)
+         status = SNMP_CLASS_TL_ACCESS_DENIED;
+       else
+         status = SNMP_CLASS_INTERNAL_ERROR;
+#else
+       if (EADDRINUSE  == errno)
+         status = SNMP_CLASS_TL_IN_USE;
+       else if (ENOBUFS == errno)
+         status = SNMP_CLASS_RESOURCE_UNAVAIL;
+       else if (errno == EAFNOSUPPORT)
+         status = SNMP_CLASS_TL_UNSUPPORTED;
+       else if (errno == ENETUNREACH)
+         status = SNMP_CLASS_TL_FAILED;
+       else if (errno == EACCES)
+         status = SNMP_CLASS_TL_ACCESS_DENIED;
+       else
+       {
+         debugprintf(0, "Uncatched errno value %d, returning internal error.",
+                     errno);
+         status = SNMP_CLASS_INTERNAL_ERROR;
+         return status;
+       }
+#endif
+       debugprintf(0, "Fatal: could not bind to %s",
+                   m_notify_addr.get_printable());
+       cleanup();
+       return status;
+      }
+      debugprintf(3, "Bind to %s for notifications, fd %d.",
+                 m_notify_addr.get_printable(), m_notify_fd);
+#else
+      debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
+      cleanup();
+      return SNMP_CLASS_TL_UNSUPPORTED;
+#endif
+    } // not is_v4_address
+  }
+
+  CNotifyEvent *newEvent = new CNotifyEvent(snmp, trapids, targets);
+
+  /*---------------------------------------------------------*/
+  /* Insert entry at head of list, done automagically by the */
+  /* constructor function, so don't use the return value.    */
+  /*---------------------------------------------------------*/
+  (void) new CNotifyEventQueueElt(newEvent, m_head.GetNext(), &m_head);
+  m_msgCount++;
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+void CNotifyEventQueue::cleanup()
+{
+  if (m_notify_fd != INVALID_SOCKET)
+  {
+    close(m_notify_fd);
+    m_notify_fd = INVALID_SOCKET;
+  }
+  m_notify_addr.clear();
+}
+
+CNotifyEvent *CNotifyEventQueue::GetEntry(Snmp * snmp) REENTRANT ({
+  CNotifyEventQueueElt *msgEltPtr = m_head.GetNext();
+  CNotifyEvent *returnVal = NULL;
+
+  while (msgEltPtr){
+    if ((returnVal = msgEltPtr->TestId(snmp)))
+      return returnVal;
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+  return 0;
+})
+
+void CNotifyEventQueue::DeleteEntry(Snmp *snmp)
+{
+  lock();
+  CNotifyEventQueueElt *msgEltPtr = m_head.GetNext();
+
+  while (msgEltPtr){
+    if (msgEltPtr->TestId(snmp)){
+      delete msgEltPtr;
+      m_msgCount--;
+      break;
+    }
+    msgEltPtr = msgEltPtr->GetNext();
+  }
+
+  if (m_msgCount <= 0)
+  {
+    // shut down the trap socket (if valid) if not using it.
+    if (m_notify_fd != INVALID_SOCKET)
+    {
+      debugprintf(3, "Closing notifications port %s, fd %d.",
+                 m_notify_addr.get_printable(), m_notify_fd);
+      close(m_notify_fd);
+      m_notify_fd = INVALID_SOCKET;
+    }
+    m_notify_addr.clear();
+  }
+  unlock();
+}
+
+#ifdef HAVE_POLL_SYSCALL
+int CNotifyEventQueue::GetFdCount()
+{
+  SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+  if (m_notify_fd == INVALID_SOCKET)
+    return 0;
+  return 1;
+}
+
+bool CNotifyEventQueue::GetFdArray(struct pollfd *readfds,
+                                  int &remaining)
+{
+  SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+
+  if (m_notify_fd != INVALID_SOCKET)
+  {
+    if (remaining == 0)
+      return false;
+    readfds[0].fd = m_notify_fd;
+    readfds[0].events = POLLIN;
+    remaining--;
+  }
+  return true;
+}
+
+int CNotifyEventQueue::HandleEvents(const struct pollfd *readfds,
+                                   const int fds)
+{
+  SnmpSynchronize _synchronize(*this); // instead of REENTRANT()
+
+  int status = SNMP_CLASS_SUCCESS;
+
+  if (m_notify_fd == INVALID_SOCKET)
+    return status;
+
+  for (int i=0; i < fds; i++)
+  {
+    Pdu pdu;
+    SnmpTarget *target = NULL;
+
+    if ((readfds[i].revents & POLLIN) == 0)
+      continue; // nothing to receive
+
+    if (readfds[i].fd != m_notify_fd)
+      continue; // not our socket
+
+    status = receive_snmp_notification(m_notify_fd, *m_snmpSession,
+                                      pdu, &target);
+
+    if ((SNMP_CLASS_SUCCESS == status) ||
+       (SNMP_CLASS_TL_FAILED == status))
+    {
+      // If we have transport layer failure, the app will want to
+      // know about it.
+      // Go through each snmp object and check the filters, making
+      // callbacks as necessary
+      if (!target) target = new SnmpTarget();
+
+      CNotifyEventQueueElt *notifyEltPtr = m_head.GetNext();
+      while (notifyEltPtr)
+      {
+       notifyEltPtr->GetNotifyEvent()->Callback(*target, pdu,
+                                                m_notify_fd, status);
+       notifyEltPtr = notifyEltPtr->GetNext();
+      } // for each snmp object
+    }
+    if (target) // receive_snmp_notification calls new
+      delete target;
+  }
+
+  return status;
+}
+
+#else
+
+void CNotifyEventQueue::GetFdSets(int &maxfds, fd_set &readfds,
+                                  fd_set &/*writefds*/,
+                                  fd_set &/*exceptfds*/)
+{
+  SnmpSynchronize _synchronize(*this); // REENTRANT
+  if (m_notify_fd != INVALID_SOCKET)
+  {
+    FD_SET(m_notify_fd, &readfds);
+    if (maxfds < SAFE_INT_CAST(m_notify_fd + 1))
+      maxfds = SAFE_INT_CAST(m_notify_fd + 1);
+  }
+  return;
+}
+
+int CNotifyEventQueue::HandleEvents(const int /*maxfds*/,
+                                    const fd_set &readfds,
+                                    const fd_set &/*writefds*/,
+                                    const fd_set &/*exceptfds*/)
+{
+  SnmpSynchronize _synchronize(*this); // REENTRANT
+  int status = SNMP_CLASS_SUCCESS;
+
+  if (m_notify_fd == INVALID_SOCKET)
+    return status;
+
+  Pdu pdu;
+  SnmpTarget *target = NULL;
+
+  // pull the notifiaction off the socket
+  if (FD_ISSET(m_notify_fd, (fd_set*)&readfds)) {
+    status = receive_snmp_notification(m_notify_fd, *m_snmpSession,
+                                      pdu, &target);
+
+    if ((SNMP_CLASS_SUCCESS == status) ||
+       (SNMP_CLASS_TL_FAILED == status))
+    {
+      // If we have transport layer failure, the app will want to
+      // know about it.
+      // Go through each snmp object and check the filters, making
+      // callbacks as necessary
+
+      // On failure target will be NULL
+      if (!target)
+       target = new SnmpTarget();
+
+      CNotifyEventQueueElt *notifyEltPtr = m_head.GetNext();
+      while (notifyEltPtr)
+      {
+       notifyEltPtr->GetNotifyEvent()->Callback(*target, pdu,
+                                                m_notify_fd, status);
+       notifyEltPtr = notifyEltPtr->GetNext();
+      } // for each snmp object
+    }
+    if (target) // receive_snmp_notification calls new
+      delete target;
+  }
+  return status;
+}
+
+#endif // HAVE_POLL_SYSCALL
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/octet.cpp b/3rdparty/snmp++/src/octet.cpp
new file mode 100644 (file)
index 0000000..c5fb693
--- /dev/null
@@ -0,0 +1,851 @@
+/*_############################################################################
+  _## 
+  _##  octet.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+  O C T E T . C P P
+
+  OCTETSTR CLASS IMPLEMENTATION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  This class is fully contained and does not rely on or any other
+  SNMP libraries. This class is portable across any platform
+  which supports C++.
+=====================================================================*/
+char octet_cpp_version[]="@(#) SNMP++ $Id: octet.cpp 1824 2010-08-29 19:47:08Z katz $";
+
+#include "snmp_pp/octet.h"    // include definition for octet class
+#include <ctype.h>    // for isprint() used by get_printable()
+#include <stdio.h>    // for sprintf() used by get_printable_hex()
+#include <string.h>   // for strlen() and memcpy()
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+enum OctetStr::OutputType OctetStr::hex_output_type
+                                               = OctetStr::OutputHexAndClear;
+char OctetStr::nonprintable_char = '.';
+
+#ifdef __unix
+    char OctetStr::linefeed_chars[3] = "\n";
+#else
+    char OctetStr::linefeed_chars[3] = "\r\n";
+#endif // __unix
+
+
+//============[ constructor using no arguments ]======================
+OctetStr::OctetStr()
+  : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
+{
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.ptr = 0;
+  smival.value.string.len = 0;
+}
+
+//============[ constructor using a  string ]=========================
+OctetStr::OctetStr(const char *str)
+  : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
+{
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.ptr = 0;
+  smival.value.string.len = 0;
+
+  size_t z;
+
+  // check for null string
+  if (!str || !((z = strlen(str))))
+    return;
+
+  // get mem needed
+  smival.value.string.ptr = (SmiLPBYTE) new unsigned char[z];
+
+  if (smival.value.string.ptr)
+  {
+    MEMCPY(smival.value.string.ptr, str, z);
+    smival.value.string.len = SAFE_INT_CAST(z);
+  }
+  else
+    validity = false;
+}
+
+
+//============[ constructor using an unsigned char * ]================
+OctetStr::OctetStr(const unsigned char *str, unsigned long len)
+  : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
+{
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.ptr = 0;
+  smival.value.string.len = 0;
+
+  if (!str || !len)  return;   // check for zero len
+
+  // get the mem needed
+  smival.value.string.ptr = (SmiLPBYTE) new unsigned char[len];
+
+  if (smival.value.string.ptr)
+  {
+    MEMCPY(smival.value.string.ptr, str, (size_t) len);
+    smival.value.string.len = len;
+  }
+  else
+    validity = false;
+}
+
+//============[ constructor using another octet object ]==============
+OctetStr::OctetStr (const OctetStr &octet)
+  : output_buffer(0), output_buffer_len(0), m_changed(true), validity(true)
+{
+  smival.syntax = sNMP_SYNTAX_OCTETS;
+  smival.value.string.ptr = 0;
+  smival.value.string.len = 0;
+
+  if (octet.smival.value.string.len == 0) return;  // check for zero len case
+
+  // must be a valid object
+  if (!octet.validity)
+  {
+    validity = false;
+    return;
+  }
+
+  // get the mem needed
+  smival.value.string.ptr = (SmiLPBYTE) new unsigned char[octet.smival.value.string.len];
+
+  if (smival.value.string.ptr)
+  {
+    MEMCPY(smival.value.string.ptr,
+          octet.smival.value.string.ptr,
+          (size_t) octet.smival.value.string.len);
+    smival.value.string.len = octet.smival.value.string.len;
+  }
+  else
+    validity = false;
+}
+
+//=============[ destructor ]=========================================
+OctetStr::~OctetStr()
+{
+  // if not empty, free it up
+  if (smival.value.string.ptr) delete [] smival.value.string.ptr;
+  smival.value.string.len = 0;
+  smival.value.string.ptr = 0;
+  if (output_buffer)           delete [] output_buffer;
+  output_buffer = 0;
+  output_buffer_len = 0;
+}
+
+
+//============[ set the data on an already constructed Octet ]============
+void OctetStr::set_data(const unsigned char *str, unsigned long len)
+{
+  // free up already used space
+  if (smival.value.string.ptr)
+  {
+    delete [] smival.value.string.ptr;
+    smival.value.string.ptr = 0;
+  }
+  smival.value.string.len = 0;
+  m_changed = true;
+
+  // check for zero len
+  if (!str || !len)
+  {
+    validity = true;
+    return;
+  }
+
+  // get the mem needed
+  smival.value.string.ptr = (SmiLPBYTE) new unsigned char[len];
+
+  if (smival.value.string.ptr)
+  {
+    MEMCPY(smival.value.string.ptr, str, len);
+    smival.value.string.len = len;
+    validity = true;
+  }
+  else
+    validity = false;
+}
+
+//=============[ assignment to a string operator overloaded ]=========
+OctetStr& OctetStr::operator=(const char *str)
+{
+  size_t nz;
+
+  // free up previous memory if needed
+  if (smival.value.string.ptr)
+  {
+    delete [] smival.value.string.ptr;
+    smival.value.string.ptr = 0;
+    smival.value.string.len = 0;
+  }
+
+  m_changed = true;
+
+  // if empty then we are done; get the string size
+  if (!str || !((nz = strlen(str))))
+  {
+    validity = true;
+    return *this;
+  }
+
+  // get memory needed
+  smival.value.string.ptr = (SmiLPBYTE) new unsigned char[nz];
+
+  if (smival.value.string.ptr)
+  {
+    MEMCPY(smival.value.string.ptr, str, nz);
+    smival.value.string.len = SAFE_INT_CAST(nz);
+    validity = true;
+  }
+  else
+    validity = false;
+
+  return *this;             // return self reference
+}
+
+//=============[ assignment to another oid object overloaded ]========
+OctetStr& OctetStr::operator=(const OctetStr &octet)
+{
+  if (this == &octet)  return *this; // protect against assignment from self
+
+  if (!octet.validity) return *this; // don't assign from invalid objs
+
+  set_data(octet.smival.value.string.ptr, octet.smival.value.string.len);
+
+  return *this;                       // return self reference
+}
+
+//==============[ equivlence operator overloaded ]====================
+int operator==(const OctetStr &lhs, const OctetStr &rhs)
+{
+  if (lhs.smival.value.string.len != rhs.smival.value.string.len)
+    return false;
+  return (lhs.nCompare(rhs.smival.value.string.len, rhs) == 0);
+}
+
+//==============[ not equivlence operator overloaded ]================
+int operator!=(const OctetStr &lhs, const OctetStr &rhs)
+{
+  if (lhs.smival.value.string.len != rhs.smival.value.string.len)
+    return true;
+  return (lhs.nCompare(rhs.smival.value.string.len, rhs) != 0);
+}
+
+//==============[ less than < overloaded ]============================
+int operator<(const OctetStr &lhs, const OctetStr &rhs)
+{
+  int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
+             ? lhs.smival.value.string.len : rhs.smival.value.string.len;
+  return (lhs.nCompare(maxlen, rhs) < 0);
+}
+
+//==============[ less than <= overloaded ]===========================
+int operator<=(const OctetStr &lhs, const OctetStr &rhs)
+{
+  int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
+             ? lhs.smival.value.string.len : rhs.smival.value.string.len;
+  return (lhs.nCompare(maxlen, rhs) <= 0);
+}
+
+//===============[ greater than > overloaded ]========================
+int operator>(const OctetStr &lhs, const OctetStr &rhs)
+{
+  int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
+             ? lhs.smival.value.string.len : rhs.smival.value.string.len;
+  return (lhs.nCompare(maxlen, rhs) > 0);
+}
+
+//===============[ greater than >= overloaded ]=======================
+int operator>=(const OctetStr &lhs, const OctetStr &rhs)
+{
+  int maxlen = lhs.smival.value.string.len > rhs.smival.value.string.len
+             ? lhs.smival.value.string.len : rhs.smival.value.string.len;
+  return (lhs.nCompare(maxlen, rhs) >=0);
+}
+
+//===============[ equivlence operator overloaded ]===================
+int operator==(const OctetStr &lhs, const char *rhs)
+{
+  OctetStr to(rhs);
+  if (lhs.smival.value.string.len != to.smival.value.string.len)
+    return false;
+  return (lhs.nCompare(to.smival.value.string.len, to) == 0);
+}
+
+//===============[ not equivlence operator overloaded ]===============
+int operator!=(const OctetStr &lhs, const char *rhs)
+{
+  OctetStr to(rhs);
+  if (lhs.smival.value.string.len != to.smival.value.string.len)
+    return true;
+  return (lhs.nCompare(to.smival.value.string.len, to) != 0);
+}
+
+//===============[ less than < operator overloaded ]==================
+int operator<(const OctetStr &lhs, const char *rhs)
+{
+  OctetStr to(rhs);
+  int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
+             ? lhs.smival.value.string.len : to.smival.value.string.len;
+  return (lhs.nCompare(maxlen,to) < 0);
+}
+
+//===============[ less than <= operator overloaded ]=================
+int operator<=(const OctetStr &lhs, const char *rhs)
+{
+  OctetStr to(rhs);
+  int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
+             ? lhs.smival.value.string.len : to.smival.value.string.len;
+  return (lhs.nCompare(maxlen, to) <= 0);
+}
+
+//===============[ greater than > operator overloaded ]===============
+int operator>(const OctetStr &lhs, const char *rhs)
+{
+  OctetStr to(rhs);
+  int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
+             ? lhs.smival.value.string.len : to.smival.value.string.len;
+  return (lhs.nCompare(maxlen, to) > 0);
+}
+
+//===============[ greater than >= operator overloaded ]==============
+int operator>=(const OctetStr &lhs, const char *rhs)
+{
+  OctetStr to(rhs);
+  int maxlen = lhs.smival.value.string.len > to.smival.value.string.len
+             ? lhs.smival.value.string.len : to.smival.value.string.len;
+  return (lhs.nCompare(maxlen, to) >= 0);
+}
+
+//===============[ append operator, appends a string ]================
+OctetStr& OctetStr::operator+=(const char *a)
+{
+  unsigned char *tmp;
+  size_t slen, nlen;
+
+  // get len of string
+  if (!a || ((slen = strlen(a)) == 0))
+    return *this;
+
+  nlen = slen + (size_t) smival.value.string.len;  // total len of new octet
+  tmp = (SmiLPBYTE) new unsigned char[nlen];  // get mem needed
+
+  if (tmp)
+  {
+    // copy in the original 1st
+    MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
+    // copy in the string
+    MEMCPY(tmp + smival.value.string.len, a, slen);
+    // delete the original
+    if (smival.value.string.ptr)
+      delete [] smival.value.string.ptr;
+    // point to the new one
+    smival.value.string.ptr = tmp;
+    smival.value.string.len = SAFE_INT_CAST(nlen);
+
+    m_changed = true;
+  }
+  return *this;
+}
+
+//================[ append one OctetStr to another ]==================
+OctetStr& OctetStr::operator+=(const OctetStr& octet)
+{
+  unsigned char *tmp;
+  size_t slen, nlen;
+
+  if (!octet.validity || !((slen = (size_t)octet.len())))
+    return *this;
+
+  nlen = slen + (size_t) smival.value.string.len;  // total len of new octet
+  tmp = (SmiLPBYTE) new unsigned char[nlen];  // get mem needed
+
+  if (tmp)
+  {
+    // copy in the original 1st
+    MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
+    // copy in the string
+    MEMCPY(tmp + smival.value.string.len, octet.data(), slen);
+    // delete the original
+    if (smival.value.string.ptr )
+      delete [] smival.value.string.ptr;
+    // point to the new one
+    smival.value.string.ptr = tmp;
+    smival.value.string.len = SAFE_INT_CAST(nlen);
+
+    m_changed = true;
+  }
+  return *this;
+}
+
+//================[ appends a char ]==================================
+OctetStr& OctetStr::operator+=(const unsigned char c)
+{
+  unsigned char *tmp;
+
+  // get the memory needed plus one extra byte
+  tmp = (SmiLPBYTE) new unsigned char[smival.value.string.len + 1];
+
+  if (tmp)
+  {
+    MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
+    tmp[smival.value.string.len] = c;  // assign in new byte
+
+    if (smival.value.string.ptr)       // delete the original
+      delete [] smival.value.string.ptr;
+
+    smival.value.string.ptr = tmp;     // point to new one
+    smival.value.string.len++;         // up the len
+
+    m_changed = true;
+  }
+  return *this;                                  // return self reference
+}
+
+//================[ compare n elements of an Octet ]==================
+int OctetStr::nCompare(const unsigned long n, const OctetStr &o) const
+{
+  unsigned long n_max;
+  unsigned long w,str_len;
+
+  if (n == 0) return 0; // Nothing to compare, strings are equal
+
+  // both are empty, they are equal
+  if ((smival.value.string.len == 0) && (o.smival.value.string.len == 0))
+    return 0;  // equal
+
+  // self is empty and param has something
+  if ((smival.value.string.len == 0) && (o.smival.value.string.len > 0))
+    return -1;
+
+  // self has something and param has nothing
+  if ((smival.value.string.len > 0) && (o.smival.value.string.len == 0))
+    return 1;
+
+  // now: n > 0; this.len > 0; o.len > 0 !!!
+
+  // pick the Min of n, this and the param len
+  // this is the maximum # to iterate a search
+  str_len = smival.value.string.len < o.smival.value.string.len
+           ? smival.value.string.len : o.smival.value.string.len;
+  w = (n <= str_len) ? n : str_len;
+
+  unsigned long z = 0;
+  while (z < w)
+  {
+    if (smival.value.string.ptr[z] < o.smival.value.string.ptr[z])
+      return -1;                               // less than
+    if (smival.value.string.ptr[z] > o.smival.value.string.ptr[z])
+      return 1;                                // greater than
+    z++;
+  }
+
+  // now: z == w > 0
+  // set n_max to min(n, max(len of strings))
+  n_max = smival.value.string.len > o.smival.value.string.len
+          ? smival.value.string.len : o.smival.value.string.len;
+  if (n< n_max) n_max = n;
+
+  if (w < n_max) // ==> we have compared too few bytes
+  {
+    if (smival.value.string.len < o.smival.value.string.len)
+      return -1;
+    else
+      return 1;
+  }
+  return 0;
+}
+
+//================[ ASCII format return ]=============================
+const char *OctetStr::get_printable() const
+{
+  if ((m_changed == false) &&
+      (output_last_function == OutputFunctionDefault))
+    return output_buffer;
+
+  for (unsigned long i=0; i < smival.value.string.len; i++)
+  {
+    if ((smival.value.string.ptr[i] != '\r')&&
+       (smival.value.string.ptr[i] != '\n')&&
+       (isprint((int) (smival.value.string.ptr[i]))==0))
+      switch (hex_output_type)
+      {
+        case OutputClear:        return get_printable_clear();
+        case OutputHexAndClear:
+        case OutputHex:
+        default:                 return get_printable_hex();
+      }
+  }
+
+  OctetStr *ncthis = PP_CONST_CAST(OctetStr*, this);
+  if (output_buffer_len < smival.value.string.len + 1)
+  {
+    if (output_buffer) delete [] ncthis->output_buffer;
+
+    ncthis->output_buffer = new char[smival.value.string.len + 1];     
+    if (!ncthis->output_buffer)
+    {
+      ncthis->output_buffer_len = 0;
+      return output_buffer;
+    }
+    ncthis->output_buffer_len = smival.value.string.len + 1;
+  }
+  if (smival.value.string.len)
+    MEMCPY(ncthis->output_buffer,
+          smival.value.string.ptr, (unsigned int) smival.value.string.len);
+  ncthis->output_buffer[smival.value.string.len] = '\0';
+
+  ncthis->m_changed = false;
+  ncthis->output_last_function = OutputFunctionDefault;
+
+  return output_buffer;
+}
+
+//================[ ASCII format return ]=============================
+const char *OctetStr::get_printable_clear() const
+{
+  if ((m_changed == false) &&
+      (output_last_np_char == nonprintable_char) &&
+      (output_last_function == OutputFunctionClear))
+    return output_buffer;
+
+  OctetStr *ncthis = PP_CONST_CAST(OctetStr*, this);
+  if (output_buffer_len < smival.value.string.len + 1)
+  {
+    if (output_buffer) delete [] ncthis->output_buffer;
+
+    ncthis->output_buffer = new char[smival.value.string.len + 1];     
+    if (!ncthis->output_buffer)
+    {
+      ncthis->output_buffer_len = 0;
+      return output_buffer;
+    }
+    ncthis->output_buffer_len = smival.value.string.len + 1;
+  }
+
+  if (smival.value.string.len)
+  {
+    for (unsigned long i=0; i < smival.value.string.len; i++)
+    {
+      if (isprint((int) (smival.value.string.ptr[i]))==0)
+        ncthis->output_buffer[i] = nonprintable_char;
+      else
+        ncthis->output_buffer[i] = smival.value.string.ptr[i];
+    }
+  }
+
+  ncthis->output_buffer[smival.value.string.len] = '\0';
+
+  ncthis->output_last_np_char = nonprintable_char;
+  ncthis->m_changed = false;
+  ncthis->output_last_function = OutputFunctionClear;
+
+  return output_buffer;
+}
+
+
+//================[ general Value = operator ]========================
+SnmpSyntax& OctetStr::operator=(const SnmpSyntax &val)
+{
+  if (this == &val) return *this;  // protect against assignment from self
+
+  // blow away the old value
+  if (smival.value.string.ptr)
+  {
+    delete [] smival.value.string.ptr;
+    smival.value.string.ptr = 0;
+  }
+  smival.value.string.len = 0;
+  validity = false;
+
+  if (val.valid()){
+    switch (val.get_syntax()){
+      case sNMP_SYNTAX_OPAQUE:
+      case sNMP_SYNTAX_BITS:
+      case sNMP_SYNTAX_OCTETS:
+      case sNMP_SYNTAX_IPADDR:
+       set_data(((OctetStr &)val).smival.value.string.ptr,
+                ((OctetStr &)val).smival.value.string.len);
+       break;
+    }
+  }
+  m_changed = true;
+  return *this;
+}
+
+#define ATOI(x)  if      ((x >= 48) && (x <= 57)) x = x-48; /* 0-9 */ \
+                 else if ((x >= 65) && (x <= 70)) x = x-55; /* A-F */ \
+                else if ((x >= 97) && (x <=102)) x = x-87; /* a-f */ \
+                else x = 0
+
+//=======[ create an octet string from a hex string ]===================
+OctetStr OctetStr::from_hex_string(const OctetStr &hex_string)
+{
+  OctetStr val;
+  unsigned int p;
+  unsigned int hex_len = 0;
+
+  // make sure the string has at least one byte
+  if (hex_string.len() == 0) return val;
+
+  // allocate max needed space for copy without spaces
+  unsigned char *hex, *hex_ptr;
+  hex = hex_ptr = new unsigned char[hex_string.len()];
+  if (!hex) return val;
+
+  // delete spaces
+  const unsigned char *ptr = hex_string.smival.value.string.ptr;
+  for (p = hex_string.len(); p > 0; p--)
+  {
+    unsigned char c = *ptr++;
+    if (c != ' ')
+    {
+      *hex_ptr++ = c;
+      ++hex_len;
+    }
+  }
+
+  // leading 0 may be omitted
+  if (hex_len % 2)
+  {
+    unsigned char c = hex[0];
+    ATOI(c);
+    val += c;
+    p = 1;
+  }
+  else
+  {
+    p = 0;
+  }
+
+  while (p < hex_len)
+  {
+    unsigned char c = hex[p++];
+    unsigned char d = hex[p++];
+
+    ATOI(c);
+    ATOI(d);
+    val += (c*16 + d);
+  }
+  delete[] hex;
+  return val;
+}
+
+#undef ATOI
+
+//================[ format the output into hex ]========================
+const char *OctetStr::get_printable_hex() const
+{
+  if ((m_changed == false) && (output_last_type == hex_output_type) &&
+      (output_last_np_char == nonprintable_char) &&
+      (output_last_function == OutputFunctionHex))
+    return output_buffer;
+
+  int cnt;
+  char char_buf[80];              // holds ASCII representation of data
+  char *buf_ptr;                  // pointer into ASCII listing        
+  char *line_ptr;                 // pointer into Hex listing
+  unsigned int  storageNeeded;    // how much space do we need ?
+  int  local_len = (int) smival.value.string.len;
+  unsigned char *bytes = smival.value.string.ptr;
+
+  storageNeeded = (unsigned int) ((smival.value.string.len/16)+1) * 72 + 1;
+  OctetStr *ncthis = PP_CONST_CAST(OctetStr*, this);
+
+  if (output_buffer_len < storageNeeded)
+  {
+    if (output_buffer)  delete [] ncthis->output_buffer;
+
+    ncthis->output_buffer = new char[storageNeeded];
+    if (!ncthis->output_buffer)
+    {
+      ncthis->output_buffer_len = 0;
+      return output_buffer;
+    }
+    ncthis->output_buffer_len = storageNeeded;
+  }
+
+  line_ptr = ncthis->output_buffer;
+
+  /*----------------------------------------*/
+  /* processing loop for entire data buffer */
+  /*----------------------------------------*/
+  while (local_len > 0)
+  {
+    cnt             = 16;        /* print 16 bytes per line */
+    buf_ptr  = char_buf;
+    sprintf(line_ptr, "  ");
+    line_ptr += 2;  /* indent */
+
+    /*-----------------------*/
+    /* process a single line */
+    /*-----------------------*/
+    while (cnt-- > 0 && local_len-- > 0)
+    {
+      sprintf(line_ptr, "%2.2X ", *bytes);
+
+      line_ptr +=3;   /* the display of a byte always 3 chars long */
+      if (isprint(*bytes))
+       *buf_ptr++ = *bytes;
+      else
+       *buf_ptr++ = nonprintable_char;
+      ++bytes;
+    }
+    ++cnt;
+    *buf_ptr = 0; // null terminate string
+
+    /*----------------------------------------------------------*/
+    /* this is to make sure that the ASCII displays line up for */
+    /* incomplete lines of hex                                  */
+    /*----------------------------------------------------------*/
+    while (cnt-- > 0)
+    {
+      *line_ptr++ = ' ';
+      *line_ptr++ = ' ';
+      *line_ptr++ = ' ';
+    }
+
+    /*------------------------------------------*/
+    /* append the ASCII display to the Hex line */
+    /*------------------------------------------*/
+    if (hex_output_type == OutputHex)
+      char_buf[0] = 0;
+
+    sprintf(line_ptr,"   %s%s", char_buf, linefeed_chars);
+    line_ptr += 3 + strlen(char_buf) + strlen(linefeed_chars);
+  }
+
+  ncthis->output_last_type = hex_output_type;
+  ncthis->output_last_np_char = nonprintable_char;
+  ncthis->m_changed = false;
+  ncthis->output_last_function = OutputFunctionHex;
+
+  return output_buffer;
+}
+
+
+//==============[ Null out the contents of the string ]===================
+void OctetStr::clear()
+{
+  if (smival.value.string.len > 0)
+  {
+    memset(smival.value.string.ptr, 0, smival.value.string.len);
+    smival.value.string.len = 0;
+  }
+
+  if (output_buffer)
+    memset(output_buffer, 0, output_buffer_len);
+  m_changed = true;
+}
+
+//============[Return the space needed for serialization]=================
+int OctetStr::get_asn1_length() const
+{
+  if (smival.value.string.len < 0x80)
+    return smival.value.string.len + 2;
+  else if (smival.value.string.len < 0x100)
+    return smival.value.string.len + 3;
+  else if (smival.value.string.len < 0x10000)
+    return smival.value.string.len + 4;
+  else if (smival.value.string.len < 0x1000000)
+    return smival.value.string.len + 5;
+  return smival.value.string.len + 6; // should be safe for some time...
+}
+
+//========[Set the character for linefeeds in get_printable() functions]====
+bool OctetStr::set_linefeed_chars(const char* lf_chars)
+{
+    if (!lf_chars) return false;
+    if (strlen(lf_chars) > 2) return false;
+
+    linefeed_chars[2] = 0;
+    linefeed_chars[1] = lf_chars[1];
+    linefeed_chars[0] = lf_chars[0];
+
+    return true;
+}
+
+//===============[ append or shorten the data buffer ]================
+bool OctetStr::set_len(const unsigned long new_len)
+{
+  unsigned char *tmp;
+
+  if (new_len <= smival.value.string.len)
+  {
+    smival.value.string.len = new_len;
+    m_changed = true;
+
+    if (new_len == 0)
+    {
+      if (smival.value.string.ptr) delete [] smival.value.string.ptr;
+      smival.value.string.ptr = 0;
+    }
+
+    return true;
+  }
+
+  tmp = (SmiLPBYTE) new unsigned char[new_len];  // get mem needed
+
+  if (!tmp) return false;
+
+  if (smival.value.string.ptr)
+    MEMCPY(tmp, smival.value.string.ptr, smival.value.string.len);
+  memset(tmp + smival.value.string.len, 0, new_len - smival.value.string.len);
+  if (smival.value.string.ptr)
+    delete [] smival.value.string.ptr;
+  smival.value.string.ptr = tmp;
+  smival.value.string.len = new_len;
+
+  m_changed = true;
+
+  return true;
+}
+
+
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/oid.cpp b/3rdparty/snmp++/src/oid.cpp
new file mode 100644 (file)
index 0000000..119b889
--- /dev/null
@@ -0,0 +1,748 @@
+/*_############################################################################
+  _## 
+  _##  oid.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+  O I D. C P P
+
+  OID CLASS IMPLEMENTATION
+
+  DESIGN + AUTHOR:         Peter E. Mellquist
+
+  DESCRIPTION:
+  This module contains the implementation of the oid class. This
+  includes all protected and public member functions. The oid class
+  may be compiled stand alone without the use of any other library.
+=====================================================================*/
+char oid_cpp_version[]="#(@) SNMP++ $Id: oid.cpp 1742 2010-04-29 19:08:54Z katz $";
+
+//---------[ external C libaries used ]--------------------------------
+#include <stdio.h>                // standard io
+#if !(defined (CPU) && CPU == PPC603)
+#include <memory.h>               // memcpy's
+#endif
+#include <string.h>               // strlen, etc..
+#include <stdlib.h>               // standard library
+#include <ctype.h>                // isdigit
+#include <stdlib.h>               // malloc, free
+
+#include "snmp_pp/oid.h"                  // include def for oid class
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define  SNMPBUFFSIZE 11          // size of scratch buffer
+#define  SNMPCHARSIZE 11          // an individual oid instance as a string
+
+/* Borlands isdigit has a bug */
+#ifdef __BCPLUSPLUS__
+#define my_isdigit(c) ((c) >= '0' && (c) <= '9')
+#else
+#define my_isdigit isdigit
+#endif
+
+//=============[Oid::Oid(void)]============================================
+// constructor using no arguments
+// initialize octet ptr and string
+// ptr to null
+Oid::Oid() : iv_str(0), iv_part_str(0), m_changed(true)
+{
+  smival.syntax = sNMP_SYNTAX_OID;
+  smival.value.oid.len = 0;
+  smival.value.oid.ptr = 0;
+}
+
+
+//=============[Oid::Oid(const char *dotted_string ]=====================
+// constructor using a dotted string
+//
+// do a string to oid using the string passed in
+Oid::Oid(const char *oid_string, const bool is_dotted_oid_string)
+  : iv_str(0), iv_part_str(0), m_changed(true)
+{
+  smival.syntax = sNMP_SYNTAX_OID;
+  smival.value.oid.len = 0;
+  smival.value.oid.ptr = 0;
+
+  if (is_dotted_oid_string)
+    StrToOid(oid_string, &smival.value.oid);
+  else
+    set_data(oid_string, oid_string ? strlen(oid_string) : 0);
+}
+
+
+//=============[Oid::Oid(const Oid &oid) ]================================
+// constructor using another oid object
+//
+// do an oid copy using the oid object passed in
+Oid::Oid(const Oid &oid)
+  : iv_str(0), iv_part_str(0), m_changed(true)
+{
+  smival.syntax = sNMP_SYNTAX_OID;
+  smival.value.oid.len = 0;
+  smival.value.oid.ptr = 0;
+
+  // allocate some memory for the oid
+  // in this case the size to allocate is the same size as the source oid
+  if (oid.smival.value.oid.len)
+  {
+    smival.value.oid.ptr = (SmiLPUINT32) new unsigned long[oid.smival.value.oid.len];
+    if (smival.value.oid.ptr)
+      OidCopy((SmiLPOID)&(oid.smival.value.oid), (SmiLPOID)&smival.value.oid);
+  }
+}
+
+
+//=============[Oid::Oid(const unsigned long *raw_oid, int oid_len) ]====
+// constructor using raw numeric form
+//
+// copy the integer values into the private member
+Oid::Oid(const unsigned long *raw_oid, int oid_len)
+  : iv_str(0), iv_part_str(0), m_changed(true)
+{
+  smival.syntax = sNMP_SYNTAX_OID;
+  smival.value.oid.len = 0;
+  smival.value.oid.ptr = 0;
+
+  if (raw_oid && (oid_len > 0))
+  {
+    smival.value.oid.ptr = (SmiLPUINT32) new unsigned long[oid_len];
+    if (smival.value.oid.ptr)
+    {
+      smival.value.oid.len = oid_len;
+      for (int i=0; i < oid_len; i++)
+        smival.value.oid.ptr[i] = raw_oid[i];
+    }
+  }
+}
+
+//=============[Oid::~Oid]==============================================
+Oid::~Oid()
+{
+  delete_oid_ptr();
+  if (iv_str)      delete [] iv_str;        // free up the output string
+  if (iv_part_str) delete [] iv_part_str;   // free up the output string
+}
+
+
+//=============[Oid::operator = const char * dotted_string ]==============
+// assignment to a string operator overloaded
+//
+// free the existing oid
+// create the new oid from the string
+// return this object
+Oid& Oid::operator=(const char *dotted_oid_string)
+{
+  delete_oid_ptr();
+
+  // assign the new value
+  StrToOid(dotted_oid_string, &smival.value.oid);
+  return *this;
+}
+
+
+//=============[Oid:: operator = const Oid &oid ]==========================
+// assignment to another oid object overloaded
+//
+// free the existing oid
+// create a new one from the object passed in
+Oid& Oid::operator=(const Oid &oid)
+{
+  if (this == &oid) return *this;  // protect against assignment from self
+
+  delete_oid_ptr();
+
+  // check for zero len on source
+  if (oid.smival.value.oid.len == 0)
+    return *this;
+
+  // allocate some memory for the oid
+  smival.value.oid.ptr = (SmiLPUINT32) new unsigned long[oid.smival.value.oid.len];
+  if (smival.value.oid.ptr)
+    OidCopy((SmiLPOID)&(oid.smival.value.oid), (SmiLPOID)&smival.value.oid);
+  return *this;
+}
+
+
+//==============[Oid:: operator += const char *a ]=========================
+// append operator, appends a string
+//
+// allocate some space for a max oid string
+// extract current string into space
+// concat new string
+// free up existing oid
+// make a new oid from string
+// delete allocated space
+Oid& Oid::operator+=(const char *a)
+{
+  unsigned int n;
+
+  if (!a) return *this;
+
+  if (*a == '.') ++a;
+
+  n = (smival.value.oid.len * SNMPCHARSIZE) + (smival.value.oid.len)
+       + 1 + SAFE_UINT_CAST(strlen(a));
+  char *ptr = new char[n];
+  if (ptr)
+  {
+    /// @todo optimze this function (avoid conversion to string)
+    OidToStr(&smival.value.oid, n, ptr);
+    if (ptr[0])
+      STRCAT(ptr,".");
+    STRCAT(ptr,a);
+
+    delete_oid_ptr();
+
+    StrToOid(ptr, &smival.value.oid);
+    delete [] ptr;
+  }
+  return *this;
+}
+
+//=============[ int operator == oid,oid ]=================================
+// equivlence operator overloaded
+int operator==(const Oid &lhs, const Oid &rhs)
+{
+  // ensure same len, then use nCompare
+  if (rhs.len() != lhs.len()) return 0;
+  return (lhs.nCompare(rhs.len(), rhs) == 0);
+}
+
+//==============[ operator<(Oid &x,Oid &y) ]=============================
+// less than < overloaded
+int operator<(const Oid &lhs, const Oid &rhs)
+{
+  int result;
+  // call nCompare with the current
+  // Oidx, Oidy and len of Oidx
+  if((result = lhs.nCompare(rhs.len(), rhs))<0)  return 1;
+  if (result > 0)    return 0;
+
+  // if here, equivalent substrings, call the shorter one <
+  return (lhs.len() < rhs.len());
+}
+
+//==============[ operator==(Oid &x,char *) ]=============================
+// equivlence operator overloaded
+int operator==(const Oid &x, const char *dotted_oid_string)
+{
+  Oid to(dotted_oid_string);   // create a temp oid object
+  return (x == to);   // compare using existing operator
+}
+
+//==============[ operator!=(Oid &x,char*) ]=============================
+// not equivlence operator overloaded
+int operator!=(const Oid &x, const char *dotted_oid_string)
+{
+  Oid to(dotted_oid_string);  // create a temp oid object
+  return (x != to);  // compare using existing operator
+}
+
+//==============[ operator<(Oid &x,char*) ]=============================
+// less than < operator overloaded
+int operator<(const Oid &x, const char *dotted_oid_string)
+{
+  Oid to(dotted_oid_string);  // create a temp oid object
+  return (x < to);  // compare using existing operator
+}
+
+//==============[ operator<=(Oid &x,char *) ]=============================
+// less than <= operator overloaded
+int operator<=(const Oid &x,char *dotted_oid_string)
+{
+  Oid to(dotted_oid_string);  // create a temp oid object
+  return (x <= to);  // compare using existing operator
+}
+
+//==============[ operator>(Oid &x,char* ]=============================
+// greater than > operator overloaded
+int operator>(const Oid &x,const char *dotted_oid_string)
+{
+  Oid to(dotted_oid_string);  // create a temp oid object
+  return (x > to);   // compare using existing operator
+}
+
+//==============[ operator>=(Oid &x,char*) ]=============================
+// greater than >= operator overloaded
+int operator>=(const Oid &x,const char *dotted_oid_string)
+{
+  Oid to(dotted_oid_string);  // create a temp oid object
+  return (x >= to);   // compare using existing operator
+}
+
+//===============[Oid::set_data ]==---=====================================
+// copy data from raw form...
+void Oid::set_data(const unsigned long *raw_oid,
+                   const unsigned int oid_len)
+{
+  if (smival.value.oid.len < oid_len)
+  {
+    delete_oid_ptr();
+
+    smival.value.oid.ptr = (SmiLPUINT32) new unsigned long[oid_len];
+    if (!smival.value.oid.ptr) return;
+  }
+  MEMCPY((SmiLPBYTE) smival.value.oid.ptr,
+         (SmiLPBYTE) raw_oid,
+         (size_t) (oid_len*sizeof(SmiUINT32)));
+  smival.value.oid.len = oid_len;
+  m_changed = true;
+}
+
+// Set the data from raw form.
+void Oid::set_data(const char *str, const unsigned int str_len)
+{
+  if (smival.value.oid.len < str_len)
+  {
+    delete_oid_ptr();
+
+    smival.value.oid.ptr = (SmiLPUINT32) new unsigned long[str_len];
+    if (!smival.value.oid.ptr) return;
+  }
+
+  if ((!str) || (str_len == 0))
+    return;
+
+  for (unsigned int i=0; i<str_len; i++)
+    smival.value.oid.ptr[i] = str[i];
+
+  smival.value.oid.len = str_len;
+  m_changed = true;
+}
+
+//===============[Oid::trim(unsigned int) ]============================
+// trim off the n leftmost values of an oid
+// Note!, does not adjust actual space for
+// speed
+void Oid::trim(const unsigned long n)
+{
+  // verify that n is legal
+  if ((n <= smival.value.oid.len) && (n > 0))
+  {
+    smival.value.oid.len -= n;
+    if (smival.value.oid.len == 0)
+      delete_oid_ptr();
+    m_changed = true;
+  }
+}
+
+//===============[Oid::operator += const unsigned int) ]====================
+// append operator, appends an int
+//
+Oid& Oid::operator+=(const unsigned long i)
+{
+  Oid other(&i, 1);
+  (*this) += other;
+  return *this;
+}
+
+//===============[Oid::operator += const Oid) ]========================
+// append operator, appends an Oid
+//
+// allocate some space for a max oid string
+// extract current string into space
+// concat new string
+// free up existing oid
+// make a new oid from string
+// delete allocated space
+Oid& Oid::operator+=(const Oid &o)
+{
+  SmiLPUINT32 new_oid;
+
+  if (o.smival.value.oid.len == 0)
+    return *this;
+
+  new_oid = (SmiLPUINT32) new unsigned long[smival.value.oid.len + o.smival.value.oid.len];
+  if (new_oid == 0)
+  {
+    delete_oid_ptr();
+    return *this;
+  }
+
+  if (smival.value.oid.ptr)
+  {
+    MEMCPY((SmiLPBYTE) new_oid,
+           (SmiLPBYTE) smival.value.oid.ptr,
+           (size_t) (smival.value.oid.len*sizeof(SmiUINT32)));
+
+    delete [] smival.value.oid.ptr;
+  }
+
+  // out with the old, in with the new...
+  smival.value.oid.ptr = new_oid;
+
+  MEMCPY((SmiLPBYTE) &new_oid[smival.value.oid.len],
+         (SmiLPBYTE) o.smival.value.oid.ptr,
+         (size_t) (o.smival.value.oid.len*sizeof(SmiUINT32)));
+
+  smival.value.oid.len += o.smival.value.oid.len;
+
+  m_changed = true;
+  return *this;
+}
+
+//==============[Oid::get_printable(unsigned int start, n) ]=============
+// return a dotted string starting at start,
+// going n positions to the left
+// NOTE, start is 1 based (the first id is at position #1)
+const char *Oid::get_printable(const unsigned long start,
+                               const unsigned long n,
+                               char *&buffer) const
+{
+  if (!m_changed && (buffer == iv_str))  return buffer;
+
+  unsigned long nz;
+  unsigned long my_start = start - 1;
+  unsigned long my_end   = my_start + n;
+
+  nz = (smival.value.oid.len * (SNMPCHARSIZE + 1)) + 1;
+
+  if (buffer) delete [] buffer;  // delete the previous output string
+
+  buffer = new char[nz];  // allocate some space for the output string
+  if (buffer == 0)
+    return 0;
+
+  buffer[0] = 0;  // init the string
+
+  // cannot ask for more than there is..
+  if ((start == 0) || (my_end > smival.value.oid.len))
+    return buffer;
+
+  char *cur_ptr = buffer;
+  bool first = true;
+
+  // loop through and build up a string
+  for (unsigned long index = my_start; index < my_end; ++index)
+  {
+    // if not at begin, pad with a dot
+    if (first)
+      first = false;
+    else
+      *cur_ptr++ = '.';
+
+    // convert data element to a string
+    cur_ptr += sprintf(cur_ptr, "%lu", smival.value.oid.ptr[index]);
+  }
+
+  if (buffer == iv_str)
+  {
+    Oid *nc_this = PP_CONST_CAST(Oid*, this);
+    nc_this->m_changed = false;
+  }
+
+  return buffer;
+}
+
+
+//=============[Oid::StrToOid(char *string, SmiLPOID dst) ]==============
+// convert a string to an oid
+int Oid::StrToOid(const char *str, SmiLPOID dstOid) const
+{
+  unsigned int index = 0;
+
+  // make a temp buffer to copy the data into first
+  SmiLPUINT32 temp;
+  unsigned int nz;
+
+  if (str && *str)
+  {
+    nz = SAFE_UINT_CAST(strlen(str));
+  }
+  else
+  {
+    dstOid->len = 0;
+    dstOid->ptr = 0;
+    return -1;
+  }
+  temp = (SmiLPUINT32) new unsigned long[nz];
+
+  if (temp == 0) return -1;   // return if can't get the mem
+
+  while ((*str) && (index < nz))
+  {
+    // skip over the dot
+    if (*str == '.') ++str;
+
+    // convert digits
+    if (my_isdigit(*str))
+    {
+      unsigned long number = 0;
+
+      // grab a digit token and convert it to a long int
+      while (my_isdigit(*str))
+        number = (number * 10) + *(str++) - '0';
+
+      // stuff the value into the array and bump the counter
+      temp[index++] = number;
+
+      // there must be a dot or end of string now
+      if ((*str) && (*str != '.'))
+      {
+        delete [] temp;
+        return -1;
+      }
+    }
+
+    // check for other chars
+    if ((*str) && (*str != '.'))
+    {
+      // found String -> converting it into an oid
+      if (*str != '$')
+      {
+        delete [] temp;
+        return -1;
+      }
+
+      // skip $
+      ++str;
+
+      // copy until second $
+      while ((*str) && (*str != '$'))
+      {
+        temp[index] = (unsigned char)*str;
+        ++str;
+        ++index;
+      }
+
+      if (*str != '$')
+      {
+        delete [] temp;
+        return -1;
+      }
+
+      // skip over the $
+      ++str;
+
+      // there must be a dot or end of string now
+      if ((*str) && (*str != '.'))
+      {
+        delete [] temp;
+        return -1;
+      }
+    }
+  }
+
+  // get some space for the real oid
+  dstOid->ptr = (SmiLPUINT32) new unsigned long[index];
+  // return if can't get the mem needed
+  if(dstOid->ptr == 0)
+  {
+    delete [] temp;
+    return -1;
+  }
+
+  // copy in the temp data
+  MEMCPY((SmiLPBYTE) dstOid->ptr,
+         (SmiLPBYTE) temp,
+         (size_t) (index*sizeof(SmiUINT32)));
+
+  // set the len of the oid
+  dstOid->len = index;
+
+  // free up temp data
+  delete [] temp;
+
+  return (int) index;
+}
+
+
+//===============[Oid::OidCopy(source, destination) ]====================
+// Copy an oid
+int Oid::OidCopy(SmiLPOID srcOid, SmiLPOID dstOid) const
+{
+  // check source len ! zero
+  if (srcOid->len == 0) return -1;
+
+  // copy source to destination
+  MEMCPY((SmiLPBYTE) dstOid->ptr,
+         (SmiLPBYTE) srcOid->ptr,
+         (size_t) (srcOid->len*sizeof(SmiUINT32)));
+
+  //set the new len
+  dstOid->len = srcOid->len;
+  return (int) srcOid->len;
+}
+
+
+//===============[Oid::nCompare(n, Oid) ]=================================
+// compare the n leftmost values of two oids (left-to_right )
+//
+// self == Oid then return 0, they are equal
+// self < Oid then return -1, <
+// self > Oid then return 1,  >
+int Oid::nCompare(const unsigned long n,
+                  const Oid &o) const
+{
+  unsigned long length = n;
+  bool reduced_len = false;
+
+  // If both oids are too short, decrease len
+  while ((smival.value.oid.len < length) && (o.smival.value.oid.len < length))
+    length--;
+
+  if (length == 0) return 0; // equal
+    
+  // only compare for the minimal length
+  if (length > smival.value.oid.len)
+  {
+    length = smival.value.oid.len;
+    reduced_len = true;
+  }
+  if (length > o.smival.value.oid.len)
+  {
+    length = o.smival.value.oid.len;
+    reduced_len = true;
+  }
+
+  unsigned long z = 0;
+  while (z < length)
+  {
+    if (smival.value.oid.ptr[z] < o.smival.value.oid.ptr[z])
+      return -1;                              // less than
+    if (smival.value.oid.ptr[z] > o.smival.value.oid.ptr[z])
+      return 1;                               // greater than
+    ++z;
+  }
+
+  // if we truncated the len then these may not be equal
+  if (reduced_len)
+  {
+    if (smival.value.oid.len < o.smival.value.oid.len) return -1;
+    if (smival.value.oid.len > o.smival.value.oid.len) return 1;
+  }
+  return 0;                                 // equal
+}
+
+//================[Oid::OidToStr ]=========================================
+// convert an oid to a string
+int Oid::OidToStr(const SmiOID *srcOid,
+                  SmiUINT32 size,
+                  char *str) const
+{
+  unsigned totLen = 0;
+  char szNumber[SNMPBUFFSIZE];
+  int cur_len;
+
+  str[0] = 0;   // init the string
+
+  // verify there is something to copy
+  if (srcOid->len == 0)
+    return -1;
+
+  // loop through and build up a string
+  for (unsigned long index = 0; index < srcOid->len; ++index)
+  {
+    // convert data element to a string
+    cur_len = sprintf(szNumber, "%lu", srcOid->ptr[index]);
+
+    // verify len is not over
+    if (totLen + cur_len + 1 >= size)
+      return -2;
+
+    // if not at begin, pad with a dot
+    if (totLen)
+      str[totLen++] = '.';
+
+    // copy the string token into the main string
+    STRCPY(str + totLen, szNumber);
+
+    // adjust the total len
+    totLen += cur_len;
+  }
+  return totLen+1;
+}
+
+
+//================[ general Value = operator ]========================
+SnmpSyntax& Oid::operator=(const SnmpSyntax &val)
+{
+  if (this == &val) return *this; // protect against assignment from self
+
+  delete_oid_ptr();
+
+  // assign new value
+  if (val.valid())
+  {
+    switch (val.get_syntax())
+    {
+      case sNMP_SYNTAX_OID:
+        set_data(((Oid &)val).smival.value.oid.ptr,
+                  (unsigned int)((Oid &)val).smival.value.oid.len);
+        break;
+    }
+  }
+  return *this;
+}
+
+int Oid::get_asn1_length() const
+{
+  int length = 1; // for first 2 subids
+
+  for (unsigned int i = 2; i < smival.value.oid.len; ++i)
+  {
+    unsigned long v = smival.value.oid.ptr[i];
+
+    if      (v <       0x80) //  7 bits long subid 
+      length += 1;
+    else if (v <     0x4000) // 14 bits long subid
+      length += 2;
+    else if (v <   0x200000) // 21 bits long subid
+      length += 3;
+    else if (v < 0x10000000) // 28 bits long subid
+      length += 4;
+    else                     // 32 bits long subid
+      length += 5;
+  }
+
+  if (length < 128)
+    return length + 2;
+  else if (length < 256)
+    return length + 3;
+  return length + 4;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/pdu.cpp b/3rdparty/snmp++/src/pdu.cpp
new file mode 100644 (file)
index 0000000..e142018
--- /dev/null
@@ -0,0 +1,585 @@
+/*_############################################################################
+  _## 
+  _##  pdu.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  P D U . C P P
+
+  PDU CLASS IMPLEMENTATION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  Pdu class implementation. Encapsulation of an SMI Protocol
+  Data Unit (PDU) in C++.
+
+=====================================================================*/
+char pdu_cpp_version[]="@(#) SNMP++ $Id: pdu.cpp 209 2006-01-07 20:02:34Z katz $";
+
+#include "snmp_pp/pdu.h"       // include Pdu class definition
+#include "snmp_pp/usm_v3.h"
+#include "snmp_pp/vb.h"
+#include "snmp_pp/v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define PDU_INITIAL_SIZE 25
+
+//=====================[ constructor no args ]=========================
+Pdu::Pdu()
+  : vbs(0), vbs_size(0), vb_count(0), error_status(0), error_index(0),
+    validity(true), request_id(0), pdu_type(0), notify_timestamp(0),
+    v1_trap_address_set(false)
+#ifdef _SNMPv3
+    , security_level(SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV),
+    message_id(0), maxsize_scopedpdu(0)
+#endif
+{
+}
+
+//=====================[ constructor with vbs and count ]==============
+Pdu::Pdu(Vb* pvbs, const int pvb_count)
+  : vbs(0), vbs_size(0), vb_count(0), error_status(0), error_index(0),
+    validity(true), request_id(0), pdu_type(0), notify_timestamp(0),
+    v1_trap_address_set(false)
+#ifdef _SNMPv3
+    , security_level(SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV),
+    message_id(0), maxsize_scopedpdu(0)
+#endif
+{
+  if (pvb_count == 0) return;    // zero is ok
+
+  vbs = new Vb*[pvb_count];
+  if (vbs)
+    vbs_size = pvb_count;
+  else
+  {
+    vbs_size = 0;
+    validity = false;
+    return;
+  }
+
+  // loop through and assign internal vbs
+  for (int z = 0; z < pvb_count; ++z)
+  {
+    if (pvbs[z].valid())
+      vbs[z] = new Vb(pvbs[z]);
+    else
+      vbs[z] = 0;
+
+    if ((vbs[z]) && !vbs[z]->valid())
+    {
+      delete vbs[z];
+      vbs[z] = 0;
+    }
+
+    if (vbs[z] == 0)     // check for new fail
+    {
+      for (int y = 0; y < z; ++y) delete vbs[y]; // free vbs
+      validity = false;
+      return;
+    }
+  }
+
+  vb_count = pvb_count;   // assign the vb count
+}
+
+//=====================[ destructor ]====================================
+Pdu::~Pdu()
+{
+  for (int z = 0; z < vb_count; ++z)
+  {
+    delete vbs[z];
+    vbs[z] = 0;
+  }
+
+  if (vbs)
+  {
+    delete [] vbs;
+    vbs = 0;
+    vbs_size = 0;
+  }
+}
+
+//=====================[ assignment to another Pdu object overloaded ]===
+Pdu& Pdu::operator=(const Pdu &pdu)
+{
+  if (this == &pdu) return *this; // check for self assignment
+
+  // Initialize all mv's
+  error_status      = pdu.error_status;
+  error_index       = pdu.error_index;
+  request_id        = pdu.request_id;
+  pdu_type          = pdu.pdu_type;
+  notify_id         = pdu.notify_id;
+  notify_timestamp  = pdu.notify_timestamp;
+  notify_enterprise = pdu.notify_enterprise;
+#ifdef _SNMPv3
+  security_level    = pdu.security_level;
+  message_id        = pdu.message_id;
+  context_name      = pdu.context_name;
+  context_engine_id = pdu.context_engine_id;
+  maxsize_scopedpdu = pdu.maxsize_scopedpdu;
+#endif
+  if (pdu.v1_trap_address_set)
+  {
+    v1_trap_address = pdu.v1_trap_address;
+    v1_trap_address_set = true;
+  }
+  else
+    v1_trap_address_set = false;
+
+  validity = true;
+
+  // free up old vbs
+  for (int z = 0; z < vb_count; ++z)  delete vbs[z];
+  vb_count = 0;
+
+  // check for zero case
+  if (pdu.vb_count == 0) return *this;
+
+  // allocate array
+  if (vbs_size < pdu.vb_count)
+  {
+    delete [] vbs;
+    vbs = new Vb*[pdu.vb_count];
+    if (vbs)
+      vbs_size = pdu.vb_count;
+    else
+    {
+      vbs_size = 0;
+      validity = false;
+      return *this;
+    }
+  }
+
+  // loop through and fill em up
+  for (int y = 0; y < pdu.vb_count; ++y)
+  {
+    vbs[y] = new Vb(*(pdu.vbs[y]));
+
+    if ((vbs[y]) && !vbs[y]->valid())
+    {
+      delete vbs[y];
+      vbs[y] = 0;
+    }
+
+    if (!vbs[y])
+    {
+      for (int x = 0; x < y; ++x) delete vbs[x]; // free vbs
+      validity = false;
+      return *this;
+    }
+  }
+
+  vb_count = pdu.vb_count;
+  return *this;
+}
+
+// append operator, appends a variable binding
+Pdu& Pdu::operator+=(const Vb &vb)
+{
+  if (!vb.valid())                return *this; // dont add invalid Vbs
+
+  if (vb_count + 1 > vbs_size)
+  {
+    if (!extend_vbs()) return *this;
+  }
+
+  vbs[vb_count] = new Vb(vb);  // add the new one
+
+  if (vbs[vb_count])   // up the vb count on success
+  {
+    if (vbs[vb_count]->valid())
+    {
+      ++vb_count;
+      validity = true;   // set up validity
+    }
+    else
+    {
+      delete vbs[vb_count];
+      vbs[vb_count] = 0;
+    }
+  }
+
+  return *this;        // return self reference
+}
+
+//=====================[ extract Vbs from Pdu ]==========================
+int Pdu::get_vblist(Vb* pvbs, const int pvb_count) const
+{
+  if ((!pvbs) || (pvb_count < 0) || (pvb_count > vb_count))
+    return false;
+
+  // loop through all vbs and assign to params
+  for (int z = 0; z < pvb_count; ++z)
+  {
+    pvbs[z] = *vbs[z];
+    if (!pvbs[z].valid())
+      return false;
+  }
+
+  return true;
+}
+
+//=====================[ deposit Vbs ]===================================
+int Pdu::set_vblist(Vb* pvbs, const int pvb_count)
+{
+  // if invalid then don't destroy
+  if (((!pvbs) && (pvb_count > 0)) ||
+      (pvb_count < 0))
+    return false;
+
+  // free up current vbs
+  for (int z = 0; z < vb_count; ++z)  delete vbs[z];
+  vb_count = 0;
+
+  // check for zero case
+  if (pvb_count == 0)
+  {
+    validity = true;
+    error_status = 0;
+    error_index = 0;
+    request_id = 0;
+    return false;
+  }
+
+  // allocate array
+  if (vbs_size < pvb_count)
+  {
+    delete [] vbs;
+    vbs = new Vb*[pvb_count];
+    if (vbs)
+      vbs_size = pvb_count;
+    else
+    {
+      vbs_size = 0;
+      validity = false;
+      return false;
+    }
+  }
+
+  // loop through all vbs and reassign them
+  for (int y = 0; y < pvb_count; ++y)
+  {
+    if (pvbs[y].valid())
+    {
+      vbs[y] = new Vb(pvbs[y]);
+      if ((vbs[y]) && !vbs[y]->valid())
+      {
+       delete vbs[y];
+       vbs[y] = 0;
+      }
+    }
+    else
+      vbs[y] = 0;
+
+    // check for errors
+    if (!vbs[y])
+    {
+      for (int x = 0; x < y; ++x) delete vbs[x]; // free vbs
+      validity = false;
+      return false;
+    }
+  }
+
+  vb_count = pvb_count;
+
+  // clear error status and index since no longer valid
+  // request id may still apply so don't reassign it
+  error_status = 0;
+  error_index = 0;
+  validity = true;
+
+  return true;
+}
+
+//===================[ get a particular vb ]=============================
+// here the caller has already instantiated a vb object
+// index is zero based
+int Pdu::get_vb(Vb &vb, const int index) const
+{
+   if (index < 0)         return false; // can't have an index less than 0
+   if (index >= vb_count) return false; // can't ask for something not there
+
+   vb = *vbs[index];   // asssign it
+
+   return vb.valid();
+}
+
+//===================[ set a particular vb ]=============================
+int Pdu::set_vb(Vb &vb, const int index)
+{
+  if (index < 0)         return false; // can't have an index less than 0
+  if (index >= vb_count) return false; // can't ask for something not there
+  if (!vb.valid())       return false; // don't set invalid vbs
+
+  Vb *victim = vbs[index]; // save in case new fails
+  vbs[index] = new Vb(vb);
+  if (vbs[index])
+  {
+    if (vbs[index]->valid())
+    {
+      delete victim;
+    }
+    else
+    {
+      delete vbs[index];
+      vbs[index] = victim;
+      return false;
+    }
+  }
+  else
+  {
+    vbs[index] = victim;
+    return false;
+  }
+  return true;
+}
+
+// trim off the last vb
+int Pdu::trim(const int count)
+{
+  // verify that count is legal
+  if ((count < 0) || (count > vb_count)) return false;
+
+  int lp = count;
+
+  while (lp != 0)
+  {
+    if (vb_count > 0)
+    {
+      delete vbs[vb_count-1];
+      vbs[vb_count-1] = 0;
+      vb_count--;
+    }
+    lp--;
+  }
+  return true;
+}
+
+// delete a Vb anywhere within the Pdu
+int Pdu::delete_vb(const int p)
+{
+  // position has to be in range
+  if ((p<0) || (p > vb_count - 1)) return false;
+
+  delete vbs[p];   // safe to remove it
+
+  for (int z = p; z < vb_count - 1; ++z)
+    vbs[z] = vbs[z+1];
+
+  vb_count--;
+
+  return true;
+}
+
+
+// Get the SNMPv1 trap address
+int Pdu::get_v1_trap_address(GenAddress &address) const
+{
+  if (v1_trap_address_set == false)
+    return false;
+
+  address = v1_trap_address;
+  return true;
+}
+
+// Set the SNMPv1 trap address
+int Pdu::set_v1_trap_address(const Address &address)
+{
+  v1_trap_address = address;
+  v1_trap_address_set = (v1_trap_address.valid() == true);
+
+  return v1_trap_address_set;
+}
+
+int Pdu::get_asn1_length() const
+{
+  int length = 0;
+
+  // length for all vbs
+  for (int i = 0; i < vb_count; ++i)
+    length += vbs[i]->get_asn1_length();
+
+  // header for vbs
+  if      (length < 0x80)      length += 2;
+  else if (length <= 0xFF)     length += 3;
+  else if (length <= 0xFFFF)   length += 4;
+  else if (length <= 0xFFFFFF) length += 5;
+  else                         length += 6;
+
+  // req id, error status, error index
+  SnmpInt32 i32(request_id ? request_id : PDU_MAX_RID);
+  length += i32.get_asn1_length();
+  i32 = error_status;
+  length += i32.get_asn1_length();
+  i32 = error_index;
+  length += i32.get_asn1_length();
+    
+  // header for data_pdu
+  if      (length < 0x80)      length += 2;
+  else if (length <= 0xFF)     length += 3;
+  else if (length <= 0xFFFF)   length += 4;
+  else if (length <= 0xFFFFFF) length += 5;
+  else                         length += 6;
+
+#ifdef _SNMPv3
+  // now the scopedpdu part sequence (4), context engine, id context name
+  length += 4 + 2 + context_engine_id.len() + 2 + context_name.len();
+
+  // An encrypted message is transported as an octet string 
+  if (security_level == SNMP_SECURITY_LEVEL_AUTH_PRIV)
+  {
+    // assume that encryption increases the data to a multiple of 16
+    int mod = length % 16;
+    if (mod) length += 16 - mod;
+
+    length += 4;
+  }
+#endif
+
+  return length;
+}
+
+// extend the vbs array
+bool Pdu::extend_vbs()
+{
+  if (vbs_size == 0)
+  {
+    vbs = new Vb*[PDU_INITIAL_SIZE];
+    if (vbs)
+    {
+      vbs_size = PDU_INITIAL_SIZE;
+      return true;
+    }
+    else
+       return false;
+  }
+
+  Vb **tmp = vbs;
+  vbs = new Vb*[vbs_size * 2];
+  if (!vbs)
+  {
+    vbs = tmp;
+    return false;
+  }
+
+  for (int y = 0; y < vb_count; ++y)
+    vbs[y] = tmp[y];
+  vbs_size *= 2;
+  delete [] tmp;
+  return true;
+}
+
+// Clear all members of the object
+void Pdu::clear()
+{
+  error_status        = 0;
+  error_index         = 0;
+  request_id          = 0;
+  pdu_type            = 0;
+  notify_timestamp    = 0;
+  notify_id.clear();
+  notify_enterprise.clear();
+  v1_trap_address_set = false;
+  validity            = true;
+
+  for (int z = 0; z < vb_count; ++z)  delete vbs[z];
+  vb_count = 0;
+
+#ifdef _SNMPv3
+  security_level    = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+  message_id        = 0;
+  maxsize_scopedpdu = 0;
+  context_name.clear();
+  context_engine_id.clear();
+#endif // _SNMPv3
+}
+
+// Does the type of response match the type of request
+bool Pdu::match_type(const int request, const int response)
+{
+  switch (request)
+  {
+    case sNMP_PDU_GET:
+    case sNMP_PDU_GETNEXT:
+    case sNMP_PDU_SET:
+    case sNMP_PDU_GETBULK:
+    case sNMP_PDU_INFORM:
+    {
+      if ((response == sNMP_PDU_RESPONSE) ||
+         (response == sNMP_PDU_REPORT))
+       return true;
+      if ((response == sNMP_PDU_GET) ||
+         (response == sNMP_PDU_GETNEXT) ||
+         (response == sNMP_PDU_SET) ||
+         (response == sNMP_PDU_GETBULK) ||
+         (response == sNMP_PDU_INFORM) ||
+         (response == sNMP_PDU_V1TRAP) ||
+         (response == sNMP_PDU_TRAP))
+      {
+       debugprintf(0, "Unknown response pdu type (%d).", response);
+      }
+      return false;
+    }
+    case sNMP_PDU_REPORT:
+    case sNMP_PDU_RESPONSE:
+    case sNMP_PDU_V1TRAP:
+    case sNMP_PDU_TRAP:
+    {
+      return false;
+    }
+    default:
+    {
+      debugprintf(0, "Unknown request pdu type (%d).", request);
+      return false;
+    }
+  }
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/reentrant.cpp b/3rdparty/snmp++/src/reentrant.cpp
new file mode 100644 (file)
index 0000000..1a9f917
--- /dev/null
@@ -0,0 +1,93 @@
+/*_############################################################################
+  _## 
+  _##  reentrant.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+char reentrant_cpp_version[]="#(@) SNMP++ $Id: reentrant.cpp 179 2005-09-19 19:59:36Z fock $";
+
+#include "snmp_pp/reentrant.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+SnmpSynchronized::SnmpSynchronized()
+{
+#ifdef _THREADS
+#ifdef WIN32
+       InitializeCriticalSection(&_mutex);
+#elif defined (CPU) && CPU == PPC603
+       _mutex = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE | SEM_INVERSION_SAFE );
+#else
+       pthread_mutex_init(&_mutex, 0);
+#endif
+#endif
+}
+
+SnmpSynchronized::~SnmpSynchronized()
+{
+#ifdef _THREADS
+#ifdef WIN32
+       DeleteCriticalSection(&_mutex);
+#elif defined (CPU) && CPU == PPC603
+       semTake(_mutex, WAIT_FOREVER);
+       semDelete(_mutex);
+#else
+       pthread_mutex_destroy(&_mutex);
+#endif
+#endif
+}
+
+void SnmpSynchronized::lock()
+{
+#ifdef _THREADS
+#ifdef WIN32
+       EnterCriticalSection(&_mutex);
+#elif defined (CPU) && CPU == PPC603
+    semTake(_mutex, WAIT_FOREVER);
+#else
+       pthread_mutex_lock(&_mutex);
+#endif
+#endif
+}      
+
+void SnmpSynchronized::unlock()
+{
+#ifdef _THREADS
+#ifdef WIN32
+       LeaveCriticalSection(&_mutex);
+#elif defined (CPU) && CPU == PPC603
+    semGive(_mutex);
+#else
+       pthread_mutex_unlock(&_mutex);
+#endif
+#endif
+}      
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
+
diff --git a/3rdparty/snmp++/src/sha.cpp b/3rdparty/snmp++/src/sha.cpp
new file mode 100644 (file)
index 0000000..0019351
--- /dev/null
@@ -0,0 +1,287 @@
+/*_############################################################################
+  _## 
+  _##  sha.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+char sha_cpp_version[]="#(@) SNMP++ $Id: sha.cpp 1549 2009-06-26 19:42:55Z katz $";
+
+#include "snmp_pp/sha.h"
+
+#if !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
+
+/*****************************************************************
+ * SHS.c  -  Secure Hash Standard (draft) FIPS 180-1             *
+ *                                                               *
+ * Copyright (C) 1994  Uri Blumenthal, uri@watson.ibm.com        *
+ * Copyright (C) 1994  IBM T. J. Watson esearch Center           *
+ *                                                               *
+ * Feel free to use this code,  as long as you acknowledge the   *
+ * ownership by U. Blumenthal and IBM Corp.  and agree to hold   *
+ * both harmless in case of ANY problem you may have with this   *
+ * code.                                                         *
+ *****************************************************************/
+
+#if !(defined (CPU) && CPU == PPC603)
+#include <memory.h>
+#else
+#include <string.h>
+#endif
+#include <stdio.h>
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define K1 0x5A827999
+#define K2 0x6ED9EBA1
+#define K3 0x8F1BBCDC
+#define K4 0xCA62C1D6
+
+#define F1(B, C, D) ((B & C) | (~B & D))
+#define F2(B, C, D) (B ^ C ^ D)
+#define F3(B, C, D) ((B & C) | (B & D) | (C & D))
+#define F4(B, C, D) (B ^ C ^ D)
+
+#define ROL(A, K) ((A << K) | (A >> (32 - K)))
+
+#if !defined(i386) && !defined(_IBMR2)
+static int msb_flag = 0;    /* ENDIAN-ness of CPU    */
+#endif
+
+static void SHATransform(SHA_CTX *ctx, const unsigned char *X)
+{
+  unsigned /* long */ int a, b, c, d, e, temp = 0;
+  unsigned /* long */ int W[80]; /* Work array for SHS    */
+  int i;
+
+#ifdef _IBMR2
+    unsigned long int *p = (unsigned long int *)X;
+    memcpy((char *)&W[0], p, 64);
+#else
+#ifndef i386
+  unsigned long int *p = (unsigned long int *)X;
+  if (msb_flag)
+    memcpy((char *)&W[0], p, 64);
+  else
+#endif /* ~i386 */
+    for (i = 0; i < 64; i += 4)
+      W[(i/4)] = X[i+3] | (X[i+2] << 8) |
+       (X[i+1] << 16) | (X[i] << 24);
+#endif /* _IBMR2 */
+
+  for (i = 16; i < 80; i++)
+    W[i] = ROL((W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]), 1);
+
+  a = ctx->h[0];
+  b = ctx->h[1];
+  c = ctx->h[2];
+  d = ctx->h[3];
+  e = ctx->h[4];
+
+  for (i =  0; i <= 19; i++) {
+    temp = ROL(a, 5) + F1(b, c, d) + e + K1 + W[i];
+    e = d; d = c; c = ROL(b, 30); b = a; a = temp;
+  }
+
+  for (i = 20; i <= 39; i++) {
+    temp = ROL(a, 5) + F2(b, c, d) + e + K2 + W[i];
+    e = d; d = c; c = ROL(b, 30); b = a; a = temp;
+  }
+
+  for (i = 40; i <= 59; i++) {
+    temp = ROL(a, 5) + F3(b, c, d) + e + K3 + W[i];
+    e = d; d = c; c = ROL(b, 30); b = a; a = temp;
+  }
+
+  for (i = 60; i <= 79; i++) {
+    temp = ROL(a, 5) + F4(b, c, d) + e + K4 + W[i];
+    e = d; d = c; c = ROL(b, 30); b = a; a = temp;
+  }
+
+  ctx->h[0] += a;
+  ctx->h[1] += b;
+  ctx->h[2] += c;
+  ctx->h[3] += d;
+  ctx->h[4] += e;
+}
+
+
+void SHAInit(SHA_CTX *ctx)
+{
+#if !defined(i386) && !defined(_IBMR2)
+  union z_test {
+    unsigned char ch[4];
+    unsigned long ll;
+  } z_t;
+#endif
+  /* Zero the SHS Context */
+  memset((char *)ctx, 0, sizeof(*ctx));
+
+  /* Prime the SHS with "magic" init constants */
+  ctx->h[0] = 0x67452301;
+  ctx->h[1] = 0xEFCDAB89;
+  ctx->h[2] = 0x98BADCFE;
+  ctx->h[3] = 0x10325476;
+  ctx->h[4] = 0xC3D2E1F0;
+
+#if !defined(i386) && !defined(_IBMR2)
+  /* Determine the ENDIAN-ness of the CPU */
+  z_t.ll = 0;
+
+  z_t.ch[0] = 0x01;
+
+  if (z_t.ll == 0x01000000)
+    msb_flag = 1;
+  else {
+    if (z_t.ll == 0x00000001)
+      msb_flag = 0;
+    else
+      printf("ENDIAN-ness is SCREWED! (%0#lx)\n", z_t.ll);
+  }
+#endif /* ~_IBMR2 & ~i386 */
+}
+
+
+void SHAUpdate(SHA_CTX *ctx, const unsigned char *buf, unsigned int lenBuf)
+{
+  /* Do we have any bytes? */
+  if (lenBuf == 0) return;
+
+  /* Calculate buf len in bits and update the len count */
+  ctx->count[0] += (lenBuf << 3);
+  if (ctx->count[0] < (lenBuf << 3))
+    ctx->count[1] += 1;
+  ctx->count[1] += (lenBuf >> 29);
+
+  /* Fill the hash working buffer for the first run, if  */
+  /* we have enough data...                              */
+  int i = 64 - ctx->index;  /* either fill it up to 64 bytes */
+  if ((int)lenBuf < i) i = lenBuf; /* or put the whole data...*/
+
+  lenBuf -= i;  /* Reflect the data we'll put in the buf */
+
+  /* Physically put the data in the hash workbuf */
+  memcpy((char *)&(ctx->X[ctx->index]), buf, i);
+  buf += i; ctx->index += i;
+
+  /* Adjust the buf index */
+  if (ctx->index == 64)
+    ctx->index = 0;
+
+  /* Let's see whether we're equal to 64 bytes in buf  */
+  if (ctx->index == 0)
+    SHATransform(ctx, ctx->X);
+
+  /* Process full 64-byte blocks */
+  while(lenBuf >= 64) {
+    lenBuf -= 64;
+    SHATransform(ctx, buf);
+    buf += 64;
+  }
+
+  /* Put the rest of data in the hash buf for next run */
+  if (lenBuf > 0) {
+    memcpy(ctx->X, buf, lenBuf);
+    ctx->index = lenBuf;
+  }
+}
+
+
+void SHAFinal(unsigned char *digest, SHA_CTX *ctx)
+{
+  int i;
+  unsigned long int c0, c1;
+  unsigned char truelen[8];
+  static unsigned char padding[64] = {
+    0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,  /*  8 */
+    0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,  /* 16 */
+    0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,  /* 24 */
+    0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,  /* 32 */
+    0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,  /* 40 */
+    0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,  /* 48 */
+    0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,  /* 56 */
+    0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; /* 64 */
+                                       
+  /* Store the message length to append after */
+  /* padding is done... */
+
+#ifdef _IBMR2
+    memcpy(truelen, (char *) &(ctx->count[1]), 4);
+    memcpy(&truelen[4], (char *) &(ctx->count[0]), 4);
+#else
+#ifndef i386
+  if (msb_flag) {
+    memcpy(truelen, (char *) &(ctx->count[1]), 4);
+    memcpy(&truelen[4], (char *) &(ctx->count[0]), 4);
+  } else
+#endif /* ~i386 */
+  {
+    c0 = ctx->count[0]; c1 = ctx->count[1];
+    for (i = 7; i >=0; i--) {
+      truelen[i] = (unsigned char) (c0 & 0xff);
+      c0 = (c0 >> 8) | (((c1 >> 8) & 0xff) << 24);
+      c1 = (c1 >> 8);
+    }
+  }
+#endif /* _IBMR2 */
+
+  /* How many padding bytes do we need? */
+  i = (ctx->count[0] >> 3) & 0x3f;  /* # of bytes mod 64 */
+  if (i >= 56) i = 120 - i; /* # of padding bytes needed */
+  else i = 56 - i;
+
+
+  SHAUpdate(ctx, padding, i);   /* Append the padding */
+  SHAUpdate(ctx, truelen, 8);   /* Append the length  */
+
+#ifdef _IBMR2
+    memcpy(digest, (char *)&ctx->h[0], 20);
+#else
+#ifndef i386
+  if (msb_flag)
+    memcpy(digest, (char *)&ctx->h[0], 20);
+  else
+#endif /* ~i386 */
+    for (i = 0; i < 4; i++) {
+      digest[3-i]  = (unsigned char) (ctx->h[0] & 0xff);
+      ctx->h[0] >>= 8;
+      digest[7-i]  = (unsigned char) (ctx->h[1] & 0xff);
+      ctx->h[1] >>= 8;
+      digest[11-i] = (unsigned char) (ctx->h[2] & 0xff);
+      ctx->h[2] >>= 8;
+      digest[15-i] = (unsigned char) (ctx->h[3] & 0xff);
+      ctx->h[3] >>= 8;
+      digest[19-i] = (unsigned char) (ctx->h[4] & 0xff);
+      ctx->h[4] >>= 8;
+    }
+#endif /* _IBMR2 */
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
+
+#endif // !defined(_USE_LIBTOMCRYPT) && !defined(_USE_OPENSSL)
diff --git a/3rdparty/snmp++/src/snmpmsg.cpp b/3rdparty/snmp++/src/snmpmsg.cpp
new file mode 100644 (file)
index 0000000..a1036fc
--- /dev/null
@@ -0,0 +1,832 @@
+/*_############################################################################
+  _## 
+  _##  snmpmsg.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1996
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+  SNMP++ S N M P M S G . C P P
+
+  SNMPMESSAGE CLASS DEFINITION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:      ASN.1      encoding / decoding class
+=====================================================================*/
+char snmpmsg_cpp_version[]="#(@) SNMP++ $Id: snmpmsg.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+#if defined(_AIX)
+#include <unistd.h>
+#endif
+#if defined(__APPLE__)
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include <stdio.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/snmpmsg.h"                    // header file for SnmpMessage
+#include "snmp_pp/oid_def.h"                    // changed (Frank Fock)
+#include "snmp_pp/log.h"
+#include "snmp_pp/vb.h"
+#include "snmp_pp/usm_v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define MAX_LEN_COMMUNITY 254
+
+const coldStartOid coldStart;
+const warmStartOid warmStart;
+const linkDownOid linkDown;
+const linkUpOid linkUp;
+const authenticationFailureOid authenticationFailure;
+const egpNeighborLossOid egpNeighborLoss;
+const snmpTrapEnterpriseOid snmpTrapEnterprise;
+
+//------------[ convert SNMP++ VB to WinSNMP smiVALUE ]----------------
+int convertVbToSmival( const Vb &tempvb, SmiVALUE *smival )
+{
+  smival->syntax = tempvb.get_syntax();
+  switch ( smival->syntax ) {
+
+    // case sNMP_SYNTAX_NULL
+  case sNMP_SYNTAX_NULL:
+  case sNMP_SYNTAX_NOSUCHOBJECT:
+  case sNMP_SYNTAX_NOSUCHINSTANCE:
+  case sNMP_SYNTAX_ENDOFMIBVIEW:
+    break;
+
+    // case sNMP_SYNTAX_INT32:
+  case sNMP_SYNTAX_INT:
+    tempvb.get_value(smival->value.sNumber);
+    break;
+
+    //    case sNMP_SYNTAX_UINT32:
+  case sNMP_SYNTAX_GAUGE32:
+  case sNMP_SYNTAX_CNTR32:
+  case sNMP_SYNTAX_TIMETICKS:
+    //  case sNMP_SYNTAX_UINT32:
+    tempvb.get_value(smival->value.uNumber);
+    break;
+
+    // case Counter64
+  case sNMP_SYNTAX_CNTR64:
+    {
+      Counter64 c64;
+      tempvb.get_value(c64);
+      smival->value.hNumber.hipart = c64.high();
+      smival->value.hNumber.lopart = c64.low();
+    }
+    break;
+
+  case sNMP_SYNTAX_BITS:
+  case sNMP_SYNTAX_OCTETS:
+  case sNMP_SYNTAX_OPAQUE:
+  case sNMP_SYNTAX_IPADDR:
+    {
+      OctetStr os;
+      tempvb.get_value(os);
+      smival->value.string.ptr = NULL;
+      smival->value.string.len = os.len();
+      if ( smival->value.string.len > 0 )
+      {
+        smival->value.string.ptr
+          = (SmiLPBYTE) new  unsigned char [smival->value.string.len];
+        if ( smival->value.string.ptr )
+        {
+          for (int i=0; i<(int) smival->value.string.len ; i++)
+            smival->value.string.ptr[i] = os[i];
+        }
+        else
+        {
+          smival->syntax = sNMP_SYNTAX_NULL;  // invalidate the smival
+          return SNMP_CLASS_RESOURCE_UNAVAIL;
+        }
+      }
+    }
+    break;
+
+  case sNMP_SYNTAX_OID:
+    {
+      Oid oid;
+      tempvb.get_value(oid);
+      smival->value.oid.ptr = NULL;
+      smival->value.oid.len = oid.len();
+      if ( smival->value.oid.len > 0 )
+      {
+        smival->value.oid.ptr
+          = (SmiLPUINT32) new unsigned long [ smival->value.oid.len];
+        if ( smival->value.oid.ptr )
+        {
+          for (int i=0; i<(int)smival->value.oid.len ; i++)
+            smival->value.oid.ptr[i] = oid[i];
+        }
+        else
+        {
+          smival->syntax = sNMP_SYNTAX_NULL;  // invalidate the smival
+          return SNMP_CLASS_RESOURCE_UNAVAIL;
+        }
+      }
+    }
+    break;
+
+  default:
+    return SNMP_CLASS_INTERNAL_ERROR;
+  }
+  return SNMP_CLASS_SUCCESS;
+}
+
+// free a SMI value
+void freeSmivalDescriptor( SmiVALUE *smival )
+{
+  switch ( smival->syntax ) {
+  case sNMP_SYNTAX_OCTETS:
+  case sNMP_SYNTAX_OPAQUE:
+  case sNMP_SYNTAX_IPADDR:
+  case sNMP_SYNTAX_BITS:                   // obsoleted in SNMPv2 Draft Std
+    delete [] smival->value.string.ptr;
+    break;
+
+  case sNMP_SYNTAX_OID:
+    delete [] smival->value.oid.ptr;
+    break;
+  }
+  smival->syntax = sNMP_SYNTAX_NULL;
+}
+
+#ifdef _SNMPv3
+
+int SnmpMessage::unloadv3( Pdu &pdu,                // Pdu returned
+                           snmp_version &version,   // version
+                           OctetStr &engine_id,     // optional v3
+                           OctetStr &security_name, // optional v3
+                           long int &security_model,
+                           UdpAddress &from_addr,
+                          Snmp &snmp_session)
+{
+  OctetStr tmp;
+  return unload(pdu, tmp, version, &engine_id,
+                &security_name, &security_model, &from_addr, &snmp_session);
+}
+
+#endif
+
+int SnmpMessage::load(const Pdu &cpdu,
+                      const OctetStr &community,
+                      const snmp_version version,
+                      const OctetStr* engine_id,
+                      const OctetStr* security_name,
+                      const int security_model)
+{
+  int status;
+  const Pdu *pdu = &cpdu;
+  Pdu temppdu;
+
+  // make sure pdu is valid
+  if ( !pdu->valid())
+    return SNMP_CLASS_INVALID_PDU;
+
+  // create a raw pdu
+  snmp_pdu *raw_pdu;
+  raw_pdu = snmp_pdu_create( (int) pdu->get_type());
+
+  Oid enterprise;
+
+  // load it up
+  raw_pdu->reqid = pdu->get_request_id();
+#ifdef _SNMPv3
+  raw_pdu->msgid = pdu->get_message_id();
+#endif
+  raw_pdu->errstat= (unsigned long) pdu->get_error_status();
+  raw_pdu->errindex= (unsigned long) pdu->get_error_index();
+
+  // if its a V1 trap then load up other values
+  // for v2, use normal pdu format
+  if (raw_pdu->command == sNMP_PDU_V1TRAP)
+  {
+    // DON'T forget about the v1 trap agent address (changed by Frank Fock)
+    GenAddress gen_addr;
+    IpAddress ip_addr;
+    int addr_set = FALSE;
+
+    if (pdu->get_v1_trap_address(gen_addr))
+    {
+      /* User did set the v1 trap address */
+      if ((gen_addr.get_type() != Address::type_ip) &&
+          (gen_addr.get_type() != Address::type_udp) )
+      {
+       LOG_BEGIN(ERROR_LOG | 4);
+       LOG("SNMPMessage: Bad v1 trap address type in pdu");
+       LOG(gen_addr.get_type());
+       LOG_END;
+
+        snmp_free_pdu( raw_pdu);
+        return SNMP_CLASS_INVALID_PDU;
+      }
+
+      ip_addr = gen_addr;
+      if (!ip_addr.valid())
+      {
+       LOG_BEGIN(ERROR_LOG | 1);
+       LOG("SNMPMessage: Copied v1 trap address not valid");
+       LOG_END;
+
+        snmp_free_pdu( raw_pdu);
+        return SNMP_CLASS_RESOURCE_UNAVAIL;
+      }
+      addr_set = TRUE;
+    }
+    else
+    {
+      /* User did not set the v1 trap address */
+      char addrString[256];
+      if (gethostname(addrString, 255) == 0)
+      {
+          ip_addr = addrString;
+          addr_set = TRUE;
+      }
+    }
+    struct sockaddr_in agent_addr;  // agent address socket struct
+    // prepare the agent address
+    memset(&agent_addr, 0, sizeof(agent_addr));
+    agent_addr.sin_family = AF_INET;
+    if (addr_set)
+    {
+      agent_addr.sin_addr.s_addr
+        = inet_addr(((IpAddress &)ip_addr).IpAddress::get_printable());
+      LOG_BEGIN(INFO_LOG | 7);
+      LOG("SNMPMessage: Setting v1 trap address");
+      LOG(((IpAddress &)ip_addr).IpAddress::get_printable());
+      LOG_END;
+    }
+    raw_pdu->agent_addr = agent_addr;
+
+    //-----[ compute generic trap value ]-------------------------------
+    // determine the generic value
+    // 0 - cold start
+    // 1 - warm start
+    // 2 - link down
+    // 3 - link up
+    // 4 - authentication failure
+    // 5 - egpneighborloss
+    // 6 - enterprise specific
+    Oid trapid;
+    pdu->get_notify_id( trapid);
+    if ( !trapid.valid() || trapid.len() < 2 )
+      {
+        snmp_free_pdu( raw_pdu);
+        return SNMP_CLASS_INVALID_NOTIFYID;
+      }
+    raw_pdu->specific_type=0;
+    if ( trapid == coldStart)
+      raw_pdu->trap_type = 0;  // cold start
+    else if ( trapid == warmStart)
+      raw_pdu->trap_type = 1;  // warm start
+    else if( trapid == linkDown)
+      raw_pdu->trap_type = 2;  // link down
+    else if ( trapid == linkUp)
+      raw_pdu->trap_type = 3;  // link up
+    else if ( trapid == authenticationFailure )
+      raw_pdu->trap_type = 4;  // authentication failure
+    else if ( trapid == egpNeighborLoss)
+      raw_pdu->trap_type = 5;  // egp neighbor loss
+    else {
+      raw_pdu->trap_type = 6;     // enterprise specific
+      // last oid subid is the specific value
+      // if 2nd to last subid is "0", remove it
+      // enterprise is always the notify oid prefix
+      raw_pdu->specific_type = (int) trapid[(int) (trapid.len()-1)];
+
+      trapid.trim(1);
+      if ( trapid[(int)(trapid.len()-1)] == 0 )
+        trapid.trim(1);
+      enterprise = trapid;
+    }
+
+    if ( raw_pdu->trap_type !=6)
+      pdu->get_notify_enterprise( enterprise);
+    if ( enterprise.len() >0) {
+      // note!!
+      // these are hooks into an SNMP++ oid
+      // and therefor the raw_pdu enterprise
+      // should not free them. null them out!!
+      SmiLPOID rawOid;
+      rawOid = enterprise.oidval();
+      raw_pdu->enterprise = rawOid->ptr;
+      raw_pdu->enterprise_length = (int) rawOid->len;
+    }
+
+    // timestamp
+    TimeTicks timestamp;
+    pdu->get_notify_timestamp( timestamp);
+    raw_pdu->time = ( unsigned long) timestamp;
+
+  }
+
+  // if its a v2 trap then we need to make a few adjustments
+  // vb #1 is the timestamp
+  // vb #2 is the id, represented as an Oid
+  if (( raw_pdu->command == sNMP_PDU_TRAP) ||
+      ( raw_pdu->command == sNMP_PDU_INFORM))
+  {
+    Vb tempvb;
+
+    temppdu = *pdu;
+    temppdu.trim(temppdu.get_vb_count());
+
+    // vb #1 is the timestamp
+    TimeTicks timestamp;
+    tempvb.set_oid(SNMP_MSG_OID_SYSUPTIME);   // sysuptime
+    pdu->get_notify_timestamp( timestamp);
+    tempvb.set_value ( timestamp);
+    temppdu += tempvb;
+
+    // vb #2 is the id
+    Oid trapid;
+    tempvb.set_oid(SNMP_MSG_OID_TRAPID);
+    pdu->get_notify_id( trapid);
+    tempvb.set_value( trapid);
+    temppdu += tempvb;
+
+    // append the remaining vbs
+    for (int z=0; z<pdu->get_vb_count(); z++) {
+      pdu->get_vb( tempvb,z);
+      temppdu += tempvb;
+    }
+
+    pdu = &temppdu;          // reassign the pdu to the temp one
+  }
+  // load up the payload
+  // for all Vbs in list, add them to the pdu
+  int vb_count;
+  Vb tempvb;
+  Oid tempoid;
+  SmiLPOID smioid;
+  SmiVALUE smival;
+
+  vb_count = pdu->get_vb_count();
+  for (int z=0;z<vb_count;z++) {
+    pdu->get_vb( tempvb,z);
+    tempvb.get_oid( tempoid);
+    smioid = tempoid.oidval();
+    // clear the value portion, in case its
+    // not already been done so by the app writer
+    // only do it in the case its a get,next or bulk
+    if ((raw_pdu->command == sNMP_PDU_GET) ||
+        (raw_pdu->command == sNMP_PDU_GETNEXT) ||
+        (raw_pdu->command == sNMP_PDU_GETBULK))
+      tempvb.set_null();
+    status = convertVbToSmival( tempvb, &smival );
+    if ( status != SNMP_CLASS_SUCCESS) {
+      snmp_free_pdu( raw_pdu);
+      return status;
+    }
+    // add the vb to the raw pdu
+    snmp_add_var( raw_pdu, smioid->ptr, (int) smioid->len, &smival);
+
+    freeSmivalDescriptor( &smival);
+  }
+
+  // ASN1 encode the pdu
+#ifdef _SNMPv3
+  if (version == version3)
+  {
+    if ((!engine_id) || (!security_name))
+    {
+      LOG_BEGIN(ERROR_LOG | 4);
+      LOG("SNMPMessage: Need security name and engine id for v3 message");
+      LOG_END;
+
+      // prevention of SNMP++ Enterprise Oid death
+      if ( enterprise.len() >0) {
+       raw_pdu->enterprise = 0;
+       raw_pdu->enterprise_length=0;
+      }
+      snmp_free_pdu( raw_pdu);
+      return SNMP_CLASS_INVALID_TARGET;
+    }
+
+    status = v3MP::I->snmp_build(raw_pdu, databuff, (int *)&bufflen,
+                                *engine_id, *security_name, security_model,
+                                pdu->get_security_level(),
+                                pdu->get_context_engine_id(),
+                                pdu->get_context_name());
+    if (status == SNMPv3_MP_OK) {
+      if ((pdu->get_type() == sNMP_PDU_RESPONSE) &&
+          ((int)pdu->get_maxsize_scopedpdu() < pdu->get_asn1_length())) {
+
+       LOG_BEGIN(ERROR_LOG | 1);
+       LOG("SNMPMessage: *BUG*: Serialized response pdu is too big (len) (max)");
+       LOG(pdu->get_asn1_length());
+       LOG(pdu->get_maxsize_scopedpdu());
+       LOG_END;
+
+        // prevention of SNMP++ Enterprise Oid death
+        if ( enterprise.len() >0) {
+          raw_pdu->enterprise = 0;
+          raw_pdu->enterprise_length=0;
+        }
+        snmp_free_pdu( raw_pdu);
+        return SNMP_ERROR_TOO_BIG;
+      }
+    }
+  }
+  else
+#endif
+    status = snmp_build( raw_pdu, databuff, (int *) &bufflen, version,
+                         community.data(), (int) community.len());
+
+  LOG_BEGIN(DEBUG_LOG | 4);
+  LOG("SNMPMessage: return value for build message");
+  LOG(status);
+  LOG_END;
+
+  if ((status != 0)
+#ifdef _SNMPv3
+      && ((version != version3) || (status != SNMPv3_MP_OK))
+#endif
+      ) {
+    valid_flag = false;
+    // prevention of SNMP++ Enterprise Oid death
+    if ( enterprise.len() >0) {
+      raw_pdu->enterprise = 0;
+      raw_pdu->enterprise_length=0;
+    }
+    snmp_free_pdu( raw_pdu);
+#ifdef _SNMPv3
+    if (version == version3)
+      return status;
+    else
+#endif
+      // NOTE: This is an assumption - in most cases during normal
+      // operation the reason is a tooBig - another could be a
+      // damaged variable binding.
+      return SNMP_ERROR_TOO_BIG;
+  }
+  valid_flag = true;
+
+  // prevention of SNMP++ Enterprise Oid death
+  if ( enterprise.len() >0) {
+    raw_pdu->enterprise = 0;
+    raw_pdu->enterprise_length=0;
+  }
+
+  snmp_free_pdu( raw_pdu);
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+// load up a SnmpMessage
+int SnmpMessage::load( unsigned char *data,
+                       unsigned long len)
+{
+  bufflen = MAX_SNMP_PACKET;
+  valid_flag = false;
+
+  if (len <= MAX_SNMP_PACKET)
+  {
+    memcpy( (unsigned char *) databuff, (unsigned char *) data,
+            (unsigned int) len);
+    bufflen = len;
+    valid_flag = true;
+  }
+  else
+    return SNMP_ERROR_WRONG_LENGTH;
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+// unload the data into SNMP++ objects
+int SnmpMessage::unload(Pdu &pdu,                 // Pdu object
+                       OctetStr &community,      // community object
+                       snmp_version &version,    // SNMP version #
+                        OctetStr *engine_id,      // optional v3
+                        OctetStr *security_name,  // optional v3
+                        long int *security_model,
+                        UdpAddress *from_addr,
+                        Snmp *snmp_session)
+{
+  pdu.clear();
+
+  if (!valid_flag)
+    return SNMP_CLASS_INVALID;
+
+  snmp_pdu *raw_pdu;
+  raw_pdu = snmp_pdu_create(0); // do a "snmp_free_pdu( raw_pdu)" before return
+
+  int status;
+
+#ifdef _SNMPv3
+  OctetStr context_engine_id;
+  OctetStr context_name;
+  long int security_level = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+
+  if ((security_model) && (security_name) && (engine_id) && (snmp_session)) {
+    status = v3MP::I->snmp_parse(snmp_session, raw_pdu,
+                         databuff, (int)bufflen, *engine_id,
+                         *security_name, context_engine_id, context_name,
+                         security_level, *security_model, version, *from_addr);
+    if (status != SNMPv3_MP_OK) {
+      pdu.set_request_id( raw_pdu->reqid);
+      pdu.set_type( raw_pdu->command);
+      snmp_free_pdu( raw_pdu);
+      return status;
+    }
+    pdu.set_context_engine_id(context_engine_id);
+    pdu.set_context_name(context_name);
+    pdu.set_security_level(security_level);
+    pdu.set_message_id(raw_pdu->msgid);
+    pdu.set_maxsize_scopedpdu(raw_pdu->maxsize_scopedpdu);
+  }
+  else {
+#endif
+    unsigned char community_name[MAX_LEN_COMMUNITY + 1];
+    int           community_len = MAX_LEN_COMMUNITY + 1;
+
+    status = snmp_parse(raw_pdu, databuff, (int) bufflen,
+                        community_name, community_len, version);
+    if (status != SNMP_CLASS_SUCCESS) {
+      snmp_free_pdu(raw_pdu);
+      return status;
+    }
+    community.set_data( community_name, community_len);
+
+#ifdef _SNMPv3
+  }
+#endif
+  // load up the SNMP++ variables
+  pdu.set_request_id(raw_pdu->reqid);
+  pdu.set_error_status((int) raw_pdu->errstat);
+  pdu.set_error_index((int) raw_pdu->errindex);
+  pdu.set_type( raw_pdu->command);
+
+  // deal with traps a little different
+  if ( raw_pdu->command == sNMP_PDU_V1TRAP) {
+    // timestamp
+    TimeTicks timestamp;
+    timestamp = raw_pdu->time;
+    pdu.set_notify_timestamp( timestamp);
+
+    // set the agent address
+    IpAddress agent_addr(inet_ntoa(raw_pdu->agent_addr.sin_addr));
+    if (agent_addr != "0.0.0.0")
+    {
+      pdu.set_v1_trap_address(agent_addr);
+
+      LOG_BEGIN(DEBUG_LOG | 4);
+      LOG("SNMPMessage: Trap address of received v1 trap");
+      LOG(agent_addr.get_printable());
+      LOG_END;
+    }
+
+    // set enterprise, notifyid
+    Oid enterprise;
+
+    if (raw_pdu->enterprise_length >0) {
+      for (int i=0; i< raw_pdu->enterprise_length; i++) {
+        enterprise += (int) (raw_pdu->enterprise[i]);
+      }
+      pdu.set_notify_enterprise(enterprise);
+    }
+    switch (raw_pdu->trap_type) {
+    case 0:
+      pdu.set_notify_id(coldStart);
+      break;
+
+    case 1:
+      pdu.set_notify_id(warmStart);
+      break;
+
+    case 2:
+      pdu.set_notify_id(linkDown);
+      break;
+
+    case 3:
+      pdu.set_notify_id(linkUp);
+      break;
+
+    case 4:
+      pdu.set_notify_id(authenticationFailure);
+      break;
+
+    case 5:
+      pdu.set_notify_id(egpNeighborLoss);
+      break;
+
+    case 6: { // enterprise specific
+      // base id + specific #
+      Oid eOid = enterprise;
+      eOid += 0ul;
+      eOid += raw_pdu->specific_type;
+      pdu.set_notify_id( eOid);
+      break;
+      }
+    default:
+      {
+       LOG_BEGIN(WARNING_LOG | 3);
+       LOG("SNMPMessage: Received trap with illegal trap type");
+       LOG(raw_pdu->trap_type);
+       LOG_END;
+      }
+    }
+  }
+
+  // vbs
+  Vb tempvb;
+  Oid tempoid;
+  struct   variable_list *vp;
+  int vb_nr = 1;
+
+  for(vp = raw_pdu->variables; vp; vp = vp->next_variable, vb_nr++) {
+
+    // extract the oid portion
+    tempoid.set_data( (unsigned long *)vp->name,
+                      ( unsigned int) vp->name_length);
+    tempvb.set_oid( tempoid);
+
+    // extract the value portion
+    switch(vp->type){
+
+      // octet string
+    case sNMP_SYNTAX_OCTETS:
+      {
+       OctetStr octets( (unsigned char *) vp->val.string,
+                        (unsigned long) vp->val_len);
+       tempvb.set_value( octets);
+      }
+      break;
+    case sNMP_SYNTAX_OPAQUE:
+      {
+       OpaqueStr octets( (unsigned char *) vp->val.string,
+                         (unsigned long) vp->val_len);
+       tempvb.set_value( octets);
+      }
+      break;
+
+      // object id
+    case sNMP_SYNTAX_OID:
+      {
+       Oid oid( (unsigned long*) vp->val.objid,
+                (int) vp->val_len);
+       tempvb.set_value( oid);
+        if ((vb_nr == 2) &&
+            ((raw_pdu->command == sNMP_PDU_TRAP) ||
+             (raw_pdu->command == sNMP_PDU_INFORM)) &&
+            (tempoid == SNMP_MSG_OID_TRAPID))
+        {
+          // set notify_id
+          pdu.set_notify_id(oid);
+         continue; // don't add vb to pdu
+        }
+      }
+      break;
+
+      // timeticks
+    case sNMP_SYNTAX_TIMETICKS:
+      {
+       TimeTicks timeticks( (unsigned long) *(vp->val.integer));
+       tempvb.set_value( timeticks);
+        if ((vb_nr == 1) &&
+            ((raw_pdu->command == sNMP_PDU_TRAP) ||
+             (raw_pdu->command == sNMP_PDU_INFORM)) &&
+            (tempoid == SNMP_MSG_OID_SYSUPTIME))
+        {
+          // set notify_timestamp
+          pdu.set_notify_timestamp( timeticks);
+         continue; // don't add vb to pdu
+        }
+      }
+      break;
+
+      // 32 bit counter
+    case sNMP_SYNTAX_CNTR32:
+      {
+       Counter32 counter32( (unsigned long) *(vp->val.integer));
+       tempvb.set_value( counter32);
+      }
+      break;
+
+      // 32 bit gauge
+    case sNMP_SYNTAX_GAUGE32:
+      {
+       Gauge32 gauge32( (unsigned long) *(vp->val.integer));
+       tempvb.set_value( gauge32);
+      }
+      break;
+
+      // ip address
+    case sNMP_SYNTAX_IPADDR:
+      {
+       char buffer[42];
+
+       if (vp->val_len == 16)
+         sprintf( buffer, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
+                  "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
+                  vp->val.string[ 0], vp->val.string[ 1], vp->val.string[ 2],
+                  vp->val.string[ 3], vp->val.string[ 4], vp->val.string[ 5],
+                  vp->val.string[ 6], vp->val.string[ 7], vp->val.string[ 8],
+                  vp->val.string[ 9], vp->val.string[10], vp->val.string[11],
+                  vp->val.string[12], vp->val.string[13], vp->val.string[14],
+                  vp->val.string[15]);
+       else
+         sprintf( buffer,"%d.%d.%d.%d",
+                  vp->val.string[0], vp->val.string[1],
+                  vp->val.string[2], vp->val.string[3]);
+       IpAddress ipaddress( buffer);
+       tempvb.set_value( ipaddress);
+      }
+      break;
+
+      // 32 bit integer
+    case sNMP_SYNTAX_INT:
+      {
+       SnmpInt32 int32( (long) *(vp->val.integer));
+       tempvb.set_value( int32);
+      }
+      break;
+
+      // 32 bit unsigned integer
+/* Not distinguishable from Gauge32
+    case sNMP_SYNTAX_UINT32:
+      {
+       SnmpUInt32 uint32( (unsigned long) *(vp->val.integer));
+       tempvb.set_value( uint32);
+      }
+      break;
+*/
+      // v2 counter 64's
+    case sNMP_SYNTAX_CNTR64:
+      { // Frank Fock (was empty before)
+       Counter64 c64(((counter64*)vp->val.counter64)->high,
+                     ((counter64*)vp->val.counter64)->low);
+       tempvb.set_value( c64);
+       break;
+      }
+    case sNMP_SYNTAX_NULL:
+           tempvb.set_null();
+           break;
+       
+           // v2 vb exceptions
+    case sNMP_SYNTAX_NOSUCHOBJECT:
+    case sNMP_SYNTAX_NOSUCHINSTANCE:
+    case sNMP_SYNTAX_ENDOFMIBVIEW:
+      tempvb.set_exception_status(vp->type);
+      break;
+
+    default:
+      tempvb.set_null();
+
+    } // end switch
+
+    // append the vb to the pdu
+    pdu += tempvb;
+  }
+
+  snmp_free_pdu( raw_pdu);
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/target.cpp b/3rdparty/snmp++/src/target.cpp
new file mode 100644 (file)
index 0000000..765935a
--- /dev/null
@@ -0,0 +1,408 @@
+/*_############################################################################
+  _## 
+  _##  target.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+  T A R G E T . C P P
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:      Target class defines target SNMP agents.
+
+=====================================================================*/
+char target_cpp_version[]="#(@) SNMP++ $Id: target.cpp 1686 2009-11-24 13:47:44Z katz $";
+#include "snmp_pp/target.h"
+#include "snmp_pp/v3.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define PUBLIC "public"
+
+// class variables for default behavior control
+unsigned long SnmpTarget::default_timeout = 100;
+int SnmpTarget::default_retries = 1;
+
+//----------------------------------------------------------------------
+//--------[ Abstract SnmpTarget Member Functions ]----------------------
+//----------------------------------------------------------------------
+
+// get the address
+int SnmpTarget::get_address(GenAddress &address) const
+{
+  if (validity == false) return FALSE;
+
+  address = my_address;
+  return TRUE;
+}
+
+// set the address
+int SnmpTarget::set_address(const Address &address)
+{
+   my_address = address;
+   if ( my_address.valid())
+      validity = true;
+   else
+      validity = false;
+
+   return validity;
+}
+
+SnmpTarget* SnmpTarget::clone() const
+{
+  GenAddress addr = my_address;
+  SnmpTarget* res = new SnmpTarget;
+  res->set_timeout(timeout);
+  res->set_retry(retries);
+  res->set_address(addr);
+  res->set_version(version);
+  return res;
+}
+
+//=============[ int operator == SnmpTarget, SnmpTarget ]======================
+// equivlence operator overloaded
+int SnmpTarget::operator==( const SnmpTarget &rhs) const
+{
+  if (my_address != rhs.my_address) return 0;
+  if (version    != rhs.version)    return 0;
+  if (timeout    != rhs.timeout)    return 0;
+  if (retries    != rhs.retries)    return 0;
+  return 1;  // they are equal
+}
+
+// reset the object
+void SnmpTarget::clear()
+{
+  validity = false;
+  timeout  = default_timeout;
+  retries  = default_retries;
+  version  = version1;
+  ttype    = type_base;
+  my_address.clear();
+}
+
+//----------------------------------------------------------------------
+//--------[ CTarget Member Functions ]----------------------------------
+//----------------------------------------------------------------------
+
+//---------[ CTarget::CTarget( void) ]----------------------------------
+// CTarget constructor no args
+CTarget::CTarget( void)
+  : read_community(PUBLIC), write_community(PUBLIC)
+{
+  ttype = type_ctarget; // overwrite value set in SnmpTarget()
+}
+
+//-----------[ CTarget:: CTarget ]-------------------------------------
+// CTarget constructor with args
+CTarget::CTarget(const Address &address,
+                 const char *read_community_name,
+                 const char *write_community_name)
+  : SnmpTarget(address),
+    read_community(read_community_name), write_community(write_community_name)
+{
+  ttype = type_ctarget; // overwrite value set in SnmpTarget()
+}
+
+//-----------[ CTarget:: CTarget ]-----------------------------------
+// CTarget constructor with args
+CTarget::CTarget(const Address &address,
+                const OctetStr& read_community_name,
+                const OctetStr& write_community_name)
+  : SnmpTarget(address),
+    read_community(read_community_name), write_community(write_community_name)
+{
+  ttype = type_ctarget; // overwrite value set in SnmpTarget()
+}
+
+
+//-----------[ CTarget:: CTarget( Address &address) ]--------------
+// CTarget constructor with args
+CTarget::CTarget(const Address &address)
+  : SnmpTarget(address), read_community(PUBLIC), write_community(PUBLIC)
+{
+  ttype = type_ctarget; // overwrite value set in SnmpTarget()
+}
+
+//-----------[ CTarget:: CTarget( const CTarget &target) ]-------
+// CTarget constructor with args
+CTarget::CTarget( const CTarget &target)
+{
+   read_community  = target.read_community;
+   write_community = target.write_community;
+   my_address      = target.my_address;
+   timeout         = target.timeout;
+   retries         = target.retries;
+   version         = target.version;
+   validity        = target.validity;
+   ttype           = type_ctarget;
+}
+
+//----------[ CTarget::resolve_to_V1 ]---------------------------------
+// resolve entity
+// common interface for Community based targets
+int CTarget::resolve_to_C ( OctetStr &read_comm,
+                            OctetStr &write_comm,
+                            GenAddress &address,
+                            unsigned long &t,
+                            int &r,
+                            unsigned char &v) const
+{
+   // if the target is invalid then return false
+   if ( !validity)
+     return FALSE;
+
+   read_comm = read_community;
+   write_comm = write_community;
+   address = my_address;
+
+   t = timeout;
+   r = retries;
+   v = version;
+
+   return TRUE;
+}
+
+// overloaded assignment
+CTarget& CTarget::operator=( const CTarget& target)
+{
+  if (this == &target) return *this;  // check for self assignment
+
+  timeout         = target.timeout;
+  retries         = target.retries;
+  read_community  = target.read_community;
+  write_community = target.write_community;
+  validity        = target.validity;
+  my_address      = target.my_address;
+  version         = target.version;
+  return *this;
+}
+
+//=============[ int operator == CTarget, CTarget ]==========================
+// equivlence operator overloaded
+int CTarget::operator==( const CTarget &rhs) const
+{
+  if (SnmpTarget::operator==(rhs) == 0)       return 0;
+  // need to compare all the members of a CTarget
+  if (read_community  != rhs.read_community)  return 0;
+  if (write_community != rhs.write_community) return 0;
+  return 1; // equal
+}
+
+// reset the object
+void CTarget::clear()
+{
+  SnmpTarget::clear();
+  read_community.clear();
+  write_community.clear();
+  ttype = type_ctarget; // overwrite value set in SnmpTarget::clear()
+}
+
+//----------------------------------------------------------------------
+//--------[ UTarget Member Functions ]----------------------------------
+//----------------------------------------------------------------------
+
+//---------[ UTarget::UTarget( void) ]----------------------------------
+// UTarget constructor no args
+UTarget::UTarget()
+  : security_name(INITIAL_USER),
+#ifdef _SNMPv3
+  security_model(SNMP_SECURITY_MODEL_USM), engine_id("")
+#else
+  security_model(SNMP_SECURITY_MODEL_V1)
+#endif
+{
+#ifdef _SNMPv3
+  version = version3;
+#endif
+  ttype = type_utarget;
+}
+
+//-----------[ UTarget:: UTarget ]-------------------------------------
+// UTarget constructor with args
+UTarget::UTarget( const Address &address,
+                  const char *sec_name,
+                  const int sec_model)
+  : SnmpTarget(address), security_name(sec_name), security_model(sec_model)
+#ifdef _SNMPv3
+    ,engine_id("")
+#endif
+{
+#ifdef _SNMPv3
+  version = version3;
+#endif
+  ttype = type_utarget;
+}
+
+//-----------[ UTarget:: UTarget ]-----------------------------------
+// UTarget constructor with args
+UTarget::UTarget( const Address &address,
+                  const OctetStr &sec_name,
+                  const int sec_model)
+  : SnmpTarget(address), security_name(sec_name), security_model(sec_model)
+#ifdef _SNMPv3
+    ,engine_id("")
+#endif
+{
+#ifdef _SNMPv3
+  version = version3;
+#endif
+  ttype = type_utarget;
+}
+
+//-----------[ UTarget:: UTarget( Address &address) ]--------------
+// UTarget constructor with args
+UTarget::UTarget( const Address &address)
+  : SnmpTarget(address), security_name(INITIAL_USER),
+#ifdef _SNMPv3
+    security_model(SNMP_SECURITY_MODEL_USM), engine_id("")
+#else
+    security_model(SNMP_SECURITY_MODEL_V1)
+#endif
+{
+#ifdef _SNMPv3
+  version = version3;
+#endif
+  ttype = type_utarget;
+}
+
+//-----------[ UTarget:: UTarget( const UTarget &target) ]-------
+// UTarget constructor with args
+UTarget::UTarget( const UTarget &target)
+{
+#ifdef _SNMPv3
+  engine_id = target.engine_id;
+#endif
+  security_name = target.security_name;
+  security_model = target.security_model;
+  my_address = target.my_address;
+  timeout = target.timeout;
+  retries = target.retries;
+  version = target.version;
+  validity = target.validity;
+  ttype = type_utarget;
+}
+
+
+// set the address
+int UTarget::set_address(const Address &address)
+{
+#ifdef _SNMPv3
+   engine_id = ""; // delete engine_id
+#endif
+   return SnmpTarget::set_address(address);
+}
+
+int UTarget::resolve_to_U( OctetStr&  sec_name,
+                           int &sec_model,
+                           GenAddress &address,
+                           unsigned long &t,
+                           int &r,
+                           unsigned char &v) const
+{
+  // if the target is invalid then return false
+  if ( !validity)
+    return FALSE;
+
+  sec_name = security_name;
+  sec_model = security_model;
+  address = my_address;
+
+  t = timeout;
+  r = retries;
+  v = version;
+
+  return TRUE;
+}
+
+// overloaded assignment
+UTarget& UTarget::operator=(const UTarget& target)
+{
+  if (this == &target) return *this;  // check for self assignment
+
+  timeout = target.timeout;
+  retries = target.retries;
+
+#ifdef _SNMPv3
+  engine_id = target.engine_id;
+#endif
+  security_name = target.security_name;
+  security_model = target.security_model;
+  version = target.version;
+
+  validity = target.validity;
+  my_address = target.my_address;
+
+  return *this;
+}
+
+//=============[ int operator == UTarget, UTarget ]==========================
+// equivlence operator overloaded
+int UTarget::operator==(const UTarget &rhs) const
+{
+  if (SnmpTarget::operator==(rhs) == 0)     return 0;
+  // need to compare all the members of a UTarget
+  // but don`t compare engine_id
+  if (security_name  != rhs.security_name)  return 0;
+  if (security_model != rhs.security_model) return 0;
+  return 1;  // they are equal
+}
+
+// reset the object
+void UTarget::clear()
+{
+  SnmpTarget::clear();
+  security_name = INITIAL_USER;
+#ifdef _SNMPv3
+  security_model = SNMP_SECURITY_MODEL_USM;
+  engine_id.clear();
+  version = version3;
+#else
+  security_model = SNMP_SECURITY_MODEL_V1;
+#endif
+  ttype = type_utarget;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/timetick.cpp b/3rdparty/snmp++/src/timetick.cpp
new file mode 100644 (file)
index 0000000..13a93d7
--- /dev/null
@@ -0,0 +1,134 @@
+/*_############################################################################
+  _## 
+  _##  timetick.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+  T I M E T I C K. C P P
+
+  TIMETICK CLASS IMPLEMENTATION
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+
+  DESCRIPTION:
+  Class implentation for SMI Timeticks class.
+=====================================================================*/
+char timetick_cpp_version[]="#(@) SNMP++ $Id: timetick.cpp 1542 2009-05-29 11:38:48Z katz $";
+
+#include "snmp_pp/timetick.h"         // include header file for timetick class
+#include <stdio.h>            // for sprintf() usage.
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// Copy constructor
+TimeTicks::TimeTicks(const TimeTicks &t)
+{
+  smival.value.uNumber = t.smival.value.uNumber;
+  smival.syntax = sNMP_SYNTAX_TIMETICKS;
+}
+
+// general assignment from any Value
+SnmpSyntax& TimeTicks::operator=(const SnmpSyntax &in_val)
+{
+  if (this == &in_val) return *this; // handle assignement from itself
+
+  valid_flag = false;           // will get set true if really valid
+  if (in_val.valid())
+  {
+    switch (in_val.get_syntax())
+    {
+      case sNMP_SYNTAX_UINT32:
+   // case sNMP_SYNTAX_GAUGE32:        .. indistinquishable from UINT32
+      case sNMP_SYNTAX_CNTR32:
+      case sNMP_SYNTAX_TIMETICKS:
+      case sNMP_SYNTAX_INT32:          // implied cast int -> uint
+         smival.value.uNumber =
+               ((TimeTicks &)in_val).smival.value.uNumber;
+         valid_flag = true;
+         break;
+    }
+  }
+  m_changed = true;
+  return *this;
+}
+
+// ASCII format return
+const char *TimeTicks::get_printable() const
+{
+  if (m_changed == false) return output_buffer;
+
+  unsigned long hseconds, seconds, minutes, hours, days;
+  unsigned long tt = smival.value.uNumber;
+  TimeTicks *nc_this = PP_CONST_CAST(TimeTicks*, this);
+
+  days = tt / 8640000;
+  tt %= 8640000;
+
+  hours = tt / 360000;
+  tt %= 360000;
+
+  minutes = tt / 6000;
+  tt %= 6000;
+
+  seconds = tt / 100;
+  tt %= 100;
+
+  hseconds = tt;
+
+  if (days == 0)
+    sprintf(nc_this->output_buffer, "%lu:%02lu:%02lu.%02lu",
+            hours, minutes, seconds, hseconds);
+  else if (days == 1)
+    sprintf(nc_this->output_buffer, "1 day %lu:%02lu:%02lu.%02lu",
+           hours, minutes, seconds, hseconds);
+  else
+    sprintf(nc_this->output_buffer, "%lu days, %lu:%02lu:%02lu.%02lu",
+           days, hours, minutes, seconds, hseconds);
+
+  nc_this->m_changed = false;
+  return output_buffer;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/usm_v3.cpp b/3rdparty/snmp++/src/usm_v3.cpp
new file mode 100644 (file)
index 0000000..ffe7c99
--- /dev/null
@@ -0,0 +1,4476 @@
+/*_############################################################################
+  _## 
+  _##  usm_v3.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+char usm_v3_cpp_version[]="@(#) SNMP++ $Id: usm_v3.cpp 1788 2010-07-23 20:02:38Z katz $";
+
+#if defined(_AIX) || defined(__APPLE__)
+#include <unistd.h>
+#endif
+#ifdef __MINGW32__
+#include <io.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "snmp_pp/config_snmp_pp.h"
+
+#ifdef _SNMPv3
+
+#include "snmp_pp/v3.h"
+#include "snmp_pp/usm_v3.h"
+#include "snmp_pp/auth_priv.h"
+#include "snmp_pp/reentrant.h"
+#include "snmp_pp/mp_v3.h"
+#include "snmp_pp/asn1.h"
+#include "snmp_pp/vb.h"
+#include "snmp_pp/pdu.h"
+#include "snmp_pp/log.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+// Use locking on access methods in an multithreading enviroment.
+#ifdef _THREADS
+#define BEGIN_REENTRANT_CODE_BLOCK SnmpSynchronize auto_lock(*this)
+#define BEGIN_REENTRANT_CODE_BLOCK_CONST  \
+          SnmpSynchronize auto_lock(*(PP_CONST_CAST(SnmpSynchronized*, this)))
+#define BEGIN_AUTO_LOCK(obj) SnmpSynchronize auto_lock(*obj)
+#else
+#define BEGIN_REENTRANT_CODE_BLOCK
+#define BEGIN_REENTRANT_CODE_BLOCK_CONST
+#define BEGIN_AUTO_LOCK(obj)
+#endif
+
+#ifndef min
+#define min(a,b) ( (a) < (b) ? (a) : (b) )
+#endif
+
+#define MAX_LINE_LEN 2048  // Max line length in usm user files
+
+// structure for key update
+struct UsmKeyUpdate
+{
+  OctetStr engineID;
+  OctetStr securityName;
+  OctetStr newPassword;
+  OctetStr newKey;
+  int type;
+};
+
+/* ------------------------- UsmTimeTable --------------------------*/
+
+/**
+ * This class provides a table for the time values (engine boots and
+ * engine time) for snmp entities that are identified through their
+ * engine id.
+ *
+ * @author Jochen Katz
+ */
+class USMTimeTable : public SnmpSynchronized
+{
+public:
+
+  /**
+   * Initialize the usmTimeTable.
+   *
+   * The usmTimeTable stores for each known engineID the engineBoots
+   * and the difference to the local system time
+   *
+   * @param owner        - Pointer to the USM object that created this table
+   * @param engine_boots - The new value for the snmpEngineBoots counter
+   * @param result       - OUT: Result of the creation of the table
+   */
+  USMTimeTable(const USM *owner, const unsigned int engine_boots, int &result);
+
+  ~USMTimeTable();
+
+  /**
+   * Add a new entry to the usmTimeTable. The caller is responsible for
+   * not adding an engineID twice.
+   *
+   * @param engine_id    - The engineID of the SNMP entity
+   * @param engine_boots - The engine boot counter
+   * @param engine_time  - The engine time
+   *
+   * @return - SNMPv3_USM_ERROR (no memory) or SNMPv3_USM_OK
+   */
+  int add_entry(const OctetStr &engine_id,
+                const long int engine_boots, const long int engine_time);
+
+  /**
+   * Delete this engine id from the table.
+   *
+   * @param engine_id    - The engineID of the SNMP entity
+   *
+   * @return - SNMPv3_USM_ERROR (no memory) or SNMPv3_USM_OK
+   */
+  int delete_entry(const OctetStr &engine_id);
+
+  /**
+   * Return engineBoots and engineTime for a given engineID
+   *
+   * @param engine_id    - The engineID of the SNMP entity
+   * @param engine_boots - OUT: boot counter (0 if not found)
+   * @param engine_time  - OUT: engine time (0 if not found)
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (entry found, values are filled)
+   *           SNMPv3_USM_UNKNOWN_ENGINEID ( not found)
+   */
+  int get_time(const OctetStr &engine_id,
+               long int &engine_boots, long int &engine_time);
+
+  /**
+   * Return the engineBoots and engineTime of this snmp entity.
+   *
+   * @param engine_boots - OUT: boot counter (0 if not found)
+   * @param engine_time  - OUT: engine time (0 if not found)
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (entry found, values are filled)
+   */
+  int get_local_time(long int &engine_boots, long int &engine_time);
+
+  /**
+   * Return the engineBoots value of this snmp entity.
+   *
+   * @return - engine_boots value if initialized, 0 else
+   */
+  unsigned long get_local_boots()
+    { return (table ? table[0].engine_boots : 0); };
+
+  /**
+   * Return the engineTime value of this snmp entity.
+   *
+   * @return - engine_time value if initialized, 0 else
+   */
+  unsigned long get_local_time();
+
+  /**
+   * Check if the given values for engineBoots and engineTime are
+   * in the time window. If the time values are ok, the entry in
+   * the usmTimeTable is updated with the given time values.
+   *
+   * @param engine_id    - The engineID of the SNMP entity
+   * @param engine_boots - The boot counter
+   * @param engine_time  - The engine time
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_NOT_IN_TIME_WINDOW,
+   *           SNMPv3_USM_OK (time ok),
+   *           SNMPv3_USM_UNKNOWN_ENGINEID
+   */
+  int check_time(const OctetStr &engine_id,
+                 const long int engine_boots, const long int engine_time);
+
+  /**
+   * Check if the given engineID is known: If the USM is in
+   * the discovery mode, all engineIDs are accepted and entries
+   * in the timeTable are created.
+   *
+   * @param engine_id - engine id to check
+   *
+   * @return - SNMPv3_USM_ERROR (not found and no discovery)
+   *           SNMPv3_USM_OK (found or discovery set)
+   */
+  int check_engine_id(const OctetStr &engine_id);
+
+private:
+  struct Entry_T
+  {
+    unsigned char engine_id[MAXLENGTH_ENGINEID];
+    int engine_id_len;
+    long int engine_boots;
+    long int time_diff;
+    long int latest_received_time;
+  };
+
+  struct Entry_T *table; ///< Array of entries
+  const USM *usm;  ///< Pointer to the USM, this table belongs to
+  int max_entries; ///< the maximum number of entries
+  int entries;     ///< the current amount of entries
+};
+
+
+/* ------------------------- UsmUserNameTable ----------------------*/
+
+/**
+ * This class holds USM users with PASSWORDS.
+ *
+ * Whenever the USM has to process a message of a user that is not
+ * found in the USMUserTable, this table is queried for the
+ * properties of the user. If the user is found, a localized entry
+ * for the USMUserTable is created and used for processing the message.
+ */
+class USMUserNameTable : public SnmpSynchronized
+{
+public:
+  USMUserNameTable(int &result);
+  ~USMUserNameTable();
+
+  /**
+   * Add a new user to the usmUserNameTable. If the userName is already
+   * known, the old entry is replaced.
+   *
+   * It is not recommended to add users with userName != securityName.
+   *
+   * @param user_name     - Unique userName
+   * @param security_name - Unique securityName
+   * @param auth_proto    - Possible values are:
+   *                        SNMP_AUTHPROTOCOL_NONE,
+   *                        SNMP_AUTHPROTOCOL_HMACMD5,
+   *                        SNMP_AUTHPROTOCOL_HMACSHA
+   * @param priv_proto    - Possible values are:
+   *                        SNMP_PRIVPROTOCOL_NONE,
+   *                        SNMP_PRIVPROTOCOL_DES,
+   *                        SNMP_PRIVPROTOCOL_IDEA
+   * @param auth_pass     - Secret password for authentication
+   * @param priv_pass     - Secret password for privacy
+   *
+   * @return - SNMPv3_USM_OK or
+   *           SNMP_v3_USM_ERROR (memory error, not initialized)
+   */
+  int add_entry(const OctetStr& user_name,
+               const OctetStr& security_name,
+               const long int  auth_proto,
+               const long int  priv_proto,
+               const OctetStr& auth_pass,
+               const OctetStr& priv_pass);
+
+  /**
+   * Delete all occurences of the user with the given securityName
+   * from the table.
+   *
+   * @param security_name - the securityName of the user
+   *
+   * @return - SNMPv3_USM_OK, SNMPv3_USM_ERROR (not initialized)
+   */
+  int delete_security_name(const OctetStr& security_name);
+
+  /**
+   * Get the entry with the given securityName from the usmUserNameTable
+   *
+   * @note Use lock() and unlock() for thread synchronizytion.
+   *
+   * @param security_name     -
+   *
+   * @return - pointer to the struct or NULL (no need to delete anything)
+   */
+  const struct UsmUserNameTableEntry* get_entry(const OctetStr &security_name);
+
+  /**
+   * Get a clone of the entry with the given securityName from the usmUserNameTable
+   *
+   * @note call delete_cloned_entry() with the retruned pointer.
+   *
+   * @param security_name     -
+   *
+   * @return - pointer to the struct or NULL
+   */
+  struct UsmUserNameTableEntry* get_cloned_entry(const OctetStr &security_name);
+
+  /**
+   * Deletes a entry created through get_cloned_entry().
+   *
+   * @param entry     -
+   */
+  void delete_cloned_entry(struct UsmUserNameTableEntry* &entry);
+
+  /**
+   * Get the securityName from a userName
+   *
+   * @param user_name         -
+   * @param user_name_len     -
+   * @param security_name     - Buffer for the securityName
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+   *           SNMPv3_USM_OK
+   */
+  int get_security_name(const unsigned char *user_name,
+                       const long int user_name_len,
+                       OctetStr &security_name);
+
+  /**
+   * Get the userName from a securityName
+   *
+   * @param user_name         - Buffer for the userName
+   * @param user_name_len     - Has to be set to the max length of the
+   *                            buffer. Is set to the length of the found
+   *                            securityName or to 0 if not found.
+   * @param security_name     -
+   * @param security_name_len -
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+   *           SNMPv3_USM_OK
+   */
+  int get_user_name(unsigned char *user_name, long int *user_name_len,
+                   const unsigned char *security_name,
+                   const long int security_name_len);
+
+  /**
+   * Save all entries into a file.
+   */
+  int save_to_file(const char *name, AuthPriv *ap);
+
+  /**
+   * Load the table from a file.
+   */
+  int load_from_file(const char *name, AuthPriv *ap);
+
+  const UsmUserNameTableEntry *peek_first() const
+    { if (entries > 0) return table; return 0; };
+
+  const UsmUserNameTableEntry *peek_next(const UsmUserNameTableEntry *e) const;
+
+private:
+  struct UsmUserNameTableEntry *table;
+
+  int max_entries; ///< the maximum number of entries
+  int entries;     ///< the current amount of entries
+};
+
+
+/* ---------------------------- UsmUserTable ------------------- */
+
+/**
+ * This class holds USM users with localized KEYS.
+ */
+class USMUserTable : public SnmpSynchronized
+{
+public:
+  USMUserTable(int &result);
+
+  ~USMUserTable();
+
+  /**
+   * Get the number of valid entries in the table.
+   *
+   * @return - number of entries
+   */
+  int size() const { return entries; };
+
+  /**
+   * Get the userName from a securityName
+   *
+   * @param user_name     - Buffer for the userName
+   * @param user_name_len - Has to be set to the max length of the
+   *                        buffer. Is set to the length of the found
+   *                        securityName or to 0 if not found.
+   * @param sec_name      -
+   * @param sec_name_len  -
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+   *           SNMPv3_USM_OK
+   */
+  int get_user_name(unsigned char *user_name, long int *user_name_len,
+                    const unsigned char *sec_name, const long sec_name_len);
+
+  /**
+   * Get the sec_name from a userName
+   *
+   * @param user_name       -
+   * @param user_name_len   -
+   * @param sec_name        - Object for the security name
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized, not found, buffer too small),
+   *           SNMPv3_USM_OK
+   */
+  int get_security_name(const unsigned char *user_name,
+                        const long user_name_len,
+                        OctetStr &sec_name);
+
+  /**
+   * Delete all entries of this user from the usmUserTable
+   *
+   * @param user_name - The userName that should be deleted
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (user deleted or not in table)
+   */
+  int delete_entries(const OctetStr& user_name);
+
+  /**
+   * Delete all entries with this engine id from the table.
+   *
+   * @param engine id - The engine id
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (user deleted or not in table)
+   */
+  int delete_engine_id(const OctetStr& engine_id);
+
+  /**
+   * Delete the entry with the given userName and engineID
+   * from the usmUserTable
+   *
+   * @param engine_id  - The engine id
+   * @param user_name - The userName that should be deleted
+   *
+   * @return - SNMPv3_USM_ERROR (not initialized),
+   *           SNMPv3_USM_OK (user deleted or not in table)
+   */
+  int delete_entry(const OctetStr& engine_id, const OctetStr& user_name);
+
+  /**
+   * Protected (for agent++):
+   *
+   * Get the user at the specified position of the usmUserTable.
+   *
+   * @note Use lock() and unlock() for thread synchronization.
+   *
+   * @param number - get the entry at position number (1...)
+   *
+   * @return - a pointer to the structure or NULL if number is out
+   *           of range (no need to delete anything)
+   */
+  const struct UsmUserTableEntry *get_entry(const int number);
+
+  /**
+   * Get a user of the usmUserTable.
+   *
+   * @note Use lock() and unlock() for thread synchronization.
+   *
+   * @param engine_id - Get a user for this engine id
+   * @param sec_name  - Get the user with this security name
+   *
+   * @return - a pointer to the structure or NULL if the user is not
+   *           found (no need to delete anything)
+   */
+  const struct UsmUserTableEntry *get_entry(const OctetStr &engine_id,
+                                           const OctetStr &sec_name);
+
+  /**
+   * Get a user of the usmUserTable.
+   *
+   * @note call delete_cloned_entry() with the retruned pointer.
+   *
+   * @param engine_id - Get a user for this engine id
+   * @param sec_name  - Get the user with this security name
+   *
+   * @return - a pointer to the structure or NULL if the user is not
+   *           found
+   */
+  struct UsmUserTableEntry *get_cloned_entry(const OctetStr &engine_id,
+                                            const OctetStr &sec_name);
+
+  /**
+   * Deletes a entry created through get_cloned_entry().
+   *
+   * @param entry     -
+   */
+  void delete_cloned_entry(struct UsmUserTableEntry* &entry);
+
+  /**
+   * Get a user of the usmUserTable.
+   *
+   * There could be more than one entry with the given
+   * sec_name. Always the first entry that is found is returned.
+   *
+   * @note Use lock() and unlock() for thread synchronization.
+   *
+   * @param sec_name - security name to search for
+   *
+   * @return - a pointer to the structure or NULL if the user is not
+   *           found (no need to delete anything)
+   */
+  const struct UsmUserTableEntry *get_entry(const OctetStr &sec_name);
+
+  /**
+   * Public:
+   *
+   * Add or replace a user in the usmUserTable. The usmUserTable stores
+   * users with their localized keys.
+   *
+   * @param engine_id     - The engine_id, the key was localized with
+   * @param user_name     - The name of the user (in the USM)
+   * @param sec_name      - The security name of the user, this name
+   *                                is the same for all securityModels
+   * @param auth_proto    - Possible values are:
+   *                                SNMP_AUTHPROTOCOL_NONE,
+   *                                SNMP_AUTHPROTOCOL_HMACMD5,
+   *                                SNMP_AUTHPROTOCOL_HMACSHA
+   * @param auth_key      - The key used for authentications
+   * @param priv_proto    - Possible values are:
+   *                                SNMP_PRIVPROTOCOL_NONE,
+   *                                SNMP_PRIVPROTOCOL_DES,
+   *                                SNMP_PRIVPROTOCOL_IDEA
+   * @param priv_key      - The key used for privacy
+   *
+   * @return - SNMPv3_USM_OK
+   *           SNMP_v3_USM_ERROR (not initialized, no memory)
+   */
+  int add_entry(const OctetStr &engine_id,
+               const OctetStr &user_name,  const OctetStr &sec_name,
+               const long int  auth_proto, const OctetStr &auth_key,
+               const long int  priv_proto, const OctetStr &priv_key);
+
+  /**
+   * Replace a localized key of the user and engine_id in the
+   * usmUserTable.
+   *
+   * @param user_name     - The name of the user in the USM
+   * @param engine_id     - Change the localized key for the SNMP
+   *                        entity with this engine_id
+   * @param new_key       - The new key
+   * @param key_type      - AUTHKEY, OWNAUTHKEY, PRIVKEY or OWNPRIVKEY
+   *
+   * @return - SNMPv3_USM_ERROR (no such entry or not initialized),
+   *           SNMPv3_USM_OK
+   */
+  int update_key(const OctetStr &user_name,
+                 const OctetStr &engine_id,
+                 const OctetStr &new_key,
+                 const int key_type);
+
+  /**
+   * Save all entries into a file.
+   */
+  int save_to_file(const char *name, AuthPriv *ap);
+
+  /**
+   * Load the table from a file.
+   */
+  int load_from_file(const char *name, AuthPriv *ap);
+
+  const UsmUserTableEntry *peek_first() const
+    { if (entries > 0) return table; return 0; };
+
+  const UsmUserTableEntry *peek_next(const UsmUserTableEntry *e) const;
+
+private:
+  void delete_entry(const int nr);
+
+  struct UsmUserTableEntry *table;
+
+  int max_entries; ///< the maximum number of entries
+  int entries;     ///< the current amount of entries
+};
+
+
+
+struct UsmSecurityParameters {
+  unsigned char  msgAuthoritativeEngineID[MAXLENGTH_ENGINEID];
+  long int       msgAuthoritativeEngineIDLength;
+  long int       msgAuthoritativeEngineBoots;
+  long int       msgAuthoritativeEngineTime;
+  unsigned char  msgUserName[MAXLEN_USMUSERNAME];
+  long int       msgUserNameLength;
+  unsigned char *msgAuthenticationParameters;
+  long int       msgAuthenticationParametersLength;
+  unsigned char *msgPrivacyParameters;
+  unsigned int   msgPrivacyParametersLength;
+};
+
+
+
+
+struct SecurityStateReference
+{
+  unsigned char  msgUserName[MAXLEN_USMUSERNAME]; int msgUserNameLength;
+  unsigned char *securityName;                    int securityNameLength;
+  unsigned char *securityEngineID;                int securityEngineIDLength;
+  int authProtocol;
+  unsigned char* authKey;                         int authKeyLength;
+  int privProtocol;
+  unsigned char* privKey;                         int privKeyLength;
+  int securityLevel;
+};
+
+
+
+
+void USM::inc_stats_unsupported_sec_levels()
+{
+  if (usmStatsUnsupportedSecLevels == MAXUINT32)
+    usmStatsUnsupportedSecLevels = 0;
+  else
+    usmStatsUnsupportedSecLevels++;
+}
+
+void USM::inc_stats_not_in_time_windows()
+{
+  if (usmStatsNotInTimeWindows == MAXUINT32)
+    usmStatsNotInTimeWindows = 0;
+  else
+    usmStatsNotInTimeWindows++;
+}
+
+void USM::inc_stats_unknown_user_names()
+{
+  if (usmStatsUnknownUserNames == MAXUINT32)
+    usmStatsUnknownUserNames = 0;
+  else
+    usmStatsUnknownUserNames++;
+}
+
+void USM::inc_stats_unknown_engine_ids()
+{
+  if (usmStatsUnknownEngineIDs == MAXUINT32)
+    usmStatsUnknownEngineIDs = 0;
+  else
+    usmStatsUnknownEngineIDs++;
+}
+
+void USM::inc_stats_wrong_digests()
+{
+  if (usmStatsWrongDigests == MAXUINT32)
+    usmStatsWrongDigests = 0;
+  else
+    usmStatsWrongDigests++;
+}
+
+void USM::inc_stats_decryption_errors()
+{
+  if (usmStatsDecryptionErrors == MAXUINT32)
+    usmStatsDecryptionErrors = 0;
+  else
+    usmStatsDecryptionErrors++;
+}
+
+
+void USM::delete_sec_state_reference(struct SecurityStateReference *ssr)
+{
+  if (ssr)
+  {
+    ssr->msgUserName[0] = 0;
+    if (ssr->securityName) delete [] ssr->securityName;
+    if (ssr->securityEngineID) delete [] ssr->securityEngineID;
+    if (ssr->authKey)
+    {
+      memset(ssr->authKey, 0, ssr->authKeyLength);
+      delete [] ssr->authKey;
+    }
+    if (ssr->privKey)
+    {
+      memset(ssr->privKey, 0, ssr->privKeyLength);
+      delete [] ssr->privKey;
+    }
+  }
+  delete ssr;
+}
+
+struct SecurityStateReference *USM::get_new_sec_state_reference()
+{
+  struct SecurityStateReference *res = new SecurityStateReference;
+
+  if (!res)
+    return NULL;
+
+  memset(res, 0, sizeof(struct SecurityStateReference));
+  return res;
+}
+
+
+USM::USM(unsigned int engine_boots, const OctetStr &engine_id,
+        const v3MP *v3_mp,
+        unsigned int *msgID, int &result)
+  : local_snmp_engine_id (engine_id),
+    v3mp (v3_mp),
+
+    discovery_mode (TRUE),
+
+    usmStatsUnsupportedSecLevels (0),
+    usmStatsNotInTimeWindows     (0),
+    usmStatsUnknownUserNames     (0),
+    usmStatsUnknownEngineIDs     (0),
+    usmStatsWrongDigests         (0),
+    usmStatsDecryptionErrors     (0),
+
+    usm_add_user_cb (0)
+{
+  auth_priv = new AuthPriv(result);
+  if (result != SNMPv3_USM_OK)
+    return;
+  auth_priv->add_default_modules();
+
+  usm_user_name_table = new USMUserNameTable(result);
+  if (result != SNMPv3_USM_OK)
+    return;
+
+  usm_user_table = new USMUserTable(result);
+  if (result != SNMPv3_USM_OK)
+    return;
+
+#ifdef _TEST
+
+  printf("\nTesting 3DES starts\n\n");
+  OctetStr engineId = OctetStr::from_hex_string("00 00 00 00 00 00 "
+                                               "00 00 00 00 00 02");
+
+  OctetStr oldKey, newKey, delta;
+  oldKey.set_len(64);
+  newKey.set_len(64);
+  unsigned int key_len=64;
+
+  debughexcprintf(0,"engineID", engineId.data(), engineId.len());
+
+  auth_priv->password_to_key_priv(SNMP_AUTHPROTOCOL_HMACSHA,
+                                SNMP_PRIVPROTOCOL_3DESEDE,
+                                (unsigned char*)"maplesyrup", 10,
+                                engineId.data(), engineId.len(),
+                                oldKey.data(),
+                                &key_len);
+  oldKey.set_len(key_len);
+  key_len=64;
+  auth_priv->password_to_key_priv(SNMP_AUTHPROTOCOL_HMACSHA,
+                                SNMP_PRIVPROTOCOL_3DESEDE,
+                                (unsigned char*)"newsyrup", 8,
+                                engineId.data(), engineId.len(),
+                                newKey.data(),
+                                &key_len);
+  newKey.set_len(key_len);
+
+  OctetStr expectedKey = OctetStr::from_hex_string("78 e2 dc ce 79 d5 94 03 b5 8c 1b ba a5 bf f4 63 91 f1 cd 25 97 74 35 55 f9 fc f9 4a c3 e7 e9 22");
+
+  if (newKey != expectedKey)
+  {
+      printf("newKey != expectedKey\n");
+      printf("newKey:   %s\n", newKey.get_printable_hex());
+      printf("expected: %s\n", expectedKey.get_printable_hex());
+  }
+
+  auth_priv->get_keychange_value(SNMP_AUTHPROTOCOL_HMACSHA,
+                                 oldKey, newKey, delta);
+
+  OctetStr expectedDelta = OctetStr::from_hex_string(
+      "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
+      "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 "
+      "ce 13 28 fb 9a 9c 19 ce c1 51 a3 5a 77 f9 20 39 "
+      "ca ff 00 c9 b3 9b 19 a0 5e 01 75 55 94 37 6a 57");
+
+  if (delta != expectedDelta)
+  {
+      printf("delta != expectedDelta\n");
+      printf("delta:    %s\n", delta.get_printable_hex());
+      printf("expected: %s\n", expectedDelta.get_printable_hex());
+  }
+
+  printf("\nTesting 3DES finished\n\n");
+
+  printf(" Testing DES:\n");
+  PrivDES pd;
+  pp_uint64 testsalt=0xbabec0de;
+  pd.set_salt(&testsalt);
+
+  const char *desplaintext[10];
+  desplaintext[0] = "abcdefghijklmnopqrstuvwxyz123456";
+  desplaintext[1] = "abcdefghijklmnopqrstuvwxyz1234567";
+  desplaintext[2] = "abcdefghijklmnopqrstuvwxyz12345678";
+  desplaintext[3] = "abcdefghijklmnopqrstuvwxyz123456789";
+  desplaintext[4] = "abcdefghijklmnopqrstuvwxyz123456789A";
+  desplaintext[5] = "abcdefghijklmnopqrstuvwxyz123456789AB";
+  desplaintext[6] = "abcdefghijklmnopqrstuvwxyz123456789ABC";
+  desplaintext[7] = "abcdefghijklmnopqrstuvwxyz123456789ABCD";
+  desplaintext[8] = "abcdefghijklmnopqrstuvwxyz123456789ABCDE";
+  desplaintext[9] = "abcdefghijklmnopqrstuvwxyz123456789ABCDEF";
+
+  unsigned char desencrypted[80];
+  unsigned char desdecrypted[80];
+  unsigned char desprivparams[8];
+  unsigned char deskey[17] = "illegal_des_key!";
+
+  for (int i=0; i<9; i++)
+  {
+      unsigned int encrypt_len = 80;
+      unsigned int decrypt_len = 80;
+      unsigned int desprivparamslen = 8;
+
+      memset(desencrypted, 'x', 80);
+      memset(desdecrypted, 'y', 80);
+
+      debughexcprintf(1, "Plaintext", (unsigned char*)desplaintext[i],
+                     strlen(desplaintext[i]));
+
+      int res = pd.encrypt(deskey, 16,
+                          (unsigned char*)desplaintext[i],
+                          strlen(desplaintext[i]),
+                          desencrypted, &encrypt_len,
+                          desprivparams, &desprivparamslen,
+                          0x2340abcd, 0);
+
+      printf("%d: Result of encryption is %d\n", i, res);
+      debughexcprintf(1, "Encrypted", desencrypted, encrypt_len);
+
+      res = pd.decrypt(deskey, 16,
+                      desencrypted, encrypt_len,
+                      desdecrypted, &decrypt_len,
+                      desprivparams, desprivparamslen,
+                      0x2340abcd, 0);
+      printf("%d: Result of decryption is %d\n", i, res);
+      debughexcprintf(1, "Decrypted", desdecrypted, decrypt_len);
+
+      if (memcmp(desplaintext[i], desdecrypted, strlen(desplaintext[i])))
+         printf("\n********* FAILED **********\n");
+      else
+         printf("\nOK\n");
+
+  }
+
+
+
+#if 0
+  printf(" Testing SHA:\n");
+
+  // test password2key-algor:
+  unsigned char keysha[50];
+  auth_priv->password_to_key_auth(...(unsigned char*)"maplesyrup",10,
+                     (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,keysha);
+  printf("Output of PasswordToKey-algorithm for SHA:\n");
+  for (int i=0; i< 20; i++) {
+    printf("%02X ", keysha[i]);
+    if ((i+1)%4==0) printf(" ");
+    if ((i+1)%16==0) printf("\n");
+  }
+  printf("\nOutput should be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
+  printf("66 95 fe bc  92 88 e3 62  82 23 5f c7  15 1f 12 84\n97 b3 8f 3f\n");
+  printf("\nTesting MD5:\n");
+  unsigned char keymd5[50];
+  apPasswordToKeyMD5((unsigned char*)"maplesyrup",10,
+                     (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,keymd5);
+  printf("Output of PasswordToKey-algorithm for MD5:\n");
+  for (int i=0; i< 16; i++) {
+    printf("%02X ", keymd5[i]);
+    if ((i+1)%4==0) printf(" ");
+    if ((i+1)%16==0) printf("\n");
+  }
+  printf("Output ahould be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
+  printf("52 6f 5e ed  9f cc e2 6f  89 64 c2 93  07 87 d8 2b\n");
+
+  printf("\nTesting IDEA:\n");
+  unsigned char source[35] = "Hallo, das ist ein test!", encrypted[35], decrypted[35], params[8];
+  int len_encrypted = 35, len_decrypted = 35;
+  apIDEAEncryptData((unsigned char*)"1234567890abcdef",
+                    source, 25, encrypted, &len_encrypted, params);
+
+  apIDEADecryptData((unsigned char*)"1234567890abcdef",
+                    encrypted, len_encrypted,
+                     decrypted, &len_decrypted, params);
+
+
+  printf("params:\n");
+  for (int i=0; i< 8; i++) {
+    printf("%02X ", params[i]);
+    if ((i+1)%4==0) printf(" ");
+    if ((i+1)%16==0) printf("\n");
+  }
+  printf("\nsource:\n");
+  for (int i=0; i< 25; i++) {
+    printf("%02X ", source[i]);
+    if ((i+1)%4==0) printf(" ");
+    if ((i+1)%16==0) printf("\n");
+  }
+  printf("\n");
+  printf("encrypted:\n");
+  for (int i=0; i< 25; i++) {
+    printf("%02X ", encrypted[i]);
+    if ((i+1)%4==0) printf(" ");
+    if ((i+1)%16==0) printf("\n");
+  }
+  printf("\n");
+  printf("decrypted:\n");
+  for (int i=0; i< 25; i++) {
+    printf("%02X ", decrypted[i]);
+    if ((i+1)%4==0) printf(" ");
+    if ((i+1)%16==0) printf("\n");
+  }
+  printf("\n");
+  for (int i=0; i<25; i++)
+    if (source[i]!=decrypted[i]) {
+      printf("\n*** source != decrypted ****\n\n");
+      break;
+    }
+
+  // test keyUpdate md5
+  printf("\n Test KeyUpdate Algorithm:\n");
+  printf("Test MD5:\n");
+  OctetStr oldKey = OctetStr(keymd5, SNMPv3_AP_OUTPUT_LENGTH_MD5);
+
+  unsigned char newkeymd5[50];
+  apPasswordToKeyMD5((unsigned char*)"newsyrup",8,
+                     (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,newkeymd5);
+  printf("Output of PasswordToKey-algorithm for MD5:\n");
+  for (int i=0; i< 16; i++) {
+    printf("%02X ", newkeymd5[i]);
+    if ((i+1)%4==0) printf(" ");
+    if ((i+1)%16==0) printf("\n");
+  }
+  printf("Output ahould be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
+  printf("87 02 1d 7b  d9 d1 01 ba  05 ea 6e 3b  f9 d9 bd 4a\n");
+  OctetStr result;
+  apNewKey(oldKey, OctetStr(newkeymd5, SNMPv3_AP_OUTPUT_LENGTH_MD5),
+            result, SNMPv3_usmHMACMD5AuthProtocol);
+
+  // test keyUpdate sha (auth)
+  printf("\nTest SHA for authPassword:\n");
+  oldKey = OctetStr(keysha, SNMPv3_AP_OUTPUT_LENGTH_SHA);
+
+  unsigned char newkeysha[50];
+  apPasswordToKeySHA((unsigned char*)"newsyrup",8,
+                     (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2",12,newkeysha);
+  printf("Output of PasswordToKey-algorithm for sha:\n");
+  for (int i=0; i< SNMPv3_AP_OUTPUT_LENGTH_SHA; i++) {
+    printf("%02X ", newkeysha[i]);
+    if ((i+1)%4==0) printf(" ");
+    if ((i+1)%16==0) printf("\n");
+  }
+  printf("Output ahould be (draft-ietf-snmpv3-usm-v2-02.txt):\n");
+  printf("78 e2 dc ce  79 d5 94 03  b5 8c 1b ba  a5 bf f4 63 \n91 f1 cd 25\n");
+
+  apNewKey(oldKey, OctetStr(newkeysha, SNMPv3_AP_OUTPUT_LENGTH_SHA),
+            result, SNMPv3_usmHMACSHAAuthProtocol);
+  // test keyUpdate sha (privPassword DES)
+  printf("\nTest SHA for privPassword:\n");
+
+  oldKey = OctetStr(keysha, SNMPv3_AP_OUTPUT_LENGTH_MD5);
+  apNewKey(oldKey, OctetStr(newkeysha, SNMPv3_AP_OUTPUT_LENGTH_MD5),
+            result, SNMPv3_usmHMACSHAAuthProtocol);
+  printf("Result should be:\n");
+  printf("00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00\n");
+  printf("7e f8 d8 a4  c9 cd b2 6b  47 59 1c d8  52 ff 88 b5\n");
+#endif
+  /* test AES key extension algorithm */
+  unsigned char key_sha[SNMPv3_USM_MAX_KEY_LEN];
+  unsigned int key_sha_len = SNMPv3_USM_MAX_KEY_LEN;
+
+  int res = auth_priv->password_to_key_priv(
+    SNMP_AUTHPROTOCOL_HMACSHA,
+    SNMP_PRIVPROTOCOL_AES256,
+    (unsigned char*)"maplesyrup", 10,
+    (unsigned char*)"\0\0\0\0\0\0\0\0\0\0\0\2", 12,
+    key_sha, &key_sha_len);
+
+  debugprintf(0, "aes key extension result %i, key_sha_len = %i.",
+             res, key_sha_len);
+  debughexcprintf(0, "key_sha", key_sha, key_sha_len);
+
+  unsigned char pt[56] = "This is a secret message, nobody is allowed to read it!";
+  unsigned char *plaintext = pt;
+  unsigned char ct[56];
+  unsigned char *cipher = ct;
+  unsigned int cipherlen = 56;
+  unsigned char privpar[8];
+  unsigned int privparlen = 8;
+
+  Priv *priv = auth_priv->get_priv(SNMP_PRIVPROTOCOL_AES256);
+  pp_uint64 salt = 0;
+  priv->set_salt(&salt);
+  auth_priv->encrypt_msg(SNMP_PRIVPROTOCOL_AES256,
+                        key_sha, key_sha_len,
+                        plaintext, 55, cipher, &cipherlen,
+                        privpar, &privparlen,
+                        0xdeadc0deUL, 0xbeefdedeUL);
+
+  auth_priv->decrypt_msg(SNMP_PRIVPROTOCOL_AES256,
+                        key_sha, key_sha_len,
+                        cipher, 55, plaintext, &cipherlen,
+                        privpar, privparlen,
+                        0xdeadc0deUL, 0xbeefdedeUL);
+
+#endif // _TEST
+
+  usm_time_table = new USMTimeTable(this, engine_boots, result);
+  if (result != SNMPv3_USM_OK)
+    return;
+
+  *msgID = (engine_boots & 0x7FFF) << 16;
+}
+
+USM::~USM()
+{
+  if (usm_time_table)
+    delete usm_time_table;
+  usm_time_table = NULL;
+
+  if (usm_user_table)
+    delete usm_user_table;
+  usm_user_table = NULL;
+
+  if (usm_user_name_table)
+  {
+    delete usm_user_name_table;
+    usm_user_name_table = NULL;
+  }
+
+  if (auth_priv)
+  {
+    delete auth_priv;
+    auth_priv = NULL;
+  }
+}
+
+// Delete this engine id form all USM tables (users and engine time).
+int USM::remove_engine_id(const OctetStr &engine_id)
+{
+  int retval1, retval2;
+
+  retval1 = usm_time_table->delete_entry(engine_id);
+
+  retval2 = usm_user_table->delete_entries(engine_id);
+
+  if ((retval1 == SNMPv3_USM_ERROR) ||
+      (retval2 == SNMPv3_USM_ERROR))
+    return SNMPv3_USM_ERROR;
+
+  return SNMPv3_USM_OK;
+}
+
+// Delete the time information for the given engine id
+int USM::remove_time_information(const OctetStr &engine_id)
+{
+  if (usm_time_table->delete_entry(engine_id) == SNMPv3_USM_ERROR)
+    return SNMPv3_USM_ERROR;
+
+  return SNMPv3_USM_OK;
+}
+
+int USM::update_key(const unsigned char* user_name,
+                   const long int user_name_len,
+                   const unsigned char* engine_id,
+                   const long int engine_id_len,
+                   const unsigned char* new_key,
+                   const long int new_key_len,
+                   const int type_of_key)
+{
+  OctetStr key(new_key, new_key_len);
+  int res;
+  res = usm_user_table->update_key(OctetStr(user_name, user_name_len),
+                                  OctetStr(engine_id, engine_id_len),
+                                  key, type_of_key);
+  key.clear();
+  return res;
+}
+
+int USM::add_localized_user(const OctetStr &engine_id,
+                           const OctetStr &user_name,
+                           const OctetStr &security_name,
+                           const long auth_protocol,
+                           const OctetStr &auth_key,
+                           const long priv_protocol,
+                           const OctetStr &priv_key)
+{
+   return usm_user_table->add_entry(engine_id, user_name, security_name,
+                                    auth_protocol, auth_key,
+                                    priv_protocol, priv_key);
+}
+
+
+int USM::add_usm_user(const OctetStr& user_name,
+                     const OctetStr& security_name,
+                     const long int  auth_protocol,
+                     const long int  priv_protocol,
+                     const OctetStr& auth_password,
+                     const OctetStr& priv_password)
+{
+  /*  delete localized entries if some exists */
+  delete_localized_user(user_name);
+
+  int result = usm_user_name_table->add_entry(user_name,security_name,
+                                             auth_protocol, priv_protocol,
+                                             auth_password, priv_password);
+  if (result != SNMPv3_USM_OK)
+    return result;
+
+  struct UsmUser *dummy;
+  dummy = get_user(local_snmp_engine_id, security_name);
+  if (dummy) free_user(dummy);
+
+  return SNMPv3_USM_OK;
+}
+
+int USM::add_usm_user(const OctetStr& user_name,
+                     const OctetStr& security_name,
+                     const long int  auth_protocol,
+                     const long int  priv_protocol,
+                     const OctetStr& auth_password,
+                     const OctetStr& priv_password,
+                     const OctetStr& engine_id)
+{
+  OctetStr auth_key;
+  OctetStr priv_key;
+
+  auth_key.set_len(SNMPv3_USM_MAX_KEY_LEN);
+  priv_key.set_len(SNMPv3_USM_MAX_KEY_LEN);
+
+  unsigned int auth_key_len = auth_key.len();
+  unsigned int priv_key_len = priv_key.len();
+
+  int res = build_localized_keys(engine_id, auth_protocol, priv_protocol,
+                                auth_password.data(), auth_password.len(),
+                                priv_password.data(), priv_password.len(),
+                                auth_key.data(), &auth_key_len,
+                                priv_key.data(), &priv_key_len);
+
+  if (res != SNMPv3_USM_OK)
+    return res;
+
+  auth_key.set_len(auth_key_len);
+  priv_key.set_len(priv_key_len);
+
+  res = usm_user_table->add_entry(engine_id, user_name, security_name,
+                                 auth_protocol, auth_key,
+                                 priv_protocol, priv_key);
+
+  auth_key.clear();
+  priv_key.clear();
+
+  return res;
+}
+
+int USM::add_usm_user(const OctetStr& security_name,
+                     const long int  auth_protocol,
+                     const long int  priv_protocol,
+                     const OctetStr& auth_password,
+                     const OctetStr& priv_password)
+{
+  // usmUserName:     UserName for UserbasedSecurityModel
+  // usmSecurityName: UserName for all SecurityModels
+  return add_usm_user(security_name, security_name,
+                     auth_protocol, priv_protocol,
+                     auth_password, priv_password);
+}
+
+int USM::delete_localized_user(const OctetStr& usmUserName)
+{
+  return usm_user_table->delete_entries(usmUserName);
+}
+
+int USM::delete_localized_user(const OctetStr& engine_id,
+                              const OctetStr& user_name)
+{
+  return usm_user_table->delete_entry(engine_id, user_name);
+}
+
+
+int USM::build_localized_keys(const OctetStr      &engine_id,
+                             const int            auth_prot,
+                             const int            priv_prot,
+                             const unsigned char *auth_password,
+                             const unsigned int   auth_password_len,
+                             const unsigned char *priv_password,
+                             const unsigned int   priv_password_len,
+                             unsigned char *auth_key,
+                             unsigned int  *auth_key_len,
+                             unsigned char *priv_key,
+                             unsigned int  *priv_key_len)
+{
+  int res = auth_priv->password_to_key_auth(
+                                 auth_prot, auth_password,
+                                 auth_password_len,
+                                 engine_id.data(), engine_id.len(),
+                                 auth_key, auth_key_len);
+
+  if (res != SNMPv3_USM_OK)
+  {
+    if (res == SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL)
+    {
+       LOG_BEGIN(ERROR_LOG | 4);
+       LOG("Could not generate localized key: Unsupported auth protocol");
+       LOG(auth_prot);
+       LOG_END;
+    }
+    else
+    {
+       LOG_BEGIN(ERROR_LOG | 4);
+       LOG("Could not generate localized auth key, error code");
+       LOG(res);
+       LOG_END;
+    }
+    return res;
+  }
+
+  res = auth_priv->password_to_key_priv(auth_prot, priv_prot, priv_password,
+                                       priv_password_len,
+                                       engine_id.data(), engine_id.len(),
+                                       priv_key, priv_key_len);
+
+  if (res != SNMPv3_USM_OK)
+  {
+    if (res == SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL)
+    {
+       LOG_BEGIN(ERROR_LOG | 4);
+       LOG("Could not generate localized key: Unsupported priv protocol");
+       LOG(priv_prot);
+       LOG_END;
+    }
+    else
+    {
+       LOG_BEGIN(ERROR_LOG | 4);
+       LOG("Could not generate localized priv key, error code");
+       LOG(res);
+       LOG_END;
+    }
+    return res;
+  }
+
+  return res; // OK
+}
+
+struct UsmUser *USM::get_user(const OctetStr &engine_id,
+                             const OctetStr &security_name)
+{
+  debugprintf(7,"USM::get_user: user (%s) engine_id (%s)",
+              security_name.get_printable(),engine_id.get_printable());
+
+  struct UsmUserNameTableEntry *name_table_entry = NULL;
+  struct UsmUserTableEntry *user_table_entry = NULL;
+
+  user_table_entry = usm_user_table->get_cloned_entry(engine_id,
+                                                     security_name);
+  if (!user_table_entry)
+  {
+    name_table_entry = usm_user_name_table->get_cloned_entry(security_name);
+    if (!name_table_entry)
+    {
+      const struct UsmUserTableEntry *entry;
+
+      BEGIN_AUTO_LOCK(usm_user_table);
+
+      entry = usm_user_table->get_entry(security_name);
+
+      if ((entry) && (engine_id.len() == 0))
+      {
+        // there is a entry for this security_name in the usmUserTable
+        // so return an entry for this user to do engine_id discovery
+        struct UsmUser *res = new UsmUser;
+        if (!res)
+          return 0;
+
+        res->engineID = 0;
+        res->engineIDLength = 0;
+        res->usmUserName = v3strcpy(entry->usmUserName,
+                                   entry->usmUserNameLength);
+        res->usmUserNameLength = entry->usmUserNameLength;
+        res->securityName = v3strcpy(entry->usmUserSecurityName,
+                                    entry->usmUserSecurityNameLength);
+        res->securityNameLength = entry->usmUserSecurityNameLength;
+        res->authProtocol = SNMP_AUTHPROTOCOL_NONE;
+        res->authKey = 0;        res->authKeyLength = 0;
+        res->privProtocol = SNMP_PRIVPROTOCOL_NONE;
+        res->privKey = 0;        res->privKeyLength = 0;
+
+       if ((res->usmUserNameLength  && !res->usmUserName) ||
+           (res->securityNameLength && !res->securityName))
+       {
+           free_user(res);
+       }
+        return res;
+      }
+      else
+      {
+        debugprintf(1, "USM::get_user: User unknown");
+        return NULL;
+      }
+    }
+    // here we have valid name_table_entry but not user_table_entry
+    if (engine_id.len() == 0)
+    {
+      // do not add a user
+      struct UsmUser *res = new UsmUser;
+      if (!res)
+      {
+       usm_user_name_table->delete_cloned_entry(name_table_entry);
+        return 0;
+      }
+      res->engineID           = 0;
+      res->engineIDLength     = 0;
+      res->usmUserName        = v3strcpy(name_table_entry->usmUserName.data(),
+                                        name_table_entry->usmUserName.len());
+      res->usmUserNameLength  = name_table_entry->usmUserName.len();
+      res->securityName       = v3strcpy(
+                                 name_table_entry->usmUserSecurityName.data(),
+                                 name_table_entry->usmUserSecurityName.len());
+      res->securityNameLength = name_table_entry->usmUserSecurityName.len();
+      res->authProtocol       = SNMP_AUTHPROTOCOL_NONE;
+      res->authKey            = 0;
+      res->authKeyLength      = 0;
+      res->privProtocol       = SNMP_PRIVPROTOCOL_NONE;
+      res->privKey            = 0;
+      res->privKeyLength      = 0;
+
+      if ((res->usmUserNameLength  && !res->usmUserName) ||
+         (res->securityNameLength && !res->securityName))
+      {
+         free_user(res);
+      }
+      usm_user_name_table->delete_cloned_entry(name_table_entry);
+      return res;
+    }
+    else
+    {
+      // We can add a new user:
+      unsigned char privKey[SNMPv3_USM_MAX_KEY_LEN];
+      unsigned char authKey[SNMPv3_USM_MAX_KEY_LEN];
+      unsigned int authKeyLength = SNMPv3_USM_MAX_KEY_LEN;
+      unsigned int privKeyLength = SNMPv3_USM_MAX_KEY_LEN;
+
+      int res = build_localized_keys(engine_id,
+                        name_table_entry->usmUserAuthProtocol,
+                        name_table_entry->usmUserPrivProtocol,
+                        name_table_entry->authPassword,
+                        name_table_entry->authPasswordLength,
+                        name_table_entry->privPassword,
+                        name_table_entry->privPasswordLength,
+                        authKey, &authKeyLength,
+                        privKey, &privKeyLength);
+
+      if (res != SNMPv3_USM_OK)
+      {
+       LOG_BEGIN(ERROR_LOG | 4);
+       LOG("Cannot add User: error code");
+       LOG(res);
+       LOG_END;
+
+       usm_user_name_table->delete_cloned_entry(name_table_entry);
+        return 0;
+      }
+
+      OctetStr akey(authKey, authKeyLength);
+      OctetStr pkey(privKey, privKeyLength);
+      add_localized_user(
+        engine_id,
+        name_table_entry->usmUserName,
+        name_table_entry->usmUserSecurityName,
+        name_table_entry->usmUserAuthProtocol, akey,
+        name_table_entry->usmUserPrivProtocol, pkey);
+
+      if (usm_add_user_cb)
+      {
+        // inform agent++ about new user
+        debugprintf(5, "Informing agent++ about newly created user");
+        usm_add_user_cb(engine_id,
+                        name_table_entry->usmUserName,
+                        name_table_entry->usmUserSecurityName,
+                        name_table_entry->usmUserAuthProtocol, akey,
+                        name_table_entry->usmUserPrivProtocol, pkey);
+      }
+      akey.clear();
+      pkey.clear();
+
+      user_table_entry = usm_user_table->get_cloned_entry(engine_id,
+                                                         security_name);
+      if (!user_table_entry)
+      {
+       LOG_BEGIN(ERROR_LOG | 1);
+       LOG("Get of just added localized entry failed (sec name) (engine id)");
+       LOG(security_name.get_printable());
+       LOG(engine_id.get_printable());
+       LOG_END;
+       usm_user_name_table->delete_cloned_entry(name_table_entry);
+        return 0;
+      }
+    }
+    usm_user_name_table->delete_cloned_entry(name_table_entry);
+  }
+  struct UsmUser *res = new UsmUser;
+  if (!res)
+  {
+    usm_user_table->delete_cloned_entry(user_table_entry);
+    return 0;
+  }
+  res->engineID           = user_table_entry->usmUserEngineID;
+  res->engineIDLength     = user_table_entry->usmUserEngineIDLength;
+  res->usmUserName        = user_table_entry->usmUserName;
+  res->usmUserNameLength  = user_table_entry->usmUserNameLength;
+  res->securityName       = user_table_entry->usmUserSecurityName;
+  res->securityNameLength = user_table_entry->usmUserSecurityNameLength;
+  res->authProtocol       = user_table_entry->usmUserAuthProtocol;
+  res->authKey            = user_table_entry->usmUserAuthKey;
+  res->authKeyLength      = user_table_entry->usmUserAuthKeyLength;
+  res->privProtocol       = user_table_entry->usmUserPrivProtocol;
+  res->privKey            = user_table_entry->usmUserPrivKey;
+  res->privKeyLength      = user_table_entry->usmUserPrivKeyLength;
+
+  user_table_entry->usmUserEngineID = 0;
+  user_table_entry->usmUserName = 0;
+  user_table_entry->usmUserSecurityName = 0;
+  user_table_entry->usmUserAuthKey = 0;
+  user_table_entry->usmUserPrivKey = 0;
+
+  usm_user_table->delete_cloned_entry(user_table_entry);
+
+  return res;
+}
+
+// Free the structure returned from get_user().
+void USM::free_user(struct UsmUser *&user)
+{
+  if (!user) return;
+
+  if (user->engineID)     delete [] user->engineID;
+  if (user->usmUserName)  delete [] user->usmUserName;
+  if (user->securityName) delete [] user->securityName;
+
+  if (user->authKey)
+  {
+    memset(user->authKey, 0, user->authKeyLength);
+    delete [] user->authKey;
+  }
+
+  if (user->privKey)
+  {
+    memset(user->privKey, 0, user->privKeyLength);
+    delete [] user->privKey;
+  }
+
+  delete user;
+
+  user = 0;
+}
+
+void USM::delete_usm_user(const OctetStr& security_name)
+{
+  usm_user_name_table->delete_security_name(security_name);
+
+  unsigned char username[MAXLEN_USMUSERNAME + 1];
+  long int length = MAXLEN_USMUSERNAME;
+
+  if ((get_user_name(username, &length,
+                    security_name.data(), security_name.len()))
+      == SNMPv3_USM_OK)
+    delete_localized_user(OctetStr(username, length));
+}
+
+int USM::get_security_name(const unsigned char *user_name,
+                          const long int user_name_len,
+                          OctetStr &security_name)
+{
+  debugprintf(20,"USM::get_security_name: get  user (%s)",
+              OctetStr(user_name,user_name_len).get_printable());
+
+  int result;
+
+  result = usm_user_name_table->get_security_name(user_name, user_name_len,
+                                                  security_name);
+  if (result == SNMPv3_USM_OK)
+    return SNMPv3_USM_OK;
+
+  result = usm_user_table->get_security_name(user_name, user_name_len,
+                                             security_name);
+  if (result == SNMPv3_USM_OK)
+    return SNMPv3_USM_OK;
+
+  debugprintf(1, "USM::get_security_name: User unknown");
+  return SNMPv3_USM_ERROR;
+}
+
+int USM::get_user_name(unsigned char *user_name, long int *user_name_len,
+                      const unsigned char *security_name,
+                      const long int security_name_len)
+{
+  int result;
+  long int  buf_len = *user_name_len;
+
+  result = usm_user_name_table->get_user_name(user_name, user_name_len,
+                                              security_name,
+                                             security_name_len);
+
+  if (result == SNMPv3_USM_OK)
+    return SNMPv3_USM_OK;
+
+  *user_name_len = buf_len;
+
+  result = usm_user_table->get_user_name(user_name, user_name_len,
+                                         security_name, security_name_len);
+
+  if (result == SNMPv3_USM_OK)
+    return SNMPv3_USM_OK;
+
+  debugprintf(1, "usmGetUsmUserName: User unknown");
+  return SNMPv3_USM_ERROR;
+}
+
+
+void USM::delete_sec_parameters( struct UsmSecurityParameters *usp)
+{
+  usp->msgAuthoritativeEngineID[0] = 0;
+  usp->msgAuthoritativeEngineIDLength = 0;
+  usp->msgAuthoritativeEngineBoots = 0;
+  usp->msgAuthoritativeEngineTime = 0;
+  usp->msgUserName[0] = 0;
+  usp->msgUserNameLength = 0;
+
+  if (usp->msgAuthenticationParameters) {
+    delete [] usp->msgAuthenticationParameters;
+    usp->msgAuthenticationParameters = NULL;
+  }
+  usp->msgAuthenticationParametersLength = 0;
+  if (usp->msgPrivacyParameters) {
+    delete [] usp->msgPrivacyParameters;
+    usp->msgPrivacyParameters = NULL;
+  }
+  usp->msgPrivacyParametersLength = 0;
+}
+
+
+const struct UsmUserTableEntry *USM::get_user(int number)
+{
+  return usm_user_table->get_entry(number);
+}
+
+const struct UsmUserNameTableEntry *USM::get_user(const OctetStr &security_name)
+{
+  return usm_user_name_table->get_entry(security_name);
+}
+
+int USM::get_user_count() const
+{
+  return usm_user_table->size();
+}
+
+DLLOPT void USM::add_user_added_callback(const usm_add_user_callback cb)
+{
+ usm_add_user_cb = cb;
+}
+
+int USM::get_time(const OctetStr &engine_id,
+                 long int *engine_boots, long int *engine_time)
+{
+  return usm_time_table->get_time(engine_id, *engine_boots, *engine_time);
+}
+
+int USM::get_local_time(long int *engine_boots, long int *engine_time) const
+{
+  return usm_time_table->get_local_time(*engine_boots, *engine_time);
+}
+
+AuthPriv *USM::get_auth_priv()
+{
+  return auth_priv;
+}
+
+struct UsmKeyUpdate* USM::key_update_prepare(const OctetStr& securityName,
+                                            SnmpTarget& target,
+                                            const OctetStr& newPassword,
+                                            Pdu& pdu, int type,
+                                            int &status,
+                                            const OctetStr& oldpass,
+                                            const OctetStr& oldengid,
+                                            const OctetStr& newengid)
+{
+  // check address
+
+  GenAddress genaddress;
+  target.get_address(genaddress);
+  UdpAddress udp_address(genaddress);
+  if (!udp_address.valid()) {
+    debugprintf(0, "usmPrepareKeyUpdate: Address invalid.");
+    status = SNMPv3_USM_ADDRESS_ERROR;
+    return NULL;
+  }
+
+  OctetStr engineID = "";
+  // get engineID
+  if (v3mp->get_from_engine_id_table(engineID,
+                                    (char*)udp_address.get_printable())
+      != SNMPv3_MP_OK ) {
+    debugprintf(0, "usmPrepareKeyUpdate: Could not find engineID of given address.");
+    status = SNMPv3_USM_ADDRESS_ERROR;
+    return NULL;
+  }
+
+  // get user
+  struct UsmUser* user;
+  user = get_user(engineID, securityName);
+
+  if (user == NULL) {
+    debugprintf(0, "usmPrepareKeyUpdate: Could not find user in usmTables.");
+    status =  SNMPv3_USM_UNKNOWN_SECURITY_NAME;
+    return NULL;
+  }
+
+  /* set old and new key */
+  unsigned char key[SNMPv3_USM_MAX_KEY_LEN];
+  unsigned int  key_len = SNMPv3_USM_MAX_KEY_LEN;
+  OctetStr      newKey;
+  OctetStr      oldKey;
+
+  switch (type) {
+    case AUTHKEY:
+    case OWNAUTHKEY: {
+      status = auth_priv->password_to_key_auth(
+                                         user->authProtocol,
+                                         newPassword.data(), newPassword.len(),
+                                         engineID.data(), engineID.len(),
+                                         key, &key_len);
+      oldKey = OctetStr(user->authKey, user->authKeyLength);
+      break;
+    }
+    case PRIVKEY:
+    case OWNPRIVKEY: {
+      status = auth_priv->password_to_key_priv(
+                                         user->authProtocol,
+                                         user->privProtocol,
+                                         newPassword.data(), newPassword.len(),
+                                         engineID.data(), engineID.len(),
+                                         key, &key_len);
+      oldKey = OctetStr(user->privKey, user->privKeyLength);
+      break;
+    }
+    default: {
+      debugprintf(0, "usmPrepareKeyUpdate: wrong type specified.");
+      status = SNMPv3_USM_ERROR;
+      free_user(user);
+      return NULL;
+    }
+  }
+
+  if (status != SNMPv3_USM_OK)
+  {
+    debugprintf(0, "usmPrepareKeyUpdate: password_to_key failed (code %i).",
+                status);
+    free_user(user);
+    return NULL;
+  }
+
+  newKey = OctetStr(key, key_len);
+
+  /* get value to set and random value */
+  OctetStr newValue;
+  OctetStr random_value;
+
+  auth_priv->get_keychange_value(user->authProtocol,
+                                 oldKey, newKey, newValue);
+
+  char tmp_rand;
+  for (int i = 0; i<30; i++) {
+    tmp_rand = rand();
+    random_value += tmp_rand;
+  }
+
+  // Oid in usmUserTable
+  Oid userOid = Oid(oidUsmUserEntry);
+  Oid publicOid  = Oid(oidUsmUserEntry);
+
+  publicOid += "11";
+
+  switch (type) {
+    case AUTHKEY: {
+      userOid += "6";
+      break;
+    }
+    case OWNAUTHKEY: {
+      userOid += "7";
+      break;
+    }
+    case PRIVKEY: {
+       userOid += "9";
+       break;
+    }
+    case OWNPRIVKEY: {
+      userOid += "10";
+      break;
+    }
+    default: {
+      debugprintf(0, "KeyChange error: wrong type:");
+      status = SNMPv3_USM_ERROR;
+      free_user(user);
+      return NULL;
+    }
+  }
+
+  userOid += engineID.len();
+  publicOid += engineID.len();
+
+  for (unsigned int j=0; j<engineID.len(); j++) {
+    userOid += (engineID)[j];
+    publicOid += (engineID)[j];
+  }
+
+  OctetStr os = securityName;
+  userOid += os.len();
+  publicOid += os.len();
+
+  for (unsigned int k=0; k<os.len(); k++) {
+    userOid += os[k];
+    publicOid += os[k];
+  }
+
+  Vb vb;
+  vb.set_oid(userOid);
+  vb.set_value(newValue);
+  pdu += vb;
+
+  vb.set_oid(publicOid);
+  vb.set_value(random_value);
+  pdu += vb;
+
+  struct UsmKeyUpdate *uku = new struct UsmKeyUpdate;
+  uku->engineID = engineID;
+  uku->securityName = securityName;
+  uku->newPassword = newPassword;
+  uku->newKey = newKey;
+  uku->type = type;
+
+  free_user(user);
+  status = SNMPv3_USM_OK;
+  return uku;
+}
+
+void USM::key_update_abort(struct UsmKeyUpdate *uku)
+{
+  delete uku;
+}
+
+int USM::key_update_commit(struct UsmKeyUpdate *uku, int update_type)
+{
+  if (!uku) return SNMPv3_USM_ERROR;
+
+  int result;
+  OctetStr userName;
+
+  switch (update_type)
+  {
+    case USM_KeyUpdate: {
+      result = update_key(uku->securityName.data(), uku->securityName.len(),
+                         uku->engineID.data(), uku->engineID.len(),
+                         uku->newKey.data(), uku->newKey.len(),
+                         uku->type);
+      delete uku;
+      return result;
+    }
+    case USM_PasswordKeyUpdate: {
+      result = update_key(uku->securityName.data(), uku->securityName.len(),
+                         uku->engineID.data(), uku->engineID.len(),
+                         uku->newKey.data(), uku->newKey.len(),
+                         uku->type);
+      struct UsmUserNameTableEntry *entry;
+      entry = usm_user_name_table->get_cloned_entry(uku->securityName);
+      if (!entry || (result != SNMPv3_USM_OK)) {
+        delete uku;
+        if (entry)
+          usm_user_name_table->delete_cloned_entry(entry);
+        return SNMPv3_USM_ERROR;
+      }
+
+      result = SNMPv3_USM_ERROR;
+
+      switch (uku->type) {
+        case OWNAUTHKEY:
+        case AUTHKEY: {
+          OctetStr privPass(entry->privPassword, entry->privPasswordLength);
+          result = add_usm_user(uku->securityName, entry->usmUserName,
+                               entry->usmUserAuthProtocol,
+                               entry->usmUserPrivProtocol,
+                               uku->newPassword, privPass);
+         break;
+        }
+        case OWNPRIVKEY:
+        case PRIVKEY: {
+          OctetStr authPass(entry->privPassword, entry->privPasswordLength);
+          result = add_usm_user(uku->securityName, entry->usmUserName,
+                               entry->usmUserAuthProtocol,
+                               entry->usmUserPrivProtocol,
+                               authPass, uku->newPassword);
+         break;
+        }
+      }
+      delete uku;
+      usm_user_name_table->delete_cloned_entry(entry);
+      return result;
+    }
+    case USM_PasswordAllKeyUpdate: {
+      struct UsmUserNameTableEntry *entry;
+      entry = usm_user_name_table->get_cloned_entry(uku->securityName);
+      if (!entry) {
+        delete uku;
+        return SNMPv3_USM_ERROR;
+      }
+
+      result = SNMPv3_USM_ERROR;
+
+      switch (uku->type) {
+        case OWNAUTHKEY:
+        case AUTHKEY: {
+          OctetStr privPass = OctetStr(entry->privPassword,
+                                       entry->privPasswordLength);
+          delete_usm_user(uku->securityName);
+          result = add_usm_user(uku->securityName, entry->usmUserName,
+                               entry->usmUserAuthProtocol,
+                               entry->usmUserPrivProtocol,
+                               uku->newPassword, privPass);
+         break;
+        }
+        case OWNPRIVKEY:
+        case PRIVKEY: {
+          OctetStr authPass = OctetStr(entry->authPassword,
+                                       entry->authPasswordLength);
+          delete_usm_user(uku->securityName);
+          result = add_usm_user(uku->securityName, entry->usmUserName,
+                               entry->usmUserAuthProtocol,
+                               entry->usmUserPrivProtocol,
+                               authPass, uku->newPassword);
+         break;
+        }
+      }
+      delete uku;
+      usm_user_name_table->delete_cloned_entry(entry);
+      return result;
+    }
+  }
+  delete uku;
+  return SNMPv3_USM_ERROR;
+}
+
+int USM::generate_msg(
+             unsigned char *globalData,       // message header, admin data
+             int globalDataLength,
+             int maxMessageSize,              // of the sending SNMP entity
+             const OctetStr &securityEngineID,// authoritative SNMP entity
+             const OctetStr &securityName,    // on behalf of this principal
+             int  securityLevel,              // Level of Security requested
+             unsigned char  *scopedPDU,       // message (plaintext) payload
+             int scopedPDULength,
+             struct SecurityStateReference *securityStateReference,
+             unsigned char *wholeMsg,         // OUT complete generated message
+             int *wholeMsgLength)             // OUT length of generated message
+{
+  Buffer<unsigned char> buffer(MAX_SNMP_PACKET);
+  Buffer<unsigned char> buffer2(MAX_SNMP_PACKET);
+  unsigned char *bufPtr = buffer.get_ptr();
+  unsigned char *buf2Ptr = buffer2.get_ptr();
+
+  if (!bufPtr || !buf2Ptr)
+    return SNMPv3_USM_ERROR;
+
+  unsigned char *wholeMsgPtr;
+  int startAuthPar = 0;
+  struct UsmUser *user = NULL;
+  struct UsmSecurityParameters usmSecurityParams;
+
+  int bufLength = 0;
+  unsigned int buf2Length = 0;
+  int totalLength = 0;             // Bytes encoded
+  int restLength = maxMessageSize; // max Bytes left in packet-buffer
+  int rc;
+  int responseMsg = 0;
+
+  if (securityStateReference) {
+    // this is a response message
+    responseMsg = 1;
+    user = new UsmUser;
+    if (!user)
+      return SNMPv3_USM_ERROR;
+    if (securityStateReference->securityEngineID) {
+      user->engineIDLength = securityStateReference->securityEngineIDLength;
+      user->engineID       = securityStateReference->securityEngineID;
+    } else {
+      user->engineIDLength = securityEngineID.len();
+      user->engineID       = v3strcpy(securityEngineID.data(),
+                                     securityEngineID.len());
+    }
+
+    user->usmUserName = new unsigned char[MAXLEN_USMUSERNAME + 1];
+    if (securityStateReference->securityName)
+    {
+      user->securityName       = securityStateReference->securityName;
+      user->securityNameLength = securityStateReference->securityNameLength;
+      memcpy(user->usmUserName, securityStateReference->msgUserName,
+            securityStateReference->msgUserNameLength);
+      user->usmUserNameLength  = securityStateReference->msgUserNameLength;
+    }
+    else
+    {
+      user->securityNameLength = securityName.len();
+      user->securityName = v3strcpy(securityName.data(), securityName.len());
+      if (securityStateReference->msgUserNameLength)
+      {
+        securityStateReference->msgUserName[0] = 0;
+        securityStateReference->msgUserNameLength = 0;
+      }
+      user->usmUserNameLength = MAXLEN_USMUSERNAME;
+      get_user_name(user->usmUserName, &user->usmUserNameLength,
+                   securityName.data(), securityName.len());
+      if ((user->usmUserNameLength == 0) &&
+          (securityName.len() <= MAXLEN_USMUSERNAME)) {
+        memcpy(user->usmUserName, securityName.data(), securityName.len());
+       user->usmUserName[securityName.len()] = 0;
+        user->usmUserNameLength = securityName.len();
+      }
+    }
+    user->authProtocol       = securityStateReference->authProtocol;
+    user->authKey            = securityStateReference->authKey;
+    user->authKeyLength      = securityStateReference->authKeyLength;
+    user->privProtocol       = securityStateReference->privProtocol;
+    user->privKeyLength      = securityStateReference->privKeyLength;
+    user->privKey            = securityStateReference->privKey;
+
+    delete securityStateReference;
+    securityStateReference = NULL;
+  }
+  else
+  {
+    if (securityEngineID.len() == 0)
+    {
+      // discovery
+      user = new UsmUser;
+      if (!user)
+       return SNMPv3_USM_ERROR;
+      memset(user, 0, sizeof(UsmUser));
+    }
+    else
+    {
+      // search for user in usmUserTable
+      user = get_user(securityEngineID, securityName);
+
+      if (!user) {
+       debugprintf(0, "USM: User unknown!");
+       return SNMPv3_USM_UNKNOWN_SECURITY_NAME;
+      }
+    }
+  }
+
+  if (securityEngineID.len() > MAXLENGTH_ENGINEID)
+  {
+    debugprintf(0, "engine_id too long %i > %i",
+               securityEngineID.len(), MAXLENGTH_ENGINEID);
+    free_user(user);
+    return SNMPv3_USM_ERROR;
+  }
+
+  if (user->usmUserNameLength > MAXLEN_USMUSERNAME)
+  {
+    debugprintf(0, "user name too long %i > %i",
+               user->usmUserNameLength, MAXLEN_USMUSERNAME);
+    free_user(user);
+    return SNMPv3_USM_ERROR;
+  }
+
+  usmSecurityParams.msgAuthoritativeEngineIDLength = securityEngineID.len();
+  usmSecurityParams.msgUserNameLength = user->usmUserNameLength;
+  memcpy(usmSecurityParams.msgUserName,
+         user->usmUserName, user->usmUserNameLength);
+  memcpy(usmSecurityParams.msgAuthoritativeEngineID,
+         securityEngineID.data(), securityEngineID.len());
+
+  usmSecurityParams.msgPrivacyParametersLength = 0;
+  usmSecurityParams.msgPrivacyParameters = NULL;
+
+  usmSecurityParams.msgAuthenticationParametersLength = 0;
+  usmSecurityParams.msgAuthenticationParameters = NULL;
+
+  if (securityLevel >= SNMP_SECURITY_LEVEL_AUTH_NOPRIV)
+  {
+    // get engineBoots, engineTime
+    rc = usm_time_table->get_time(
+                           securityEngineID,
+                           usmSecurityParams.msgAuthoritativeEngineBoots,
+                           usmSecurityParams.msgAuthoritativeEngineTime);
+    if (rc == SNMPv3_USM_UNKNOWN_ENGINEID) {
+      usm_time_table->add_entry(securityEngineID,
+                                usmSecurityParams.msgAuthoritativeEngineBoots,
+                                usmSecurityParams.msgAuthoritativeEngineTime);
+    }
+    if (rc == SNMPv3_USM_ERROR) {
+      debugprintf(0, "usm: usmGetTime error.");
+      free_user(user);
+      return SNMPv3_USM_ERROR;
+    }
+  }
+
+  if (securityLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
+  {
+    usmSecurityParams.msgPrivacyParametersLength
+             = auth_priv->get_priv_params_len(user->privProtocol);
+    usmSecurityParams.msgPrivacyParameters
+             = new unsigned char[usmSecurityParams.msgPrivacyParametersLength];
+
+    // encrypt Message
+    int enc_result = auth_priv->encrypt_msg(
+                               user->privProtocol,
+                              user->privKey, user->privKeyLength,
+                               scopedPDU, scopedPDULength,
+                               buf2Ptr, &buf2Length,
+                               usmSecurityParams.msgPrivacyParameters,
+                               &usmSecurityParams.msgPrivacyParametersLength,
+                               usmSecurityParams.msgAuthoritativeEngineBoots,
+                              usmSecurityParams.msgAuthoritativeEngineTime);
+    if (enc_result != SNMPv3_USM_OK)
+    {
+      int return_value;
+
+      if (user->privProtocol == SNMP_PRIVPROTOCOL_NONE)
+      {
+        debugprintf(0, "usm: Privacy requested, but no UserPrivProtocol");
+        return_value = SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
+      }
+      else
+      {
+        return_value = SNMPv3_USM_ENCRYPTION_ERROR;
+      }
+
+      debugprintf(0, "usm: Encryption error (result %i).", enc_result);
+
+      delete_sec_parameters(&usmSecurityParams);
+      free_user(user);
+      return return_value;
+    }
+
+    bufPtr = asn_build_string(bufPtr, &restLength, ASN_UNI_PRIM | ASN_OCTET_STR,
+                              buf2Ptr, buf2Length);
+    if (!bufPtr) {
+      debugprintf(0, "usm: Encoding Error");
+      free_user(user);
+      return SNMPv3_USM_ERROR;
+    }
+    bufLength = SAFE_INT_CAST(bufPtr - buffer.get_ptr());
+    totalLength =  bufLength;
+    bufPtr = buffer.get_ptr();
+    memcpy(buf2Ptr, bufPtr, bufLength);
+    buf2Length = bufLength;
+
+  } else { // (securityLevel != SNMP_SECURITY_LEVEL_AUTH_PRIV)
+    buf2Ptr = scopedPDU;
+    buf2Length = scopedPDULength;
+    totalLength = scopedPDULength;
+  }
+  if (!bufPtr) {
+    debugprintf(0, "usm: Encoding Error");
+    free_user(user);
+    return SNMPv3_USM_ERROR;
+  }
+
+  totalLength += SAFE_INT_CAST(bufPtr - buffer.get_ptr());
+  memcpy(bufPtr, buf2Ptr, buf2Length);
+  bufLength = totalLength;
+
+  debugprintf(21, "buf after privacy:");
+  debughexprintf(21, buffer.get_ptr(), bufLength);
+
+  wholeMsgPtr = wholeMsg;
+
+  if (securityLevel >= SNMP_SECURITY_LEVEL_AUTH_NOPRIV)
+  {
+    /* Build message with authentication */
+    usmSecurityParams.msgAuthenticationParametersLength
+                         = auth_priv->get_auth_params_len(user->authProtocol);
+    usmSecurityParams.msgAuthenticationParameters
+      = new unsigned char[usmSecurityParams.msgAuthenticationParametersLength];
+    memset((char*)(usmSecurityParams.msgAuthenticationParameters), 0,
+           usmSecurityParams.msgAuthenticationParametersLength);
+
+    wholeMsgPtr = build_whole_msg(wholeMsgPtr, &maxMessageSize,
+                                 globalData, globalDataLength,
+                                 &startAuthPar, // for MD5, SHA,...
+                                 usmSecurityParams,
+                                 buffer.get_ptr(),
+                                 bufLength);   // the msgData
+    if (wholeMsgPtr == NULL)
+    {
+      debugprintf(0, "usm: could not generate wholeMsg");
+      delete_sec_parameters(&usmSecurityParams);
+      free_user(user);
+      return SNMPv3_USM_ERROR;
+    }
+    *wholeMsgLength = SAFE_INT_CAST(wholeMsgPtr - wholeMsg);
+
+    rc = auth_priv->auth_out_msg(user->authProtocol,
+                                 user->authKey,
+                                 wholeMsg, *wholeMsgLength,
+                                 wholeMsg + startAuthPar);
+
+    if (rc!=SNMPv3_USM_OK)
+    {
+      debugprintf(0, "usm: Authentication error for outgoing message."
+                  " error code (%i).", rc);
+      delete_sec_parameters(&usmSecurityParams);
+      free_user(user);
+      return rc;
+    }
+  }
+  else
+  {
+    //build Message without authentication
+
+    // Set engineBoots and enigneTime to zero!
+    usmSecurityParams.msgAuthoritativeEngineBoots = 0;
+    usmSecurityParams.msgAuthoritativeEngineTime  = 0;
+
+    usmSecurityParams.msgAuthenticationParametersLength = 0;
+    usmSecurityParams.msgAuthenticationParameters = 0;
+
+    wholeMsgPtr = build_whole_msg(wholeMsgPtr, &maxMessageSize,
+                                 globalData, globalDataLength,
+                                 &startAuthPar, // dummy ( no auth)
+                                 usmSecurityParams,
+                                 buffer.get_ptr(),
+                                 bufLength);   // the msgData
+    if (wholeMsgPtr == NULL) {
+      debugprintf(0, "usm: could not generate wholeMsg");
+      delete_sec_parameters(&usmSecurityParams);
+      free_user(user);
+      return SNMPv3_USM_ERROR;
+    }
+    *wholeMsgLength = SAFE_INT_CAST(wholeMsgPtr - wholeMsg);
+  }
+
+  debugprintf(21, "Complete Whole Msg:");
+  debughexprintf(21, wholeMsg, *wholeMsgLength);
+
+  delete_sec_parameters(&usmSecurityParams);
+  free_user(user);
+  return SNMPv3_USM_OK;
+}
+
+int USM::process_msg(
+            int maxMessageSize,               // of the sending SNMP entity
+            unsigned char *securityParameters,// for the received message
+            int securityParametersLength,
+            int securityParametersPosition,
+            long int securityLevel,           // Level of Security
+            unsigned char *wholeMsg,          // as received on the wire
+            int wholeMsgLength,               // length as received on the wire
+            unsigned char *msgData,
+            int msgDataLength,
+           OctetStr &security_engine_id,     // authoritative SNMP entity
+           OctetStr &security_name,          //identification of the principal
+            unsigned char *scopedPDU,         // message (plaintext) payload
+            int *scopedPDULength,
+            long *maxSizeResponseScopedPDU, // maximum size of the Response PDU
+            struct SecurityStateReference *securityStateReference,
+                                            // reference to security state
+                                            // information, needed for response
+            const UdpAddress &fromAddress)
+{
+  unsigned char* sp = securityParameters;
+  int spLength = securityParametersLength;
+  unsigned char type;
+  long int engineBoots, engineTime;
+  unsigned char authParam[SNMPv3_AP_MAXLENGTH_AUTHPARAM];
+  unsigned char privParam[SNMPv3_AP_MAXLENGTH_PRIVPARAM];
+  int authParamLength = SNMPv3_AP_MAXLENGTH_AUTHPARAM;
+  int privParamLength = SNMPv3_AP_MAXLENGTH_PRIVPARAM;
+  Buffer<unsigned char> encryptedScopedPDU(MAX_SNMP_PACKET);
+  int encryptedScopedPDULength = msgDataLength;
+  struct UsmUser *user = NULL;
+  int rc;
+  int notInTime = 0;
+
+  // check securityParameters
+  sp = asn_parse_header( sp, &spLength, &type);
+  if (sp == NULL){
+    debugprintf(0, "bad header of securityParameters");
+    return SNMPv3_USM_PARSE_ERROR;
+  }
+  debugprintf(3, "Parsed securityParametersLength = 0x%x", spLength);
+
+  if (type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)){
+    debugprintf(0, "wrong type in header of securityParameters");
+    return SNMPv3_USM_PARSE_ERROR;
+  }
+
+  // extract security parameters
+  {
+    int len = MAXLENGTH_ENGINEID + 1;
+    unsigned char data[MAXLENGTH_ENGINEID + 1];
+    sp = asn_parse_string( sp, &spLength, &type, data, &len);
+
+    debugprintf(3, "Parsed securityEngineID, length = 0x%x", len);
+    if (sp==NULL) {
+      debugprintf(0, "bad parse of securityEngineID");
+      return SNMPv3_USM_PARSE_ERROR;
+    }
+    security_engine_id.set_data(data, len);
+  }
+
+  sp = asn_parse_int(sp, &spLength, &type, &engineBoots);
+  if ((sp == NULL) || (engineBoots < 0)) {
+    debugprintf(0, "bad parse of engineBoots");
+    return SNMPv3_USM_PARSE_ERROR;
+  }
+
+  sp = asn_parse_int(sp, &spLength, &type, &engineTime);
+  if ((sp == NULL) || (engineTime < 0)) {
+    debugprintf(0, "bad parse of engineTime");
+    return SNMPv3_USM_PARSE_ERROR;
+  }
+
+  debugprintf(3, "Parsed engineBoots(0x%lx), engineTime(0x%lx)",
+             engineTime, engineBoots);
+
+  unsigned char usmUserName[MAXLEN_USMUSERNAME + 1];
+  int usmUserNameLength = MAXLEN_USMUSERNAME;
+
+  sp = asn_parse_string( sp, &spLength, &type,
+                         (unsigned char*)&usmUserName, &usmUserNameLength);
+
+  if (sp==NULL) {
+    debugprintf(0, "bad parse of usmUserName");
+    return SNMPv3_USM_PARSE_ERROR;
+  }
+
+  sp = asn_parse_string( sp, &spLength, &type,
+                         (unsigned char*)&authParam, &authParamLength);
+
+  if (sp==NULL) {
+    debugprintf(0, "bad parse of msgAuthenticationParameters");
+    return SNMPv3_USM_PARSE_ERROR;
+  }
+  int authParametersPosition = securityParametersPosition +
+                               SAFE_INT_CAST(sp - securityParameters) - authParamLength;
+
+  sp = asn_parse_string( sp, &spLength, &type,
+                         (unsigned char*)&privParam, &privParamLength);
+
+  if (sp==NULL) {
+    debugprintf(0, "bad parse of msgPrivacyParameters");
+    return SNMPv3_USM_PARSE_ERROR;
+  }
+  if (spLength !=0) {
+    debugprintf(0, "Error Parsing msgPrivacyParameters");
+    return SNMPv3_USM_PARSE_ERROR;
+  }
+  debugprintf(5, "Parsed usmUserName length(0x%x)"
+             " msgAuthenticationParameters length(0x%x)"
+             " msgPrivacyParameters length(0x%x)",
+             usmUserNameLength, authParamLength, privParamLength);
+
+  // prepare securityStateReference
+  if (usmUserNameLength > MAXLEN_USMUSERNAME)
+  {
+    debugprintf(0, "user name too long: %i > %i.",
+               usmUserNameLength, MAXLEN_USMUSERNAME);
+    return SNMPv3_USM_PARSE_ERROR;
+  }
+
+  securityStateReference->msgUserNameLength = usmUserNameLength;
+  memcpy(securityStateReference->msgUserName, usmUserName,
+         securityStateReference->msgUserNameLength);
+
+  securityStateReference->securityEngineIDLength = security_engine_id.len();
+  securityStateReference->securityEngineID =
+    new unsigned char [securityStateReference->securityEngineIDLength];
+  memcpy(securityStateReference->securityEngineID, security_engine_id.data(),
+         securityStateReference->securityEngineIDLength);
+
+  securityStateReference->securityLevel = securityLevel;
+
+  securityStateReference->securityNameLength = 0;
+  securityStateReference->securityName = NULL;
+  securityStateReference->authProtocol = 1;
+  securityStateReference->privProtocol = 1;
+  securityStateReference->authKey = NULL;
+  securityStateReference->privKey = NULL;
+
+  // in case we return with error,
+  // perhaps v3MP can decode it (requestID!!!)
+  memcpy(scopedPDU, msgData, msgDataLength);
+  *scopedPDULength = msgDataLength;
+
+  if ((security_engine_id.len() == 0) ||
+      (usm_time_table->check_engine_id(security_engine_id) != SNMPv3_USM_OK ))
+  {
+    inc_stats_unknown_engine_ids();
+
+    // *+* REPORT *+*
+    securityStateReference->securityLevel = SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+    security_name.set_data(usmUserName, usmUserNameLength);
+
+    debugprintf(2, "USM: EngineID unknown");
+    return SNMPv3_USM_UNKNOWN_ENGINEID;
+  }
+
+  // get securityName:
+  if ((usmUserNameLength) ||
+      (securityLevel != SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV))
+  {
+    rc = get_security_name(usmUserName, usmUserNameLength, security_name);
+    if (rc != SNMPv3_USM_OK) {
+      inc_stats_unknown_user_names();
+      security_name.set_data(usmUserName, usmUserNameLength);
+
+      debugprintf(2,"usmProcessMsg: unknown user (%s)",
+                 security_name.get_printable());
+      return SNMPv3_USM_UNKNOWN_SECURITY_NAME;
+    }
+  }
+  else
+  {
+    debugprintf(2, "Accepting zero length user/security name.");
+    security_name = "";
+  }
+
+  securityStateReference->securityNameLength = security_name.len();
+  securityStateReference->securityName =
+    new unsigned char [securityStateReference->securityNameLength];
+  memcpy(securityStateReference->securityName, security_name.data(),
+         securityStateReference->securityNameLength);
+
+  // get user from LCD (usmUserTable)
+  if (usmUserNameLength)
+  {
+    user = get_user(security_engine_id, security_name);
+
+    if (!user) {
+      inc_stats_unknown_user_names();
+      debugprintf(0, "usmProcessMsg: unknown user");
+      return SNMPv3_USM_UNKNOWN_SECURITY_NAME;
+    }
+  }
+  else
+  {
+    user = new UsmUser;
+    if (!user)
+    {
+      debugprintf(0, "Memory error");
+      return SNMPv3_USM_ERROR;
+    }
+    memset(user, 0, sizeof(UsmUser));
+  }
+
+  if (((securityLevel > SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV) &&
+       (user->authProtocol == SNMP_AUTHPROTOCOL_NONE)) ||
+      ((securityLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV) &&
+       (user->privProtocol == SNMP_PRIVPROTOCOL_NONE))) {
+    inc_stats_unsupported_sec_levels();
+    debugprintf(0, "usmProcessMsg: unsupported Securitylevel");
+    free_user(user);
+    return SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL;
+  }
+
+  if (securityLevel > SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV)
+  {
+    rc = auth_priv->auth_inc_msg(user->authProtocol,
+                                 user->authKey,
+                                 wholeMsg, wholeMsgLength,
+                                 wholeMsg + authParametersPosition,
+                                authParamLength);
+    if (rc != SNMPv3_USM_OK)
+    {
+      switch (rc)
+      {
+        case SNMPv3_USM_AUTHENTICATION_FAILURE:
+          debugprintf(0, "usmProcessMsg: Authentication failure.");
+         inc_stats_wrong_digests();
+          /* set securityLevel for Report */
+          break;
+        case SNMPv3_USM_UNSUPPORTED_AUTHPROTOCOL:
+          debugprintf(0, "usmProcessMsg: unknown AuthProtocol");
+         inc_stats_unsupported_sec_levels();
+        default:
+          debugprintf(0, "usmProcessMsg: error authenticating msg."
+                      " Error code (%i).", rc);
+          // todo: is it ok to increment this counter?
+         inc_stats_unsupported_sec_levels();
+          break;
+      }
+      securityStateReference->securityLevel= SNMP_SECURITY_LEVEL_NOAUTH_NOPRIV;
+      free_user(user);
+      return rc;
+    }
+
+    rc = usm_time_table->check_time(security_engine_id,
+                                   engineBoots, engineTime);
+    if (rc == SNMPv3_USM_NOT_IN_TIME_WINDOW)
+    {
+      inc_stats_not_in_time_windows();
+      debugprintf(2, "***Message not in TimeWindow!");
+      notInTime = 1;
+    }
+    if (rc == SNMPv3_USM_UNKNOWN_ENGINEID)
+    {
+      debugprintf(0, "***EngineID not in timeTable!");
+      free_user(user);
+      return rc;
+    }
+  }
+
+  *scopedPDULength = MAX_SNMP_PACKET;
+
+  // decrypt ScopedPDU if message is in time window
+  if ((securityLevel == SNMP_SECURITY_LEVEL_AUTH_PRIV)
+      && (!notInTime)) {
+    msgData = asn_parse_string( msgData, &msgDataLength, &type,
+                                encryptedScopedPDU.get_ptr(),
+                               &encryptedScopedPDULength);
+    if (msgData == NULL){
+      debugprintf(0, "usmProcessMsg: bad header of encryptedPDU");
+      free_user(user);
+      return SNMPv3_USM_PARSE_ERROR;
+    }
+
+    // decrypt Message
+    unsigned int tmp_length = *scopedPDULength;
+    int dec_result = auth_priv->decrypt_msg(
+                                  user->privProtocol,
+                                  user->privKey, user->privKeyLength,
+                                  encryptedScopedPDU.get_ptr(),
+                                 encryptedScopedPDULength,
+                                  scopedPDU, &tmp_length,
+                                  (unsigned char*)&privParam, privParamLength,
+                                 engineBoots, engineTime);
+    *scopedPDULength = tmp_length;
+    if (dec_result != SNMPv3_USM_OK)
+    {
+      int return_value;
+      if (dec_result == SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL)
+      {
+        debugprintf(0, "usmProcessMsg: unknown PrivacyProtocol");
+       inc_stats_unsupported_sec_levels();
+        return_value = SNMPv3_USM_UNSUPPORTED_PRIVPROTOCOL;
+      }
+      else // catch all
+      {
+        debugprintf(0, "usmProcessMsg: Decryption error (result %i).",
+                   dec_result);
+       inc_stats_decryption_errors();
+        return_value = SNMPv3_USM_DECRYPTION_ERROR;
+      }
+      free_user(user);
+      return return_value;
+    }
+
+    debugprintf(21, "scopedPDU(1):");
+    debughexprintf(21, scopedPDU, *scopedPDULength);
+
+    // test for decryption error
+    // first byte 0x30
+    if (scopedPDU[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCE)) {
+      debugprintf(0, "Decryption error detected");
+      inc_stats_decryption_errors();
+      free_user(user);
+      return SNMPv3_USM_DECRYPTION_ERROR;
+    }
+  }
+  else {
+    // message was not encrypted
+    memcpy(scopedPDU, msgData, msgDataLength);
+    *scopedPDULength = msgDataLength;
+  }
+
+  *maxSizeResponseScopedPDU = maxMessageSize - (wholeMsgLength - *scopedPDULength);
+
+  security_name.set_data(user->securityName, user->securityNameLength);
+
+  securityStateReference->authProtocol = user->authProtocol;
+  securityStateReference->privProtocol = user->privProtocol;
+
+  securityStateReference->authKeyLength = user->authKeyLength;
+  securityStateReference->authKey = user->authKey;
+
+  securityStateReference->privKeyLength = user->privKeyLength;
+  securityStateReference->privKey = user->privKey;
+
+  user->authKey = 0;
+  user->privKey = 0;
+
+  free_user(user);
+
+  if (notInTime)
+    return SNMPv3_USM_NOT_IN_TIME_WINDOW;
+
+  return SNMPv3_USM_OK;
+}
+
+unsigned char *USM::build_sec_params(unsigned char *outBuf, int *maxLength,
+                                    struct UsmSecurityParameters sp,
+                                    int *position)
+{
+  Buffer<unsigned char> buf(MAX_SNMP_PACKET);
+  unsigned char *bufPtr = buf.get_ptr();
+  unsigned char *outBufPtr = outBuf;
+  int length = *maxLength;
+  int totalLength;
+
+  debugprintf(5, "Coding octstr sp.msgAuthoritativeEngineID, length = 0x%lx",
+             sp.msgAuthoritativeEngineIDLength);
+  bufPtr = asn_build_string(bufPtr, &length,
+                            ASN_UNI_PRIM | ASN_OCTET_STR,
+                            sp.msgAuthoritativeEngineID,
+                            sp.msgAuthoritativeEngineIDLength);
+  if (bufPtr == NULL) {
+    debugprintf(0, "usmBuildSecurityParameters error coding engineid");
+    return NULL;
+  }
+
+  debugprintf(5, "Coding int sp.msgAuthoritativeEngineBoots = 0x%lx",
+             sp.msgAuthoritativeEngineBoots);
+  bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
+                         &sp.msgAuthoritativeEngineBoots);
+
+  if (bufPtr == NULL) {
+    debugprintf(0, "usmBuildSecurityParameters error coding engineboots");
+    return NULL;
+  }
+
+  debugprintf(5, "Coding int sp.msgAuthoritativeEngineTime = 0x%lx",
+             sp.msgAuthoritativeEngineTime);
+  bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
+                         &sp.msgAuthoritativeEngineTime);
+
+  if (bufPtr == NULL) {
+    debugprintf(0, "usmBuildSecurityParameters error coding enginetime");
+    return NULL;
+  }
+
+  debugprintf(5, "Coding octstr sp.msgUserName, length = 0x%lx",
+             sp.msgUserNameLength);
+  bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
+                            sp.msgUserName, sp.msgUserNameLength);
+  if (bufPtr == NULL) {
+    debugprintf(0, "usmBuildSecurityParameters error coding msgusername");
+    return NULL;
+  }
+
+  *position = SAFE_INT_CAST(bufPtr - buf.get_ptr()) + 2;
+
+  debugprintf(5, "Coding octstr sp.msgAu..Para.. , length = 0x%lx",
+             sp.msgAuthenticationParametersLength);
+  bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
+                            sp.msgAuthenticationParameters,
+                            sp.msgAuthenticationParametersLength);
+
+  if (bufPtr == NULL) {
+    debugprintf(0, "usmBuildSecurityParameters error coding authparams");
+    return NULL;
+  }
+
+  debugprintf(5, "Coding octstr sp.msgPr..Para.. , length = 0x%lx",
+             sp.msgPrivacyParametersLength);
+  bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
+                            sp.msgPrivacyParameters,
+                            sp.msgPrivacyParametersLength);
+
+  if (bufPtr == NULL) {
+    debugprintf(0, "usmBuildSecurityParameters error coding privparams");
+    return NULL;
+  }
+
+  totalLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());
+
+  debugprintf(5, "Coding sequence (securityPar), length = 0x%x", totalLength);
+  outBufPtr = asn_build_sequence(outBufPtr, maxLength, ASN_SEQ_CON,
+                                 totalLength);
+
+  if (outBufPtr == NULL) {
+    debugprintf(0, "usm: usmBuildSecurityParameters error coding secparams");
+    return NULL;
+  }
+
+  if (*maxLength < totalLength) {
+    debugprintf(0, "usm: usmBuildSecurityParameters error (length mismatch)");
+    return NULL;
+  }
+  *position += SAFE_INT_CAST(outBufPtr - outBuf);
+  memcpy(outBufPtr, buf.get_ptr(), totalLength);
+  outBufPtr += totalLength;
+  *maxLength -= totalLength;
+
+  debugprintf(21, "bufSecurityData:");
+  debughexprintf(21, outBuf, SAFE_INT_CAST(outBufPtr - outBuf));
+
+  return outBufPtr;
+}
+
+unsigned char *USM::build_whole_msg(
+                         unsigned char *outBuf, int *maxLength,
+                        unsigned char *globalData, long int globalDataLength,
+                        int *positionAuthPar,
+                        struct UsmSecurityParameters  securityParameters,
+                        unsigned char *msgData, long int msgDataLength)
+{
+  Buffer<unsigned char> buf(MAX_SNMP_PACKET);
+  unsigned char *bufPtr = buf.get_ptr();
+  Buffer<unsigned char> secPar(MAX_SNMP_PACKET);
+  unsigned char *secParPtr = secPar.get_ptr();
+  unsigned char *outBufPtr = outBuf;
+  long int secParLength;
+  int length = *maxLength;
+  int totalLength;
+
+  int dummy = *maxLength;
+
+  secParPtr = build_sec_params(secParPtr, &dummy, securityParameters,
+                              positionAuthPar);
+
+  if (!secParPtr)
+    return NULL;
+  secParLength = SAFE_INT_CAST(secParPtr - secPar.get_ptr());
+
+  long int dummyVersion = 3;
+  debugprintf(3, "Coding int snmpVersion = 0x%lx",dummyVersion);
+  bufPtr = asn_build_int(bufPtr, &length, ASN_UNI_PRIM | ASN_INTEGER,
+                         &dummyVersion);
+  if (bufPtr == NULL) {
+    debugprintf(0, "usmBuildWholeMsg error");
+    return NULL;
+  }
+
+  // globalData is encoded as sequence
+  length -= globalDataLength;
+  if (length < 0) {
+    debugprintf(0, "usmBuildWholeMsg error");
+    return NULL;
+  }
+  memcpy(bufPtr, globalData, globalDataLength);
+  bufPtr += globalDataLength;
+
+  *positionAuthPar += SAFE_INT_CAST(bufPtr - buf.get_ptr()) +2;
+  if (secParLength> 0x7f)
+    *positionAuthPar += 2;
+
+  debugprintf(3, "Coding octstr securityParameter, length = 0x%lx",
+              secParLength);
+  bufPtr = asn_build_string(bufPtr, &length, ASN_UNI_PRIM | ASN_OCTET_STR,
+                            secPar.get_ptr(), secParLength);
+
+  if (bufPtr == NULL) {
+    debugprintf(0, "usmBuildWholeMsg error2");
+    return NULL;
+  }
+
+  // msgData (ScopedPduData) is encoded
+  length -=msgDataLength;
+  if (length < 0) {
+    debugprintf(10, "usmBuildWholeMsg error: msgDataLength = %i",
+                msgDataLength);
+    debugprintf(10, "maxLength = %i, encoded = %i", *maxLength,
+                SAFE_INT_CAST(bufPtr - buf.get_ptr()));
+    return NULL;
+  }
+  memcpy(bufPtr, msgData, msgDataLength);
+  bufPtr += msgDataLength;
+
+  totalLength = SAFE_INT_CAST(bufPtr - buf.get_ptr());
+
+  debugprintf(3, "Coding sequence (wholeMsg), length = 0x%x", totalLength);
+
+  outBufPtr = asn_build_sequence(outBufPtr, maxLength, ASN_SEQ_CON,
+                                 totalLength);
+
+  if (outBufPtr == NULL) {
+    debugprintf(0, "usm: usmBuildWholeMsg error");
+    return NULL;
+  }
+
+  if (*maxLength < totalLength) {
+    debugprintf(0, "usm: usmBuildWholeMsg error");
+    return NULL;
+  }
+  *positionAuthPar += SAFE_INT_CAST(outBufPtr - outBuf);
+  memcpy(outBufPtr, buf.get_ptr(), totalLength);
+  outBufPtr += totalLength;
+  *maxLength -= totalLength;
+
+  debugprintf(21,"bufWholeMsg:");
+  debughexprintf(21, outBuf, SAFE_INT_CAST(outBufPtr - outBuf));
+
+  return outBufPtr;
+}
+
+inline void USM::delete_user_ptr(struct UsmUser *user)
+{
+  if (!user) return;
+  if (user->engineID) {
+    delete [] user->engineID;
+    user->engineID = NULL;
+  }
+  if (user->usmUserName) {
+    delete [] user->usmUserName;
+    user->usmUserName = NULL;
+  }
+  if (user->securityName) {
+    delete [] user->securityName;
+    user->securityName = NULL;
+  }
+  if (user->authKey) {
+    memset(user->authKey, 0, user->authKeyLength);
+    delete [] user->authKey;
+    user->authKey = NULL;
+  }
+  if (user->privKey) {
+    memset(user->privKey, 0, user->privKeyLength);
+    delete [] user->privKey;
+    user->authKey = NULL;
+  }
+}
+
+// Save all localized users into a file.
+int USM::save_localized_users(const char *file)
+{
+  return usm_user_table->save_to_file(file, auth_priv);
+}
+
+// Load localized users from a file.
+int USM::load_localized_users(const char *file)
+{
+  return usm_user_table->load_from_file(file, auth_priv);
+}
+
+// Safe all users with their passwords into a file.
+int USM::save_users(const char *file)
+{
+  return usm_user_name_table->save_to_file(file, auth_priv);
+}
+
+// Load users with their passwords from a file.
+int USM::load_users(const char *file)
+{
+  return usm_user_name_table->load_from_file(file, auth_priv);
+}
+
+// Lock the UsmUserNameTable for access through peek_first/next_user()
+void USM::lock_user_name_table()
+{
+  usm_user_name_table->lock();
+}
+
+// Get a const pointer to the first entry of the UsmUserNameTable.
+const UsmUserNameTableEntry *USM::peek_first_user()
+{
+  return usm_user_name_table->peek_first();
+}
+
+// Get a const pointer to the next entry of the UsmUserNameTable.
+const UsmUserNameTableEntry *USM::peek_next_user(const UsmUserNameTableEntry *e)
+{
+  return usm_user_name_table->peek_next(e);
+}
+
+// Unlock the UsmUserNameTable after access through peek_first/next_user()
+void USM::unlock_user_name_table()
+{
+  usm_user_name_table->unlock();
+}
+
+// Lock the UsmUserTable for access through peek_first/next_luser()
+void USM::lock_user_table()
+{
+  usm_user_table->lock();
+}
+
+// Get a const pointer to the first entry of the UsmUserTable.
+const UsmUserTableEntry *USM::peek_first_luser()
+{
+  return usm_user_table->peek_first();
+}
+
+// Get a const pointer to the next entry of the UsmUserTable.
+const UsmUserTableEntry *USM::peek_next_luser(const UsmUserTableEntry *e)
+{
+  return usm_user_table->peek_next(e);
+}
+
+// Unlock the UsmUserTable after access through peek_first/next_luser()
+void USM::unlock_user_table()
+{
+  usm_user_table->unlock();
+}
+
+
+/* ----------------------- class USMTimeTable --------------------*/
+
+USMTimeTable::USMTimeTable(const USM *owner,
+                          const unsigned int engine_boots, int &result)
+{
+  time_t now;
+
+  table = new struct Entry_T[5];
+
+  if (!table)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMTimeTable: error constructing table.");
+    LOG_END;
+
+    result = SNMPv3_USM_ERROR;
+    return;
+  }
+
+  usm = owner;
+
+  /* the first entry always contains the local engine id and time */
+  time(&now);
+
+  table[0].time_diff     = - SAFE_LONG_CAST(now);
+  table[0].engine_boots  = engine_boots;
+  table[0].engine_id_len = min(usm->get_local_engine_id().len(),
+                              MAXLENGTH_ENGINEID);
+  memcpy(table[0].engine_id, usm->get_local_engine_id().data(),
+        table[0].engine_id_len);
+
+  entries = 1;
+  max_entries = 5;
+
+  result = SNMPv3_USM_OK;
+}
+
+USMTimeTable::~USMTimeTable()
+{
+  if (table)
+  {
+    delete [] table;
+    table = NULL;
+  }
+  entries = 0;
+  max_entries = 0;
+}
+
+int USMTimeTable::add_entry(const OctetStr &engine_id,
+                            const long int engine_boots,
+                            const long int engine_time)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  LOG_BEGIN(INFO_LOG | 11);
+  LOG("USMTimeTable: Adding entry (engine id) (boot) (time)");
+  LOG(engine_id.get_printable());
+  LOG(engine_boots);
+  LOG(engine_time);
+  LOG_END;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  if (entries == max_entries)
+  {
+    /* resize Table */
+    struct Entry_T *tmp = new struct Entry_T[4 * max_entries];
+
+    if (!tmp)
+      return SNMPv3_USM_ERROR;
+
+    memcpy(tmp, table, entries * sizeof(Entry_T));
+
+    struct Entry_T *victim = table;
+    table = tmp;
+    delete [] victim;
+
+    max_entries *= 4;
+  }
+
+  time_t now;
+  time(&now);
+
+  table[entries].engine_boots = engine_boots;
+  table[entries].latest_received_time = engine_time;
+  table[entries].time_diff = engine_time - SAFE_ULONG_CAST(now);
+  table[entries].engine_id_len = engine_id.len();
+  table[entries].engine_id_len = min(table[entries].engine_id_len,
+                                     MAXLENGTH_ENGINEID);
+  memcpy(table[entries].engine_id,
+        engine_id.data(), table[entries].engine_id_len);
+
+  entries++;
+
+  return SNMPv3_USM_OK;
+}
+
+// Delete this engine id from the table.
+int USMTimeTable::delete_entry(const OctetStr &engine_id)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  LOG_BEGIN(INFO_LOG | 12);
+  LOG("USMTimeTable: Deleting entry (engine id)");
+  LOG(engine_id.get_printable());
+  LOG_END;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i=1; i < entries; i++) /* start from 1 */
+    if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
+                            engine_id.data(), engine_id.len()))
+    {
+      if (i != entries - 1)
+       table[i] = table[entries - 1];
+
+      entries--;
+
+      return SNMPv3_USM_OK;
+    }
+
+  return SNMPv3_USM_OK;
+}
+
+unsigned long USMTimeTable::get_local_time()
+{
+  if (!table)
+    return 0;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  time_t now;
+  time(&now);
+
+  return table[0].time_diff + SAFE_ULONG_CAST(now);
+}
+
+int USMTimeTable::get_local_time(long int &engine_boots,
+                                 long int &engine_time)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  time_t now;
+  time(&now);
+
+  engine_boots = table[0].engine_boots;
+  engine_time  = table[0].time_diff + SAFE_ULONG_CAST(now);
+
+  LOG_BEGIN(DEBUG_LOG | 11);
+  LOG("USMTimeTable: returning local time (boots) (time)");
+  LOG(engine_boots);
+  LOG(engine_time);
+  LOG_END;
+
+  return SNMPv3_USM_OK;
+}
+
+int USMTimeTable::get_time(const OctetStr &engine_id,
+                           long int &engine_boots, long int &engine_time)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i=0; i < entries; i++)
+    if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
+                            engine_id.data(), engine_id.len()))
+    {
+      /* Entry found */
+      time_t now;
+      time(&now);
+
+      engine_boots = table[i].engine_boots;
+      engine_time  = table[i].time_diff + SAFE_ULONG_CAST(now);
+
+      LOG_BEGIN(INFO_LOG | 4);
+      LOG("USMTimeTable: Returning time (engine id) (boot) (time)");
+      LOG(engine_id.get_printable());
+      LOG(engine_boots);
+      LOG(engine_time);
+      LOG_END;
+
+      return SNMPv3_USM_OK;
+    }
+
+  /* no entry */
+  engine_boots = 0;
+  engine_time = 0;
+
+  LOG_BEGIN(INFO_LOG | 4);
+  LOG("USMTimeTable: No entry found for (engine id)");
+  LOG(engine_id.get_printable());
+  LOG_END;
+
+  return SNMPv3_USM_UNKNOWN_ENGINEID;
+}
+
+int USMTimeTable::check_time(const OctetStr &engine_id,
+                             const long int engine_boots,
+                             const long int engine_time)
+
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  time_t now;
+  time(&now);
+
+  /* table[0] contains the local engine_id and time */
+  if (unsignedCharCompare(table[0].engine_id, table[0].engine_id_len,
+                          engine_id.data(), engine_id.len()))
+  {
+    /* Entry found, we are authoritative */
+    if ((table[0].engine_boots == 2147483647) ||
+        (table[0].engine_boots != engine_boots) ||
+        (labs(SAFE_ULONG_CAST(now) + table[0].time_diff - engine_time) > 150))
+    {
+      LOG_BEGIN(DEBUG_LOG | 9);
+      LOG("USMTimeTable: Check time failed, authoritative (id) (boot) (time)");
+      LOG(engine_id.get_printable());
+      LOG(engine_boots);
+      LOG(engine_time);
+      LOG_END;
+
+      return SNMPv3_USM_NOT_IN_TIME_WINDOW;
+    }
+    else
+    {
+      LOG_BEGIN(DEBUG_LOG | 9);
+      LOG("USMTimeTable: Check time ok, authoritative (id)");
+      LOG(engine_id.get_printable());
+      LOG_END;
+
+      return SNMPv3_USM_OK;
+    }
+  }
+
+  for (int i=1; i < entries; i++)
+    if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
+                            engine_id.data(), engine_id.len()))
+    {
+      /* Entry found we are not authoritative */
+      if ((engine_boots < table[i].engine_boots) ||
+          ((engine_boots == table[i].engine_boots) &&
+           (table[i].time_diff + now > engine_time + 150)) ||
+          (table[i].engine_boots == 2147483647))
+      {
+       LOG_BEGIN(DEBUG_LOG | 9);
+       LOG("USMTimeTable: Check time failed, not authoritative (id)");
+       LOG(engine_id.get_printable());
+       LOG_END;
+
+        return SNMPv3_USM_NOT_IN_TIME_WINDOW;
+      }
+      else
+      {
+        if ((engine_boots > table[i].engine_boots) ||
+            ((engine_boots == table[i].engine_boots) &&
+             (engine_time > table[i].latest_received_time)))
+        {
+          /* time ok, update values */
+          table[i].engine_boots = engine_boots;
+          table[i].latest_received_time  = engine_time;
+          table[i].time_diff = engine_time - SAFE_ULONG_CAST(now);
+        }
+
+       LOG_BEGIN(DEBUG_LOG | 9);
+       LOG("USMTimeTable: Check time ok, not authoritative, updated (id)");
+       LOG(engine_id.get_printable());
+       LOG_END;
+
+        return SNMPv3_USM_OK;
+      }
+    }
+
+  LOG_BEGIN(DEBUG_LOG | 9);
+  LOG("USMTimeTable: Check time, engine id not found");
+  LOG(engine_id.get_printable());
+  LOG_END;
+
+  return SNMPv3_USM_UNKNOWN_ENGINEID;
+}
+
+
+int USMTimeTable::check_engine_id(const OctetStr &engine_id)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  {
+    // Begin reentrant code block
+    BEGIN_REENTRANT_CODE_BLOCK;
+
+    for (int i=0; i < entries; i++)
+      if (unsignedCharCompare(table[i].engine_id, table[i].engine_id_len,
+                             engine_id.data(), engine_id.len()))
+       return SNMPv3_USM_OK;
+  }
+
+  /* if in discovery mode:  accept all EngineID's (rfc2264 page 26) */
+  if (usm->is_discovery_enabled())
+    return add_entry(engine_id, 0, 0);
+
+  LOG_BEGIN(DEBUG_LOG | 9);
+  LOG("USMTimeTable: Check id, not found (id)");
+  LOG(engine_id.get_printable());
+  LOG_END;
+
+  return SNMPv3_USM_ERROR;
+}
+
+
+
+/* ------------------------- USMUserNameTable ----------------------*/
+
+USMUserNameTable::USMUserNameTable(int &result)
+{
+  /* init Table */
+  table = new struct UsmUserNameTableEntry[10];
+  if (!table)
+  {
+    result = SNMPv3_USM_ERROR;
+    return;
+  }
+  max_entries = 10;
+  entries = 0;
+  result = SNMPv3_USM_OK;
+}
+
+USMUserNameTable::~USMUserNameTable()
+{
+  if (table)
+  {
+    for (int i=0; i < entries; i++)
+    {
+      if (table[i].authPassword)
+      {
+        memset(table[i].authPassword, 0, table[i].authPasswordLength);
+        delete [] table[i].authPassword;
+      }
+
+      if (table[i].privPassword)
+      {
+        memset(table[i].privPassword, 0, table[i].privPasswordLength);
+        delete [] table[i].privPassword;
+      }
+    }
+    delete [] table;
+    table = NULL;
+  }
+  entries = 0;
+  max_entries = 0;
+}
+
+int USMUserNameTable::add_entry(const OctetStr& user_name,
+                                const OctetStr& security_name,
+                                const long int  auth_proto,
+                                const long int  priv_proto,
+                                const OctetStr& auth_pass,
+                                const OctetStr& priv_pass)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  int found=0;
+  int i;
+  for (i = 0; i < entries; i++)
+    if (table[i].usmUserName == user_name)
+    {
+      found=1;
+      break;
+    }
+
+  if (found)
+  {
+    /* replace user */
+    table[i].usmUserSecurityName = security_name;
+    table[i].usmUserAuthProtocol = auth_proto;
+    table[i].usmUserPrivProtocol = priv_proto;
+
+    if (table[i].authPassword)
+    {
+      memset(table[i].authPassword, 0, table[i].authPasswordLength);
+      delete [] table[i].authPassword;
+    }
+    table[i].authPassword = v3strcpy(auth_pass.data(), auth_pass.len());
+    table[i].authPasswordLength = auth_pass.len();
+
+    if (table[i].privPassword)
+    {
+      memset(table[i].privPassword, 0, table[i].privPasswordLength);
+      delete [] table[i].privPassword;
+    }
+    table[i].privPassword = v3strcpy(priv_pass.data(), priv_pass.len());
+    table[i].privPasswordLength = priv_pass.len();
+  }
+  else
+  {
+    if (entries == max_entries)
+    {
+      /* resize Table */
+      struct UsmUserNameTableEntry *tmp;
+      tmp = new struct UsmUserNameTableEntry[4 * max_entries];
+      if (!tmp)
+        return SNMPv3_USM_ERROR;
+      for (i=0; i < entries; i++)
+        tmp[i] = table[i];
+
+      struct UsmUserNameTableEntry *victim = table;
+      table = tmp;
+      delete [] victim;
+
+      max_entries *= 4;
+    }
+
+    table[entries].usmUserName          = user_name;
+    table[entries].usmUserSecurityName  = security_name;
+    table[entries].usmUserAuthProtocol  = auth_proto;
+    table[entries].usmUserPrivProtocol  = priv_proto;
+
+    table[entries].authPasswordLength = auth_pass.len();
+    table[entries].authPassword = v3strcpy(auth_pass.data(), auth_pass.len());
+    if (!table[entries].authPassword)
+      return SNMPv3_USM_ERROR;
+
+    table[entries].privPasswordLength = priv_pass.len();
+    table[entries].privPassword = v3strcpy(priv_pass.data(), priv_pass.len());
+    if (!table[entries].privPassword)
+      return SNMPv3_USM_ERROR;
+
+    entries++;
+  }
+
+  return SNMPv3_USM_OK;
+}
+
+int USMUserNameTable::delete_security_name(const OctetStr& security_name)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i = 0; i < entries; i++)
+    if (table[i].usmUserSecurityName == security_name)
+    {
+      memset(table[i].authPassword, 0, table[i].authPasswordLength);
+      delete [] table[i].authPassword;
+      memset(table[i].privPassword, 0, table[i].privPasswordLength);
+      delete [] table[i].privPassword;
+      entries--;
+      if (entries > i)
+        table[i] = table[entries];
+      break;
+    }
+  return SNMPv3_USM_OK;
+}
+
+const struct UsmUserNameTableEntry* USMUserNameTable::get_entry(
+                                          const OctetStr &security_name)
+{
+  if (!table)
+    return NULL;
+
+  for (int i = 0; i < entries; i++)
+    if (table[i].usmUserSecurityName == security_name)
+      return &table[i];
+  return NULL;
+}
+
+struct UsmUserNameTableEntry* USMUserNameTable::get_cloned_entry(const OctetStr &security_name)
+{
+  lock();
+  const struct UsmUserNameTableEntry *e = get_entry(security_name);
+  struct UsmUserNameTableEntry *res = 0;
+
+  if (e)
+  {
+    res = new struct UsmUserNameTableEntry;
+  }
+
+  if (res)
+  {
+    res->usmUserName = e->usmUserName;
+    res->usmUserSecurityName = e->usmUserSecurityName;
+    res->usmUserAuthProtocol = e->usmUserAuthProtocol;
+    res->usmUserPrivProtocol = e->usmUserPrivProtocol;
+    res->authPassword = v3strcpy(e->authPassword, e->authPasswordLength);
+    res->authPasswordLength = e->authPasswordLength;
+    res->privPassword = v3strcpy(e->privPassword, e->privPasswordLength);
+    res->privPasswordLength = e->privPasswordLength;
+
+    if ((res->authPasswordLength && !res->authPassword) ||
+       (res->privPasswordLength && !res->privPassword))
+    {
+      delete_cloned_entry(res);
+    }
+  }
+
+  unlock();
+  return res;
+}
+
+void USMUserNameTable::delete_cloned_entry(struct UsmUserNameTableEntry* &entry)
+{
+  if (!entry) return;
+
+  if (entry->authPassword)
+  {
+    memset(entry->authPassword, 0, entry->authPasswordLength);
+    delete [] entry->authPassword;
+  }
+
+  if (entry->privPassword)
+  {
+    memset(entry->privPassword, 0, entry->privPasswordLength);
+    delete [] entry->privPassword;
+  }
+
+  delete entry;
+
+  entry = 0;
+}
+
+
+int USMUserNameTable::get_security_name(const unsigned char *user_name,
+                                       const long int user_name_len,
+                                       OctetStr &security_name)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i = 0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserName.data(),
+                           table[i].usmUserName.len(),
+                            user_name, user_name_len))
+    {
+      security_name = table[i].usmUserSecurityName;
+
+      LOG_BEGIN(INFO_LOG | 9);
+      LOG("USMUserNameTable: Translated (user name) to (security name)");
+      LOG(table[i].usmUserName.get_printable());
+      LOG(security_name.get_printable());
+      LOG_END;
+
+      return SNMPv3_USM_OK;
+    }
+
+  int logclass = WARNING_LOG;
+  if (user_name_len == 0) logclass = INFO_LOG;
+  LOG_BEGIN(logclass | 5);
+  LOG("USMUserNameTable: No entry for (user name) in table");
+  LOG(OctetStr(user_name, user_name_len).get_printable());
+  LOG_END;
+
+  return SNMPv3_USM_ERROR;
+}
+
+int USMUserNameTable::get_user_name(unsigned char *user_name,
+                                    long int *user_name_len,
+                                    const unsigned char *security_name,
+                                    const long int security_name_len)
+{
+  unsigned long buf_len = *user_name_len;
+  *user_name_len = 0;
+
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i = 0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserSecurityName.data(),
+                            table[i].usmUserSecurityName.len(),
+                            security_name, security_name_len))
+    {
+      if (buf_len < table[i].usmUserName.len())
+      {
+          LOG_BEGIN(ERROR_LOG | 1);
+          LOG("USMUserNameTable: Buffer for user name too small (is) (should)");
+          LOG(buf_len);
+          LOG(table[i].usmUserName.len());
+          LOG_END;
+
+        return SNMPv3_USM_ERROR;
+      }
+      *user_name_len = table[i].usmUserName.len();
+      memcpy(user_name, table[i].usmUserName.data(),
+            table[i].usmUserName.len());
+
+      LOG_BEGIN(INFO_LOG | 9);
+      LOG("USMUserNameTable: Translated (security name) to (user name)");
+      LOG(table[i].usmUserSecurityName.get_printable());
+      LOG(table[i].usmUserName.get_printable());
+      LOG_END;
+
+      return SNMPv3_USM_OK;
+    }
+
+  int logclass = WARNING_LOG;
+  if (security_name_len == 0) logclass = INFO_LOG;
+  LOG_BEGIN(logclass | 5);
+  LOG("USMUserNameTable: No entry for (security  name) in table");
+  LOG(OctetStr(security_name, security_name_len).get_printable());
+  LOG_END;
+
+  return SNMPv3_USM_ERROR;
+}
+
+// Save all entries into a file.
+int USMUserNameTable::save_to_file(const char *name, AuthPriv *ap)
+{
+  char encoded[MAX_LINE_LEN * 2];
+  FILE *file_out;
+  char tmp_file_name[MAXLENGTH_FILENAME];
+  bool failed = false;
+
+  if (!name || !ap)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserNameTable: save_to_file called with illegal param");
+    if (!name)
+    {
+      LOG("filename");
+    }
+    if (!ap)
+    {
+      LOG("AuthPriv pointer");
+    }
+    LOG_END;
+
+    return SNMPv3_USM_ERROR;
+  }
+
+  LOG_BEGIN(INFO_LOG | 4);
+  LOG("USMUserNameTable: Saving users to file");
+  LOG(name);
+  LOG_END;
+
+  sprintf(tmp_file_name, "%s.tmp", name);
+  file_out = fopen(tmp_file_name, "w");
+  if (!file_out)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserNameTable: could not create tmpfile");
+    LOG(tmp_file_name);
+    LOG_END;
+
+    return SNMPv3_USM_FILECREATE_ERROR;
+  }
+
+  {
+    // Begin reentrant code block
+    BEGIN_REENTRANT_CODE_BLOCK;
+
+    for (int i=0; i < entries; ++i)
+    {
+      LOG_BEGIN(INFO_LOG | 8);
+      LOG("USMUserNameTable: Saving user to file");
+      LOG(table[i].usmUserName.get_printable());
+      LOG_END;
+
+      encodeString(table[i].usmUserName.data(), table[i].usmUserName.len(),
+                  encoded);
+      encoded[2 * table[i].usmUserName.len()] = '\n';
+      if (fwrite(encoded, 2 * table[i].usmUserName.len() + 1, 1,
+                file_out) != 1)
+      { failed = true; break; }
+
+      encodeString(table[i].usmUserSecurityName.data(),
+                  table[i].usmUserSecurityName.len(), encoded);
+      encoded[2 * table[i].usmUserSecurityName.len()] = '\n';
+      if (fwrite(encoded, 2 * table[i].usmUserSecurityName.len() + 1, 1,
+                file_out) != 1)
+      { failed = true; break; }
+
+      encodeString(table[i].authPassword, table[i].authPasswordLength,
+                  encoded);
+      encoded[2 * table[i].authPasswordLength] = '\n';
+      if (fwrite(encoded, 2 * table[i].authPasswordLength + 1, 1,
+                file_out) != 1)
+      { failed = true; break; }
+
+      encodeString(table[i].privPassword, table[i].privPasswordLength,
+                  encoded);
+      encoded[2 * table[i].privPasswordLength] = '\n';
+      if (fwrite(encoded, 2 * table[i].privPasswordLength + 1, 1,
+                file_out) != 1)
+      { failed = true; break; }
+
+      if (table[i].usmUserAuthProtocol == SNMP_AUTHPROTOCOL_NONE)
+      {
+       if (fwrite("none\n", 5, 1, file_out) != 1)
+       { failed = true; break; }
+      }
+      else
+      {
+       const Auth *a = ap->get_auth(table[i].usmUserAuthProtocol);
+       if (!a) { failed = true; break; }
+       sprintf(encoded, "%s\n", a->get_id_string());
+       if (fwrite(encoded, strlen(a->get_id_string()) + 1, 1, file_out) != 1)
+       { failed = true; break; }
+      }
+
+      if (table[i].usmUserPrivProtocol == SNMP_PRIVPROTOCOL_NONE)
+      {
+       if (fwrite("none\n", 5, 1, file_out) != 1)
+       { failed = true; break; }
+      }
+      else
+      {
+       const Priv *p = ap->get_priv(table[i].usmUserPrivProtocol);
+       if (!p) { failed = true; break; }
+       sprintf(encoded, "%s\n", p->get_id_string());
+       if (fwrite(encoded, strlen(p->get_id_string()) + 1, 1, file_out) != 1)
+       { failed = true; break; }
+      }
+    }
+  }
+
+  fclose(file_out);
+  if (failed)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserNameTable: Failed to write table entries.");
+    LOG_END;
+
+#ifdef WIN32
+    _unlink(tmp_file_name);
+#else
+    unlink(tmp_file_name);
+#endif
+    return SNMPv3_USM_FILEWRITE_ERROR;
+  }
+#ifdef WIN32
+  _unlink(name);
+#else
+  unlink(name);
+#endif
+  if (rename(tmp_file_name, name))
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserNameTable: Could not rename file (from) (to)");
+    LOG(tmp_file_name);
+    LOG(name);
+    LOG_END;
+
+    return SNMPv3_USM_FILERENAME_ERROR;
+  }
+
+  LOG_BEGIN(INFO_LOG | 4);
+  LOG("USMUserNameTable: Saving users to file finished");
+  LOG_END;
+
+  return SNMPv3_USM_OK;
+}
+
+// Load the table from a file.
+int USMUserNameTable::load_from_file(const char *name, AuthPriv *ap)
+{
+  char decoded[MAX_LINE_LEN];
+  FILE *file_in;
+  unsigned char line[MAX_LINE_LEN * 2];
+
+  if (!name || !ap)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserNameTable: load_to_file called with illegal param");
+    if (!name)
+    {
+      LOG("filename");
+    }
+    if (!ap)
+    {
+      LOG("AuthPriv pointer");
+    }
+    LOG_END;
+
+    return SNMPv3_USM_ERROR;
+  }
+
+  LOG_BEGIN(INFO_LOG | 4);
+  LOG("USMUserNameTable: Loading users from file");
+  LOG(name);
+  LOG_END;
+
+  file_in = fopen(name, "r");
+  if (!file_in)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserNameTable: could not open file");
+    LOG(name);
+    LOG_END;
+
+    return SNMPv3_USM_FILEOPEN_ERROR;
+  }
+
+  int len;
+  bool failed = false;
+  while (fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+  {
+    // user_name
+    len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+    decodeString(line, len, decoded);
+    OctetStr user_name((unsigned char*)decoded, len / 2);
+
+    // security_name
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+    decodeString(line, len, decoded);
+    OctetStr user_security_name((unsigned char*)decoded, len / 2);
+
+    // auth password
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+    decodeString(line, len, decoded);
+    OctetStr auth_pass((unsigned char*)decoded, len / 2);
+
+    // priv password
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+    decodeString(line, len, decoded);
+    OctetStr priv_pass((unsigned char*)decoded, len / 2);
+
+    // auth protocol
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    line[strlen((char*)line) - 1] = 0;
+    int auth_prot = SNMP_AUTHPROTOCOL_NONE;
+    if (strcmp((char*)line, "none") != 0)
+    {
+      auth_prot = ap->get_auth_id((char*)line);
+      if (auth_prot < 0)
+      { failed = true; break; }
+    }
+
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    line[strlen((char*)line) - 1] = 0;
+    int priv_prot = SNMP_PRIVPROTOCOL_NONE;
+    if (strcmp((char*)line, "none") != 0)
+    {
+      priv_prot = ap->get_priv_id((char*)line);
+      if (priv_prot < 0)
+      { failed = true; break; }
+    }
+
+    LOG_BEGIN(INFO_LOG | 7);
+    LOG("USMUserNameTable: Adding user (user name) (sec name) (auth) (priv)");
+    LOG(user_name.get_printable());
+    LOG(user_security_name.get_printable());
+    LOG(auth_prot);
+    LOG(priv_prot);
+    LOG_END;
+
+    if (add_entry(user_name, user_security_name, auth_prot, priv_prot,
+                 auth_pass, priv_pass) == SNMPv3_USM_ERROR)
+    {
+      failed = true;
+
+      LOG_BEGIN(ERROR_LOG | 1);
+      LOG("USMUserNameTable: Error adding (user name)");
+      LOG(user_name.get_printable());
+      LOG_END;
+    }
+  }
+
+  fclose(file_in);
+  if (failed)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserNameTable: Failed to read table entries");
+    LOG_END;
+
+    return SNMPv3_USM_FILEREAD_ERROR;
+  }
+
+  LOG_BEGIN(INFO_LOG | 4);
+  LOG("USMUserNameTable: Loaded all users from file");
+  LOG_END;
+
+  return SNMPv3_USM_OK;
+}
+
+const UsmUserNameTableEntry *USMUserNameTable::peek_next(
+                       const UsmUserNameTableEntry *e) const
+{
+  if (e == 0) return 0;
+  if (e - table < 0) return 0;
+  if (e - table >= entries - 1) return 0;
+  return (e + 1);
+}
+
+/* ---------------------------- USMUserTable ------------------- */
+
+USMUserTable::USMUserTable(int &result)
+{
+  entries = 0;
+
+  table = new struct UsmUserTableEntry[10];
+  if (!table)
+  {
+    result = SNMPv3_USM_ERROR;
+    return;
+  }
+  max_entries = 10;
+}
+
+USMUserTable::~USMUserTable()
+{
+  if (table)
+  {
+    for (int i = 0; i < entries; i++)
+    {
+      if (table[i].usmUserEngineID)
+       delete [] table[i].usmUserEngineID;
+      if (table[i].usmUserName)
+       delete [] table[i].usmUserName;
+      if (table[i].usmUserSecurityName)
+       delete [] table[i].usmUserSecurityName;
+      if (table[i].usmUserAuthKey)
+      {
+       memset(table[i].usmUserAuthKey, 0, table[i].usmUserAuthKeyLength);
+       delete [] table[i].usmUserAuthKey;
+      }
+      if (table[i].usmUserPrivKey)
+      {
+       memset(table[i].usmUserPrivKey, 0, table[i].usmUserPrivKeyLength);
+       delete [] table[i].usmUserPrivKey;
+      }
+    }
+    delete [] table;
+    table = NULL;
+    max_entries = 0;
+    entries = 0;
+  }
+}
+
+int USMUserTable::get_user_name(unsigned char       *user_name,
+                               long int            *user_name_len,
+                               const unsigned char *sec_name,
+                               const long           sec_name_len)
+
+{
+  long buf_len = *user_name_len;
+  *user_name_len = 0;
+
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i=0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserSecurityName,
+                           table[i].usmUserSecurityNameLength,
+                           sec_name, sec_name_len))
+    {
+      if (buf_len < table[i].usmUserNameLength)
+      {
+       LOG_BEGIN(ERROR_LOG | 1);
+       LOG("USMUserTable: Buffer for user name too small (is) (should)");
+       LOG(buf_len);
+       LOG(table[i].usmUserNameLength);
+       LOG_END;
+
+       return SNMPv3_USM_ERROR;
+      }
+      *user_name_len = table[i].usmUserNameLength;
+      memcpy(user_name, table[i].usmUserName, table[i].usmUserNameLength);
+
+      LOG_BEGIN(INFO_LOG | 9);
+      LOG("USMUserTable: Translated (security name) to (user name)");
+      LOG(OctetStr(sec_name, sec_name_len).get_printable());
+      LOG(OctetStr(table[i].usmUserName, table[i].usmUserNameLength).get_printable());
+      LOG_END;
+
+      return SNMPv3_USM_OK;
+    }
+
+  int logclass = WARNING_LOG;
+  if (sec_name_len == 0) logclass = INFO_LOG;
+  LOG_BEGIN(logclass | 5);
+  LOG("USMUserTable: No entry for (security  name) in table");
+  LOG(OctetStr(sec_name, sec_name_len).get_printable());
+  LOG_END;
+
+  return SNMPv3_USM_ERROR;
+}
+
+int USMUserTable::get_security_name(const unsigned char *user_name,
+                                   const long user_name_len,
+                                   OctetStr &sec_name)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i=0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
+                           user_name, user_name_len))
+    {
+      sec_name.set_data(table[i].usmUserSecurityName,
+                       table[i].usmUserSecurityNameLength);
+      LOG_BEGIN(INFO_LOG | 9);
+      LOG("USMUserTable: Translated (user name) to (security name)");
+      LOG(OctetStr(table[i].usmUserName, table[i].usmUserNameLength).get_printable());
+      LOG(sec_name.get_printable());
+      LOG_END;
+
+      return SNMPv3_USM_OK;
+    }
+
+  int logclass = WARNING_LOG;
+  if (user_name_len == 0) logclass = INFO_LOG;
+  LOG_BEGIN(logclass | 5);
+  LOG("USMUserTable: No entry for (user name) in table");
+  LOG(OctetStr(user_name, user_name_len).get_printable());
+  LOG_END;
+
+  return SNMPv3_USM_ERROR;
+}
+
+int USMUserTable::delete_entries(const OctetStr& user_name)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i = 0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
+                           user_name.data(), user_name.len()))
+    {
+      /* delete this entry and recheck this position */
+      delete_entry(i);
+      i--;
+    }
+  return SNMPv3_USM_OK;
+}
+
+// Delete all entries of this user from the usmUserTable
+int USMUserTable::delete_engine_id(const OctetStr& engine_id)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i = 0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserEngineID,
+                           table[i].usmUserEngineIDLength,
+                           engine_id.data(), engine_id.len()))
+    {
+      /* delete this entry and recheck this position*/
+      delete_entry(i);
+      i--;
+    }
+  return SNMPv3_USM_OK;
+}
+
+int USMUserTable::delete_entry(const OctetStr& engine_id,
+                              const OctetStr& user_name)
+{
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i = 0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
+                           user_name.data(), user_name.len()))
+      if (unsignedCharCompare(table[i].usmUserEngineID,
+                             table[i].usmUserEngineIDLength,
+                             engine_id.data(), engine_id.len()))
+      {
+       /* delete this entry and recheck this position*/
+       delete_entry(i);
+       i--;
+      }
+  return SNMPv3_USM_OK;
+}
+
+const struct UsmUserTableEntry *USMUserTable::get_entry(const int number)
+{
+  if ((entries < number) || (number < 1))
+    return NULL;
+
+  return &table[number - 1];
+}
+
+const struct UsmUserTableEntry *USMUserTable::get_entry(const OctetStr &engine_id,
+                                                       const OctetStr &sec_name)
+{
+  if (!table)
+    return NULL;
+
+  for (int i = 0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserSecurityName,
+                           table[i].usmUserSecurityNameLength,
+                           sec_name.data(), sec_name.len()))
+      if (unsignedCharCompare(table[i].usmUserEngineID,
+                             table[i].usmUserEngineIDLength,
+                             engine_id.data(), engine_id.len()))
+       return &table[i];
+  return NULL;
+}
+
+struct UsmUserTableEntry *USMUserTable::get_cloned_entry(
+                                 const OctetStr &engine_id,
+                                const OctetStr &sec_name)
+{
+  lock();
+  const struct UsmUserTableEntry *e = get_entry(engine_id, sec_name);
+  struct UsmUserTableEntry *res = 0;
+
+  if (e)
+  {
+    res = new struct UsmUserTableEntry;
+  }
+
+  if (res)
+  {
+    res->usmUserEngineID       = v3strcpy(e->usmUserEngineID,
+                                         e->usmUserEngineIDLength);
+    res->usmUserEngineIDLength = e->usmUserEngineIDLength;
+    res->usmUserName           = v3strcpy(e->usmUserName,
+                                         e->usmUserNameLength);
+    res->usmUserNameLength     = e->usmUserNameLength;
+    res->usmUserSecurityName   = v3strcpy(e->usmUserSecurityName,
+                                         e->usmUserSecurityNameLength);
+    res->usmUserSecurityNameLength = e->usmUserSecurityNameLength;
+    res->usmUserAuthProtocol   = e->usmUserAuthProtocol;
+    res->usmUserAuthKey        = v3strcpy(e->usmUserAuthKey,
+                                         e->usmUserAuthKeyLength);
+    res->usmUserAuthKeyLength  = e->usmUserAuthKeyLength;
+    res->usmUserPrivProtocol   = e->usmUserPrivProtocol;
+    res->usmUserPrivKey        = v3strcpy(e->usmUserPrivKey,
+                                         e->usmUserPrivKeyLength);
+    res->usmUserPrivKeyLength  = e->usmUserPrivKeyLength;
+
+    if ((res->usmUserEngineIDLength && !res->usmUserEngineID) ||
+       (res->usmUserNameLength && !res->usmUserName) ||
+       (res->usmUserSecurityNameLength && !res->usmUserSecurityName) ||
+       (res->usmUserAuthKeyLength && !res->usmUserAuthKey) ||
+       (res->usmUserPrivKeyLength && !res->usmUserPrivKey))
+    {
+      delete_cloned_entry(res);
+    }
+  }
+
+  unlock();
+  return res;
+}
+
+void USMUserTable::delete_cloned_entry(struct UsmUserTableEntry* &entry)
+{
+  if (!entry) return;
+
+  if (entry->usmUserEngineID) delete [] entry->usmUserEngineID;
+  if (entry->usmUserName)     delete [] entry->usmUserName;
+  if (entry->usmUserSecurityName) delete [] entry->usmUserSecurityName;
+
+  if (entry->usmUserAuthKey)
+  {
+    memset(entry->usmUserAuthKey, 0, entry->usmUserAuthKeyLength);
+    delete [] entry->usmUserAuthKey;
+  }
+
+  if (entry->usmUserPrivKey)
+  {
+    memset(entry->usmUserPrivKey, 0, entry->usmUserPrivKeyLength);
+    delete [] entry->usmUserPrivKey;
+  }
+
+  delete entry;
+
+  entry = 0;
+}
+
+
+const struct UsmUserTableEntry *USMUserTable::get_entry(const OctetStr &sec_name)
+{
+  if (!table)
+    return NULL;
+
+  for (int i = 0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserSecurityName,
+                           table[i].usmUserSecurityNameLength,
+                           sec_name.data(), sec_name.len()))
+      return &table[i];
+  return NULL;
+}
+
+int USMUserTable::add_entry(
+                      const OctetStr &engine_id,
+                     const OctetStr &user_name,  const OctetStr &sec_name,
+                     const long int  auth_proto, const OctetStr &auth_key,
+                     const long int  priv_proto, const OctetStr &priv_key)
+{
+  LOG_BEGIN(INFO_LOG | 7);
+  LOG("USMUserTable: Adding user (user name) (engine id) (auth) (priv)");
+  LOG(user_name.get_printable());
+  LOG(engine_id.get_printable());
+  LOG(auth_proto);
+  LOG(priv_proto);
+  LOG_END;
+
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  if (entries == max_entries)
+  {
+    /* resize Table */
+    struct UsmUserTableEntry *tmp;
+    tmp = new struct UsmUserTableEntry[4 * max_entries];
+    if (!tmp) return SNMPv3_USM_ERROR;
+    for (int i = 0; i < entries; i++)
+      tmp[i] = table[i];
+    delete [] table;
+    table = tmp;
+    max_entries *= 4;
+  }
+
+  for (int i = 0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
+                           user_name.data(), user_name.len()))
+      if (unsignedCharCompare(table[i].usmUserEngineID,
+                             table[i].usmUserEngineIDLength,
+                             engine_id.data(), engine_id.len()))
+      {
+       /* delete this entry */
+       delete_entry(i);
+       break;
+      }
+
+  /* add user at the last position */
+  table[entries].usmUserEngineIDLength = engine_id.len();
+  table[entries].usmUserEngineID       = v3strcpy(engine_id.data(),
+                                                 engine_id.len());
+  table[entries].usmUserNameLength     = user_name.len();
+  table[entries].usmUserName           = v3strcpy(user_name.data(),
+                                                 user_name.len());
+  table[entries].usmUserSecurityNameLength = sec_name.len();
+  table[entries].usmUserSecurityName   = v3strcpy(sec_name.data(),
+                                                 sec_name.len());
+  table[entries].usmUserAuthProtocol   = auth_proto;
+  table[entries].usmUserAuthKeyLength  = auth_key.len();
+  table[entries].usmUserAuthKey        = v3strcpy(auth_key.data(),
+                                                 auth_key.len());
+  table[entries].usmUserPrivProtocol   = priv_proto;
+  table[entries].usmUserPrivKeyLength  = priv_key.len();
+  table[entries].usmUserPrivKey        = v3strcpy(priv_key.data(),
+                                                 priv_key.len());
+  entries++;
+  return SNMPv3_USM_OK;
+}
+
+int USMUserTable::update_key(const OctetStr &user_name,
+                            const OctetStr &engine_id,
+                            const OctetStr &new_key,
+                            const int key_type)
+{
+  LOG_BEGIN(INFO_LOG | 7);
+  LOG("USMUserTable: Update key for user (name) (engine id) (type)");
+  LOG(user_name.get_printable());
+  LOG(engine_id.get_printable());
+  LOG(key_type);
+  LOG_END;
+
+  if (!table)
+    return SNMPv3_USM_ERROR;
+
+  BEGIN_REENTRANT_CODE_BLOCK;
+
+  for (int i = 0; i < entries; i++)
+    if (unsignedCharCompare(table[i].usmUserName, table[i].usmUserNameLength,
+                           user_name.data(), user_name.len()))
+      if (unsignedCharCompare(table[i].usmUserEngineID,
+                             table[i].usmUserEngineIDLength,
+                             engine_id.data(), engine_id.len()))
+      {
+       LOG_BEGIN(DEBUG_LOG | 15);
+       LOG("USMUserTable: New key");
+       LOG(new_key.get_printable());
+       LOG_END;
+
+       /* update key: */
+       switch (key_type)
+       {
+         case AUTHKEY:
+         case OWNAUTHKEY:
+         {
+           if (table[i].usmUserAuthKey)
+           {
+             memset(table[i].usmUserAuthKey, 0,
+                    table[i].usmUserAuthKeyLength);
+             delete [] table[i].usmUserAuthKey;
+           }
+           table[i].usmUserAuthKeyLength = new_key.len();
+           table[i].usmUserAuthKey = v3strcpy(new_key.data(), new_key.len());
+           return SNMPv3_USM_OK;
+         }
+         case PRIVKEY:
+         case OWNPRIVKEY:
+         {
+           if (table[i].usmUserPrivKey)
+           {
+             memset(table[i].usmUserPrivKey, 0,
+                    table[i].usmUserPrivKeyLength);
+             delete [] table[i].usmUserPrivKey;
+           }
+           table[i].usmUserPrivKeyLength = new_key.len();
+           table[i].usmUserPrivKey = v3strcpy(new_key.data(), new_key.len());
+           return SNMPv3_USM_OK;
+         }
+         default:
+         {
+           LOG_BEGIN(WARNING_LOG | 3);
+           LOG("USMUserTable: setting new key failed (wrong type).");
+           LOG_END;
+
+           return SNMPv3_USM_ERROR;
+         }
+       }
+      }
+
+  LOG_BEGIN(INFO_LOG | 7);
+  LOG("USMUserTable: setting new key failed (user) not found");
+  LOG(user_name.get_printable());
+  LOG_END;
+
+  return SNMPv3_USM_ERROR;
+}
+
+void USMUserTable::delete_entry(const int nr)
+{
+  /* Table is locked through caller, so do NOT lock table!
+   * All checks have been made, so dont check again!
+   */
+
+  if (table[nr].usmUserEngineID)     delete [] table[nr].usmUserEngineID;
+  if (table[nr].usmUserName)         delete [] table[nr].usmUserName;
+  if (table[nr].usmUserSecurityName) delete [] table[nr].usmUserSecurityName;
+  if (table[nr].usmUserAuthKey)
+  {
+    memset(table[nr].usmUserAuthKey, 0, table[nr].usmUserAuthKeyLength);
+    delete [] table[nr].usmUserAuthKey;
+  }
+  if (table[nr].usmUserPrivKey)
+  {
+    memset(table[nr].usmUserPrivKey, 0, table[nr].usmUserPrivKeyLength);
+    delete [] table[nr].usmUserPrivKey;
+  }
+
+  /* We have now one entry less */
+  entries--;
+
+  if (entries > nr)
+  {
+    /* move the last entry to the deleted position */
+    table[nr] = table[entries];
+  }
+}
+
+// Save all entries into a file.
+int USMUserTable::save_to_file(const char *name, AuthPriv *ap)
+{
+  char encoded[MAX_LINE_LEN * 2];
+  FILE *file_out;
+  char tmp_file_name[MAXLENGTH_FILENAME];
+  bool failed = false;
+
+  if (!name || !ap)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserTable: save_to_file called with illegal param");
+    if (!name)
+    {
+      LOG("filename");
+    }
+    if (!ap)
+    {
+      LOG("AuthPriv pointer");
+    }
+    LOG_END;
+
+    return SNMPv3_USM_ERROR;
+  }
+
+  LOG_BEGIN(INFO_LOG | 4);
+  LOG("USMUserTable: Saving users to file");
+  LOG(name);
+  LOG_END;
+
+  sprintf(tmp_file_name, "%s.tmp", name);
+  file_out = fopen(tmp_file_name, "w");
+  if (!file_out)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserTable: could not create tmpfile");
+    LOG(tmp_file_name);
+    LOG_END;
+
+    return SNMPv3_USM_FILECREATE_ERROR;
+  }
+
+  {
+    // Begin reentrant code block
+    BEGIN_REENTRANT_CODE_BLOCK;
+
+    for (int i=0; i < entries; ++i)
+    {
+      LOG_BEGIN(INFO_LOG | 8);
+      LOG("USMUserTable: Saving user to file");
+      LOG(OctetStr(table[i].usmUserName, table[i].usmUserNameLength)
+                 .get_printable());
+      LOG_END;
+
+      encodeString(table[i].usmUserEngineID, table[i].usmUserEngineIDLength,
+                  encoded);
+      encoded[2 * table[i].usmUserEngineIDLength] = '\n';
+      if (fwrite(encoded, 2 * table[i].usmUserEngineIDLength + 1, 1,
+                file_out) != 1)
+      { failed = true; break; }
+
+      encodeString(table[i].usmUserName, table[i].usmUserNameLength, encoded);
+      encoded[2 * table[i].usmUserNameLength] = '\n';
+      if (fwrite(encoded, 2 * table[i].usmUserNameLength + 1, 1,
+                file_out) != 1)
+      { failed = true; break; }
+
+      encodeString(table[i].usmUserSecurityName,
+                  table[i].usmUserSecurityNameLength, encoded);
+      encoded[2 * table[i].usmUserSecurityNameLength] = '\n';
+      if (fwrite(encoded, 2 * table[i].usmUserSecurityNameLength + 1, 1,
+                file_out) != 1)
+      { failed = true; break; }
+
+      encodeString(table[i].usmUserAuthKey, table[i].usmUserAuthKeyLength,
+                  encoded);
+      encoded[2 * table[i].usmUserAuthKeyLength] = '\n';
+      if (fwrite(encoded, 2 * table[i].usmUserAuthKeyLength + 1, 1,
+                file_out) != 1)
+      { failed = true; break; }
+
+      encodeString(table[i].usmUserPrivKey, table[i].usmUserPrivKeyLength,
+                  encoded);
+      encoded[2 * table[i].usmUserPrivKeyLength] = '\n';
+      if (fwrite(encoded, 2 * table[i].usmUserPrivKeyLength + 1, 1,
+                file_out) != 1)
+      { failed = true; break; }
+
+      if (table[i].usmUserAuthProtocol == SNMP_AUTHPROTOCOL_NONE)
+      {
+       if (fwrite("none\n", 5, 1, file_out) != 1)
+       { failed = true; break; }
+      }
+      else
+      {
+       const Auth *a = ap->get_auth(table[i].usmUserAuthProtocol);
+       if (!a) { failed = true; break; }
+       sprintf(encoded, "%s\n", a->get_id_string());
+       if (fwrite(encoded, strlen(a->get_id_string()) + 1, 1, file_out) != 1)
+       { failed = true; break; }
+      }
+
+      if (table[i].usmUserPrivProtocol == SNMP_PRIVPROTOCOL_NONE)
+      {
+       if (fwrite("none\n", 5, 1, file_out) != 1)
+       { failed = true; break; }
+      }
+      else
+      {
+       const Priv *p = ap->get_priv(table[i].usmUserPrivProtocol);
+       if (!p) { failed = true; break; }
+       sprintf(encoded, "%s\n", p->get_id_string());
+       if (fwrite(encoded, strlen(p->get_id_string()) + 1, 1, file_out) != 1)
+       { failed = true; break; }
+      }
+    }
+  }
+
+  fclose(file_out);
+  if (failed)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserTable: Failed to write table entries.");
+    LOG_END;
+
+#ifdef WIN32
+    _unlink(tmp_file_name);
+#else
+    unlink(tmp_file_name);
+#endif
+    return SNMPv3_USM_FILEWRITE_ERROR;
+  }
+#ifdef WIN32
+  _unlink(name);
+#else
+  unlink(name);
+#endif
+  if (rename(tmp_file_name, name))
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserTable: Could not rename file (from) (to)");
+    LOG(tmp_file_name);
+    LOG(name);
+    LOG_END;
+
+    return SNMPv3_USM_FILERENAME_ERROR;
+  }
+
+  LOG_BEGIN(INFO_LOG | 4);
+  LOG("USMUserTable: Saving users to file finished");
+  LOG_END;
+
+  return SNMPv3_USM_OK;
+}
+
+// Load the table from a file.
+int USMUserTable::load_from_file(const char *name, AuthPriv *ap)
+{
+  char decoded[MAX_LINE_LEN];
+  FILE *file_in;
+  unsigned char line[MAX_LINE_LEN * 2];
+
+  if (!name || !ap)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserTable: load_from_file called with illegal param");
+    if (!name)
+    {
+      LOG("filename");
+    }
+    if (!ap)
+    {
+      LOG("AuthPriv pointer");
+    }
+    LOG_END;
+
+    return SNMPv3_USM_ERROR;
+  }
+
+  LOG_BEGIN(INFO_LOG | 4);
+  LOG("USMUserTable: Loading users from file");
+  LOG(name);
+  LOG_END;
+
+  file_in = fopen(name, "r");
+  if (!file_in)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserTable: could not open file");
+    LOG(name);
+    LOG_END;
+
+    return SNMPv3_USM_FILEOPEN_ERROR;
+  }
+
+  bool failed = false;
+  int len;
+  while (fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+  {
+    // engine_id
+    len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+    decodeString(line, len, decoded);
+    OctetStr engine_id((unsigned char*)decoded, len / 2);
+
+    // user_name
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+    decodeString(line, len, decoded);
+    OctetStr user_name((unsigned char*)decoded, len / 2);
+
+    // security_name
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+    decodeString(line, len, decoded);
+    OctetStr user_security_name((unsigned char*)decoded, len / 2);
+
+    // auth key
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+    decodeString(line, len, decoded);
+    OctetStr auth_key((unsigned char*)decoded, len / 2);
+
+    // priv key
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    len = SAFE_INT_CAST(strlen((char*)line)) - 1;
+    decodeString(line, len, decoded);
+    OctetStr priv_key((unsigned char*)decoded, len / 2);
+
+    // auth protocol
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    line[strlen((char*)line) - 1] = 0;
+    int auth_prot = SNMP_AUTHPROTOCOL_NONE;
+    if (strcmp((char*)line, "none") != 0)
+    {
+      auth_prot = ap->get_auth_id((char*)line);
+      if (auth_prot < 0)
+      { failed = true; break; }
+    }
+
+    if (!fgets((char*)line, MAX_LINE_LEN * 2, file_in))
+    { failed = true; break; }
+    line[strlen((char*)line) - 1] = 0;
+    int priv_prot = SNMP_PRIVPROTOCOL_NONE;
+    if (strcmp((char*)line, "none") != 0)
+    {
+      priv_prot = ap->get_priv_id((char*)line);
+      if (priv_prot < 0)
+      { failed = true; break; }
+    }
+
+    LOG_BEGIN(INFO_LOG | 7);
+    LOG("USMUserTable: Adding localized (user name) (eng id) (auth) (priv)");
+    LOG(user_name.get_printable());
+    LOG(engine_id.get_printable());
+    LOG(auth_prot);
+    LOG(priv_prot);
+    LOG_END;
+
+    if (add_entry(engine_id, user_name, user_security_name,
+                 auth_prot, auth_key, priv_prot, priv_key)
+       == SNMPv3_USM_ERROR)
+    {
+      failed = true;
+
+      LOG_BEGIN(ERROR_LOG | 1);
+      LOG("USMUserTable: Error adding (user name)");
+      LOG(user_name.get_printable());
+      LOG_END;
+    }
+  }
+
+  fclose(file_in);
+  if (failed)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("USMUserTable: Failed to read table entries");
+    LOG_END;
+
+    return SNMPv3_USM_FILEREAD_ERROR;
+  }
+
+  LOG_BEGIN(INFO_LOG | 4);
+  LOG("USMUserTable: Loaded all users from file");
+  LOG_END;
+
+  return SNMPv3_USM_OK;
+}
+
+const UsmUserTableEntry *USMUserTable::peek_next(
+                   const UsmUserTableEntry *e) const
+{
+  if (e == 0) return 0;
+  if (e - table < 0) return 0;
+  if (e - table >= entries - 1) return 0;
+  return (e + 1);
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif
+
+#endif // _SNMPv3
diff --git a/3rdparty/snmp++/src/uxsnmp.cpp b/3rdparty/snmp++/src/uxsnmp.cpp
new file mode 100644 (file)
index 0000000..e033b50
--- /dev/null
@@ -0,0 +1,2362 @@
+/*_############################################################################
+  _## 
+  _##  uxsnmp.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+      U X S N M P . C P P
+
+      UXSNMP CLASS DECLARATION
+
+      Description:    Snmp class
+
+      Author:         Peter E Mellquist
+=====================================================================*/
+char snmp_cpp_version[]="#(@) SNMP++ $Id: uxsnmp.cpp 1798 2010-08-14 20:10:48Z katz $";
+
+/* CK Ng    added support for WIN32 in the whole file */
+
+//-----[ includes ]----------------------------------------------------
+#ifdef WIN32
+#include <sys/types.h>     // system types
+#include <sys/timeb.h>     // _timeb and _ftime
+#else
+#include <unistd.h>        // unix
+#include <sys/socket.h>    // bsd socket stuff
+#include <netinet/in.h>    // network types
+#include <arpa/inet.h>     // arpa types
+#include <sys/types.h>     // system types
+#if !(defined CPU && CPU == PPC603)
+#include <sys/time.h>      // time stuff
+#endif
+#endif
+#ifdef _AIX
+#define ss_family __ss_family
+#endif
+
+#include <stdlib.h>        // need for malloc
+#include <errno.h>         // ux errs
+
+#define _INCLUDE_SNMP_ERR_STRINGS
+
+//----[ snmp++ includes ]----------------------------------------------
+#include "snmp_pp/config_snmp_pp.h"
+#include "snmp_pp/uxsnmp.h"        // class def for this module
+#include "snmp_pp/oid_def.h"       // class def for well known trap oids
+#include "snmp_pp/v3.h"
+#include "snmp_pp/msgqueue.h"      // message queue
+#include "snmp_pp/notifyqueue.h"   // notification queue
+#include "snmp_pp/snmpmsg.h"       // asn serialization class
+#include "snmp_pp/eventlistholder.h"
+#include "snmp_pp/usm_v3.h"
+#include "snmp_pp/vb.h"
+#include "snmp_pp/log.h"
+#include "snmp_pp/IPv6Utility.h"
+
+#if defined (CPU) && CPU == PPC603
+#include <sockLib.h> 
+#include <taskLib.h> 
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+//-----[ special includes ]-------------------------------------------
+extern "C"
+{
+  //------------[ if using Wind-U, then bring in the ms-windows header ]
+#ifndef WIN32
+  typedef short WORD;
+  typedef long DWORD;
+#endif
+}
+
+//-----[ macros ]------------------------------------------------------
+#define DEFAULT_TIMEOUT 1000  // one second default timeout
+#define DEFAULT_RETRIES 1     // no retry default
+#define SNMP_PORT 161         // port # for SNMP
+#define SNMP_TRAP_PORT 162    // port # for SNMP traps
+
+#ifdef WIN32
+#ifdef __BCPLUSPLUS__
+#define _timeb timeb
+#define _ftime ftime
+#endif
+#define close closesocket
+#endif
+
+//--------[ globals ]---------------------------------------------------
+
+//--------------[ well known trap ids ]-----------------------------------
+const coldStartOid coldStart;
+const warmStartOid warmStart;
+const linkDownOid linkDown;
+const linkUpOid linkUp;
+const authenticationFailureOid authenticationFailure;
+const egpNeighborLossOid egpNeighborLoss;
+const snmpTrapEnterpriseOid snmpTrapEnterprise;
+
+
+#ifdef _SNMPv3
+
+void deleteV3Callback(struct Snmp::V3CallBackData *&cbData)
+{
+  if (cbData->pdu) {
+    delete cbData->pdu;
+    cbData->pdu = 0;
+  }
+  if (cbData->target) {
+    delete cbData->target;
+    cbData->target = 0;
+  }
+  delete cbData;
+  cbData = 0;
+}
+
+void v3CallBack(int reason, Snmp *snmp, Pdu &pdu, SnmpTarget &target, void *v3cd)
+{
+  struct Snmp::V3CallBackData *cbData = (struct Snmp::V3CallBackData*)v3cd;
+
+  Vb tmpvb;
+  pdu.get_vb(tmpvb,0);
+
+  debugprintf(5, "v3CallBack: received oid: %s with value: %s",
+              tmpvb.get_printable_oid(), tmpvb.get_printable_value());
+  debugprintf(5, "v3CallBack: error_msg (%s), pdu_type (%i)",
+             snmp->error_msg(tmpvb.get_oid()), pdu.get_type());
+
+  if ((pdu.get_type() == REPORT_MSG) &&
+      (((tmpvb.get_oid() == oidUsmStatsUnknownEngineIDs) &&
+       (cbData->reports_received == 0)) ||
+       ((tmpvb.get_oid() == oidUsmStatsNotInTimeWindows) &&
+       (cbData->reports_received <= 1)))) {
+    // hide those reports from user
+    int rc;
+    if ((cbData->pdu) && (cbData->target)) {
+      rc = snmp->snmp_engine(*(cbData->pdu), cbData->non_reps,
+                             cbData->max_reps, *(cbData->target),
+                             (snmp_callback)(cbData->oldCallback),
+                             (void *)cbData->cbd, INVALID_SOCKET,
+                            cbData->reports_received + 1);
+      debugprintf(3,"v3CallBack: snmp_engine called, rc (%i)", rc);
+    }
+    else
+      rc = SNMP_CLASS_ERROR;
+
+    if (rc != SNMP_CLASS_SUCCESS) {
+      // call callback if snmp_engine failed or pdu or target was 0
+      debugprintf(3,"v3CallBack: calling user callback");
+      snmp_callback tmp_callBack;
+      tmp_callBack = (snmp_callback)(cbData->oldCallback);
+      tmp_callBack(rc, snmp, pdu, target, (void *)cbData->cbd);
+    }
+  }
+  else {
+    debugprintf(3,"v3CallBack: calling user callback");
+    snmp_callback tmp_callBack;
+    tmp_callBack = (snmp_callback)(cbData->oldCallback);
+    tmp_callBack(reason, snmp, pdu, target, (void *)cbData->cbd);
+  }
+  // save to delete it here, because either snmp_engine created a new
+  // callback entry or the user specified callback has been called
+  deleteV3Callback(cbData);
+  return;
+}
+#endif
+
+//--------[ make the pdu request id ]-----------------------------------
+// return a unique rid, clock can be too slow , so use current_rid
+long Snmp::MyMakeReqId()
+{
+  long rid;
+  eventListHolder->snmpEventList()->lock();
+  do {
+    rid = ++current_rid;
+
+#ifdef INVALID_REQID
+    debugprintf(-10, "\nWARNING: Using constand RequestID!\n");
+    rid = 0xc0de;
+#endif
+
+    if ( current_rid > PDU_MAX_RID)
+    {
+      current_rid = rid = PDU_MIN_RID;
+      // let other tasks proceed
+      eventListHolder->snmpEventList()->unlock();
+      struct timeval tv;
+      tv.tv_sec = 0;
+      tv.tv_usec = 100;
+      select(0, 0, 0, 0, &tv);
+      eventListHolder->snmpEventList()->lock();
+    }
+  } while (eventListHolder->snmpEventList()->GetEntry(rid));
+  eventListHolder->snmpEventList()->unlock();
+
+  return rid;
+}
+
+//---------[ Send SNMP Request ]---------------------------------------
+// Send out a snmp request
+DLLOPT int send_snmp_request(SnmpSocket sock, unsigned char *send_buf,
+                             size_t send_len, Address & address)
+{
+  // UX only supports UDP type addresses (addr and port) right now
+  if (address.get_type() != Address::type_udp)
+    return -1;// unsupported address type
+
+  debugprintf(1, "++ SNMP++: sending to %s:",
+              ((UdpAddress &)address).UdpAddress::get_printable());
+  debughexprintf(5, send_buf, SAFE_UINT_CAST(send_len));
+
+  int send_result;
+
+  if (((UdpAddress &)address).get_ip_version() == Address::version_ipv4)
+  {
+    // prepare the destination address
+    struct sockaddr_in agent_addr;  // send socket struct
+    memset(&agent_addr, 0, sizeof(agent_addr));
+    agent_addr.sin_family = AF_INET;
+    agent_addr.sin_addr.s_addr
+              = inet_addr(((IpAddress &)address).IpAddress::get_printable());
+    agent_addr.sin_port = htons(((UdpAddress &)address).get_port());
+
+    send_result = sendto(sock, (char*) send_buf, SAFE_INT_CAST(send_len), 0,
+                         (struct sockaddr*) &agent_addr, sizeof(agent_addr));
+  }
+  else
+  {
+#ifdef SNMP_PP_IPv6
+    struct sockaddr_in6 agent_addr;
+    memset(&agent_addr, 0, sizeof(agent_addr));
+    unsigned int scope = 0;
+    
+    OctetStr addrstr = ((IpAddress &)address).IpAddress::get_printable();
+
+    if (((IpAddress &)address).has_ipv6_scope())
+    {
+       scope = ((IpAddress &)address).get_scope();
+
+       int i = addrstr.len() - 1;
+       while ((i>0) && (addrstr[i] != '%'))
+       {
+           addrstr.set_len(addrstr.len() - 1);
+           i--;
+       }
+       if (addrstr[i] == '%')
+           addrstr.set_len(addrstr.len() - 1);
+    }
+
+    if (inet_pton(AF_INET6, addrstr.get_printable(),
+                 &agent_addr.sin6_addr) < 0)
+    {
+       LOG_BEGIN(ERROR_LOG | 1);
+       LOG("Snmp transport: inet_pton returns (errno) (str)");
+       LOG(errno);
+       LOG(strerror(errno));
+       LOG_END;
+       return -1;
+    }
+    agent_addr.sin6_family = AF_INET6;
+    agent_addr.sin6_port = htons(((UdpAddress &)address).get_port());
+    agent_addr.sin6_scope_id = scope;
+    send_result = sendto( sock, (char*) send_buf, send_len, 0,
+                          (struct sockaddr*) &agent_addr, sizeof(agent_addr));
+#else
+    debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
+    return -1;
+#endif
+  }
+
+  if (send_result < 0)
+  {
+    debugprintf(0, "Error sending packet: %s", strerror(errno));
+    return -1; // send error!
+  }
+
+  return 0;
+}
+
+//---------[ receive a snmp response ]---------------------------------
+// Receive a response from the specified socket.
+// This function does not set the request id in the pdu if
+// any error occur in receiving or parsing.  This is important
+// because the caller initializes this to zero and checks it to
+// see whether it has been changed to a valid value.  The
+// return value is the normal PDU status or SNMP_CLASS_SUCCESS.
+// when we are successful in receiving a pdu.  Otherwise it
+// is an error status.
+
+int receive_snmp_response(SnmpSocket sock, Snmp &snmp_session,
+                          Pdu &pdu, UdpAddress &fromaddress,
+                         OctetStr &engine_id, bool process_msg = true)
+{
+  unsigned char receive_buffer[MAX_SNMP_PACKET + 1];
+  long receive_buffer_len; // len of received data
+#ifdef SNMP_PP_IPv6
+  struct sockaddr_storage from_addr;
+#else
+  struct sockaddr_in from_addr;
+#endif
+#if !(defined (CPU) && CPU == PPC603) && (defined __GNUC__ || defined __FreeBSD__ || defined _AIX) && ! defined __MINGW32__
+  socklen_t fromlen;
+#else
+  int fromlen;
+#endif
+  fromlen = sizeof(from_addr);
+
+  memset(&from_addr, 0, sizeof(from_addr));
+
+  // do the read
+  do {
+    receive_buffer_len = (long) recvfrom(sock, (char *) receive_buffer,
+                                         MAX_SNMP_PACKET + 1, 0,
+                                         (struct sockaddr*) &from_addr,
+                                         &fromlen);
+    debugprintf(2, "++ SNMP++: something received...");
+  } while ((receive_buffer_len < 0) && (EINTR == errno));
+
+  if (receive_buffer_len < 0 )                // error or no data pending
+    return SNMP_CLASS_TL_FAILED;
+  debugprintf(6, "Length received %i from socket %i; fromlen %i",
+              receive_buffer_len, sock, fromlen);
+
+  if (receive_buffer_len == MAX_SNMP_PACKET + 1)
+  {
+    // Message is too long...
+    debugprintf(1, "Received message is ignored (packet too long)");
+    return SNMP_CLASS_ERROR;
+  }
+
+  if (((sockaddr_in&)from_addr).sin_family == AF_INET)
+  {
+    // IPv4
+    fromaddress = inet_ntoa(((sockaddr_in&)from_addr).sin_addr);
+    fromaddress.set_port(ntohs(((sockaddr_in&)from_addr).sin_port));
+  }
+#ifdef SNMP_PP_IPv6
+  else if (from_addr.ss_family == AF_INET6)
+  {
+    // IPv6
+    char tmp_buffer[INET6_ADDRSTRLEN+1];
+
+    inet_ntop(AF_INET6, &(((sockaddr_in6&)from_addr).sin6_addr),
+              tmp_buffer, INET6_ADDRSTRLEN);
+
+    fromaddress = tmp_buffer;
+    fromaddress.set_port(ntohs(((sockaddr_in6&)from_addr).sin6_port));
+    if (((sockaddr_in6&)from_addr).sin6_scope_id != 0)
+       fromaddress.set_scope(((sockaddr_in6&)from_addr).sin6_scope_id);
+  }
+#endif // SNMP_PP_IPv6
+  else
+  {
+    debugprintf(0, "Unknown socket address family (%i).",
+                ((sockaddr_in&)from_addr).sin_family);
+    return SNMP_CLASS_ERROR;
+  }
+
+  debugprintf(1, "++ SNMP++: data received from %s.",
+              fromaddress.get_printable());
+  debughexprintf(5, receive_buffer, receive_buffer_len);
+
+  if (process_msg == false)
+    return SNMP_CLASS_SUCCESS;   // return success
+
+  SnmpMessage snmpmsg;
+  if ( snmpmsg.load( receive_buffer, receive_buffer_len) != SNMP_CLASS_SUCCESS)
+    return SNMP_CLASS_ERROR;
+
+  OctetStr community_name;
+  snmp_version version;
+  OctetStr security_name;
+
+#ifdef _SNMPv3
+  long int security_model;
+  if (snmpmsg.is_v3_message() == TRUE)
+  {
+    int returncode = snmpmsg.unloadv3(pdu, version, engine_id,
+                                      security_name, security_model,
+                                      fromaddress, snmp_session);
+    if (returncode != SNMP_CLASS_SUCCESS)
+      return returncode;
+  }
+  else
+  {
+#endif
+    int returncode = snmpmsg.unload( pdu, community_name, version);
+    if (returncode != SNMP_CLASS_SUCCESS)
+      return SNMP_CLASS_ERROR;
+#ifdef _SNMPv3
+  }
+  if (version == version3)
+  {
+    debugprintf(4,"receive_snmp_response: engine_id (%s), security_name (%s), "
+               "security_model (%i), security_level (%i)",
+                engine_id.get_printable(), security_name.get_printable(),
+                security_model, pdu.get_security_level());
+    debugprintf(5," addtoengineidtable: (%s)",
+                (unsigned char*)fromaddress.get_printable());
+  }
+#endif
+
+  //-----[ check for error status stuff..]
+  // an error status is a valid pdu,
+  // the caller needs to know about it
+  if ( pdu.get_error_status() != 0)
+    return pdu.get_error_status();
+
+  debugprintf(5,"receive_snmp_response requestID = %li, "
+             "returning SUCCESS.", pdu.get_request_id());
+
+  return SNMP_CLASS_SUCCESS;   // Success! return
+}
+
+
+//---------[ receive a snmp trap ]---------------------------------
+// Receive a trap from the specified socket
+// note: caller has to delete target!
+int receive_snmp_notification(SnmpSocket sock, Snmp &snmp_session,
+                              Pdu &pdu, SnmpTarget **target)
+{
+  unsigned char receive_buffer[MAX_SNMP_PACKET + 1];
+  long receive_buffer_len; // len of received data
+
+#ifdef SNMP_PP_IPv6
+  struct sockaddr_storage from_addr;
+#else
+  struct sockaddr_in from_addr;
+#endif // SNMP_PP_IPv6
+
+#if !(defined (CPU) && CPU == PPC603) && (defined __GNUC__ || defined __FreeBSD__ || defined _AIX) && ! defined __MINGW32__
+  socklen_t fromlen;
+#else
+  int fromlen;
+#endif
+  fromlen = sizeof(from_addr);
+
+  memset(&from_addr, 0, sizeof(from_addr));
+
+  // do the read
+  do {
+    receive_buffer_len = (long) recvfrom(sock, (char *) receive_buffer,
+                                         MAX_SNMP_PACKET + 1, 0,
+                                         (struct sockaddr*)&from_addr,
+                                         &fromlen);
+  } while (receive_buffer_len < 0 && EINTR == errno);
+
+  if (receive_buffer_len < 0 )                // error or no data pending
+    return SNMP_CLASS_TL_FAILED;
+
+  if (receive_buffer_len == MAX_SNMP_PACKET + 1)
+  {
+    // Message is too long...
+    debugprintf(1, "Received message is ignored (packet too long)");
+    return SNMP_CLASS_ERROR;
+  }
+
+  // copy fromaddress and remote port
+  UdpAddress fromaddress;
+
+  if (((sockaddr_in&)from_addr).sin_family == AF_INET)
+  {
+    // IPv4
+    fromaddress = inet_ntoa(((sockaddr_in&)from_addr).sin_addr);
+    fromaddress.set_port(ntohs(((sockaddr_in&)from_addr).sin_port));
+  }
+#ifdef SNMP_PP_IPv6
+  else if (from_addr.ss_family == AF_INET6)
+  {
+    // IPv6
+    char tmp_buffer[INET6_ADDRSTRLEN+1];
+
+    inet_ntop(AF_INET6, &(((sockaddr_in6&)from_addr).sin6_addr),
+              tmp_buffer, INET6_ADDRSTRLEN);
+
+    fromaddress = tmp_buffer;
+    fromaddress.set_port(ntohs(((sockaddr_in6&)from_addr).sin6_port));
+    if (((sockaddr_in6&)from_addr).sin6_scope_id != 0)
+       fromaddress.set_scope(((sockaddr_in6&)from_addr).sin6_scope_id);
+  }
+#endif // SNMP_PP_IPv6
+  else
+  {
+    debugprintf(0, "Unknown socket address family (%i).",
+                ((sockaddr_in&)from_addr).sin_family);
+    return SNMP_CLASS_TL_FAILED;
+  }
+
+  debugprintf(1, "++ SNMP++: data received from %s.",
+              fromaddress.get_printable());
+  debughexprintf(5, receive_buffer, receive_buffer_len);
+
+  SnmpMessage snmpmsg;
+  if ( snmpmsg.load( receive_buffer, receive_buffer_len) != SNMP_CLASS_SUCCESS)
+    return SNMP_CLASS_ERROR;
+
+  OctetStr community_name;
+  snmp_version version;
+  OctetStr engine_id;
+  OctetStr security_name;
+
+#ifdef _SNMPv3
+  long int security_model;
+  if (snmpmsg.is_v3_message() == TRUE)
+  {
+    int returncode = snmpmsg.unloadv3(pdu, version, engine_id,
+                                      security_name, security_model,
+                                      fromaddress, snmp_session);
+    if (returncode != SNMP_CLASS_SUCCESS)
+      return returncode;
+  }
+  else
+  {
+#endif
+    int returncode = snmpmsg.unload( pdu, community_name, version);
+    if (returncode != SNMP_CLASS_SUCCESS)
+      return SNMP_CLASS_ERROR;
+#ifdef _SNMPv3
+  }
+
+  if (version == version3) {
+    *target = new UTarget();
+    (*target)->set_address(fromaddress);
+    (*target)->set_version(version);
+    ((UTarget*)*target)->set_engine_id(engine_id);
+    ((UTarget*)*target)->set_security_name(security_name);
+    ((UTarget*)*target)->set_security_model(security_model);
+
+    v3MP::I->add_to_engine_id_table(engine_id,
+                         (char*)(fromaddress.IpAddress::get_printable()),
+                         fromaddress.get_port());
+
+    debugprintf(4,"receive_snmp_notification: engine_id (%s), security_name "
+               "(%s), security_model (%i), security_level (%i)",
+                engine_id.get_printable(), security_name.get_printable(),
+                security_model, pdu.get_security_level());
+  }
+  else
+  {
+#endif
+    *target = new CTarget();
+    (*target)->set_version(version);
+    (*target)->set_address(fromaddress);
+    ((CTarget*)*target)->set_readcommunity( community_name);
+    ((CTarget*)*target)->set_writecommunity( community_name);
+#ifdef _SNMPv3
+  }
+#endif
+  return SNMP_CLASS_SUCCESS;   // Success! return
+}
+
+
+//--------[ map action ]------------------------------------------------
+// map the snmp++ action to a SMI pdu type
+void Snmp::map_action( unsigned short action, unsigned short & pdu_action)
+{
+  switch( action)
+    {
+    case sNMP_PDU_GET:
+    case sNMP_PDU_GET_ASYNC:
+      pdu_action = sNMP_PDU_GET;
+      break;
+
+    case sNMP_PDU_SET:
+    case sNMP_PDU_SET_ASYNC:
+      pdu_action = sNMP_PDU_SET;
+      break;
+
+    case sNMP_PDU_GETNEXT:
+    case sNMP_PDU_GETNEXT_ASYNC:
+      pdu_action = sNMP_PDU_GETNEXT;
+      break;
+
+    case sNMP_PDU_GETBULK:
+    case sNMP_PDU_GETBULK_ASYNC:
+      pdu_action = sNMP_PDU_GETBULK;
+      break;
+
+    case sNMP_PDU_RESPONSE:
+      pdu_action = sNMP_PDU_RESPONSE;
+      break;
+
+    case sNMP_PDU_INFORM:
+    case sNMP_PDU_INFORM_ASYNC:
+      pdu_action = sNMP_PDU_INFORM;
+      break;
+
+    case sNMP_PDU_REPORT:
+      pdu_action = sNMP_PDU_REPORT;
+      break;
+
+    default:
+      pdu_action = sNMP_PDU_GET;  // TM ?? error ??
+      break;
+
+    };  // end switch
+}
+
+//------[ Snmp Class Constructor ]--------------------------------------
+
+Snmp::Snmp(int &status, const unsigned short port, const bool bind_ipv6)
+    : SnmpSynchronized(),
+      m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
+{
+  IpAddress *addresses[2];
+
+  if (bind_ipv6)
+  {
+    listen_address = "::";
+
+    addresses[0] = NULL;
+    addresses[1] = &listen_address;
+
+    init(status, addresses, 0, port);
+  }
+  else
+  {
+    listen_address = "0.0.0.0";
+
+    addresses[0] = &listen_address;
+    addresses[1] = NULL;
+
+    init(status, addresses, port, 0);
+  }
+
+}
+
+Snmp::Snmp( int &status, const UdpAddress& addr)
+    : SnmpSynchronized(),
+      m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
+{
+  IpAddress *addresses[2];
+
+  listen_address = addr;
+
+  if (listen_address.get_ip_version() == Address::version_ipv4)
+  {
+    addresses[0] = &listen_address;
+    addresses[1] = NULL;
+    init(status, addresses, addr.get_port(), 0);
+  }
+  else
+  {
+    addresses[0] = NULL;
+    addresses[1] = &listen_address;
+    init(status, addresses, 0, addr.get_port());
+  }
+}
+
+Snmp::Snmp( int &status,  const UdpAddress& addr_v4,
+            const UdpAddress& addr_v6)
+    : SnmpSynchronized(),
+      m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
+{
+  IpAddress *addresses[2];
+
+  listen_address = addr_v4;
+  IpAddress address_v6((IpAddress)addr_v6);
+  addresses[0] = &listen_address;
+  addresses[1] = &address_v6;
+
+  init(status, addresses, addr_v4.get_port(), addr_v6.get_port());
+}
+
+void Snmp::socket_startup()
+{
+#ifdef WIN32
+  WSADATA WSAData;
+  (void)WSAStartup(0x0101, &WSAData);
+#endif
+}
+
+void Snmp::socket_cleanup()
+{
+#ifdef WIN32
+  int iRetValue = WSACleanup();
+  debugprintf(4, "WSACleanup: ReturnValue (%i)", iRetValue);
+#endif
+}
+
+void Snmp::init(int& status, IpAddress *addresses[2],
+                const unsigned short port_v4,
+                const unsigned short port_v6)
+{
+#ifdef _THREADS
+#ifdef WIN32
+  m_hThread = INVALID_HANDLE_VALUE;
+  m_hThreadEndEvent = ::CreateEvent(NULL, true, false, NULL);
+#endif
+#endif
+
+  eventListHolder = new EventListHolder(this);
+  // initialize the request_id
+  eventListHolder->snmpEventList()->lock();
+//  srand(time(0)); // better than nothing
+  current_rid = (rand() % (PDU_MAX_RID - PDU_MIN_RID +1)) + PDU_MIN_RID;
+  debugprintf(4, "Initialized request_id to %i.", current_rid);
+  eventListHolder->snmpEventList()->unlock();
+
+  // intialize all the trap receiving member variables
+  notifycallback = 0;
+  notifycallback_data = 0;
+#ifdef HPUX
+  int errno = 0;
+#endif
+
+  status = SNMP_CLASS_ERROR;
+  iv_snmp_session = INVALID_SOCKET;
+#ifdef SNMP_PP_IPv6
+  iv_snmp_session_ipv6 = INVALID_SOCKET;
+#endif
+
+  /* Open IPv4 socket */
+  if (addresses[0])
+  {
+    // open a socket to be used for the session
+    if (( iv_snmp_session = socket( AF_INET, SOCK_DGRAM,0)) == INVALID_SOCKET)
+    {
+#ifdef WIN32
+      int werr = WSAGetLastError();
+      debugprintf(1, "Call to socket throws error %d", werr);
+      if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
+        status = SNMP_CLASS_RESOURCE_UNAVAIL;
+      else if (WSAEHOSTDOWN == werr)
+        status = SNMP_CLASS_TL_FAILED;
+      else
+        status = SNMP_CLASS_TL_UNSUPPORTED;
+#else
+      if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
+        status = SNMP_CLASS_RESOURCE_UNAVAIL;
+      else if (EHOSTDOWN == errno)
+        status = SNMP_CLASS_TL_FAILED;
+      else
+        status = SNMP_CLASS_TL_UNSUPPORTED;
+#endif
+    }
+    else
+    {
+      // set up the manager socket attributes
+      unsigned long inaddr = inet_addr(addresses[0]->get_printable());
+      struct sockaddr_in mgr_addr;
+      memset(&mgr_addr, 0, sizeof(mgr_addr));
+      mgr_addr.sin_family = AF_INET;
+      mgr_addr.sin_addr.s_addr = inaddr;
+      mgr_addr.sin_port = htons( port_v4);
+#ifdef CYGPKG_NET_OPENBSD_STACK
+      mgr_addr.sin_len = sizeof(mgr_addr);
+#endif
+
+      // bind the socket
+      if (bind(iv_snmp_session, (struct sockaddr*)&mgr_addr,
+               sizeof(mgr_addr)) < 0)
+      {
+#ifdef WIN32
+        int werr = WSAGetLastError();
+       debugprintf(1, "Call to bind throws error %d", werr);
+        if (WSAEADDRINUSE  == werr)
+          status = SNMP_CLASS_TL_IN_USE;
+        else if (WSAENOBUFS == werr)
+          status = SNMP_CLASS_RESOURCE_UNAVAIL;
+        else if (werr == WSAEAFNOSUPPORT)
+          status = SNMP_CLASS_TL_UNSUPPORTED;
+        else if (werr == WSAENETUNREACH)
+          status = SNMP_CLASS_TL_FAILED;
+        else if (werr == EACCES)
+          status = SNMP_CLASS_TL_ACCESS_DENIED;
+        else
+          status = SNMP_CLASS_INTERNAL_ERROR;
+#else
+        if (EADDRINUSE  == errno)
+          status = SNMP_CLASS_TL_IN_USE;
+        else if (ENOBUFS == errno)
+          status = SNMP_CLASS_RESOURCE_UNAVAIL;
+        else if (errno == EAFNOSUPPORT)
+          status = SNMP_CLASS_TL_UNSUPPORTED;
+        else if (errno == ENETUNREACH)
+          status = SNMP_CLASS_TL_FAILED;
+        else if (errno == EACCES)
+          status = SNMP_CLASS_TL_ACCESS_DENIED;
+        else
+       {
+         debugprintf(0, "Uncatched errno value %d, returning internal error.",
+                     errno);
+          status = SNMP_CLASS_INTERNAL_ERROR;
+       }
+#endif
+       close(iv_snmp_session);    // close the dynamic socket
+       iv_snmp_session = INVALID_SOCKET;
+      }
+      else
+      {
+        status = SNMP_CLASS_SUCCESS;
+#ifdef SNMP_BROADCAST
+        int enable_broadcast = 1;
+        setsockopt(iv_snmp_session, SOL_SOCKET, SO_BROADCAST,
+                   (char*)&enable_broadcast, sizeof(enable_broadcast));
+#endif
+      }
+    }
+    if (status != SNMP_CLASS_SUCCESS)
+      return;
+  }
+
+  /* Open IPv6 socket */
+  if (addresses[1])
+  {
+#ifdef SNMP_PP_IPv6
+    // open a socket to be used for the session
+    if (( iv_snmp_session_ipv6 = socket( AF_INET6, SOCK_DGRAM,0)) 
+       == INVALID_SOCKET)
+    {
+#ifdef WIN32
+      int werr = WSAGetLastError();
+      if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
+        status = SNMP_CLASS_RESOURCE_UNAVAIL;
+      else if (WSAEHOSTDOWN == werr)
+        status = SNMP_CLASS_TL_FAILED;
+      else
+        status = SNMP_CLASS_TL_UNSUPPORTED;
+#else
+      if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
+        status = SNMP_CLASS_RESOURCE_UNAVAIL;
+      else if (EHOSTDOWN == errno)
+        status = SNMP_CLASS_TL_FAILED;
+      else
+        status = SNMP_CLASS_TL_UNSUPPORTED;
+#endif
+    }
+    else
+    {
+      // set up the manager socket attributes
+      struct sockaddr_in6 mgr_addr;
+      memset(&mgr_addr, 0, sizeof(mgr_addr));
+      unsigned int scope = 0;
+    
+      OctetStr addrstr = addresses[1]->get_printable();
+
+      if (addresses[1]->has_ipv6_scope())
+      {
+       scope = addresses[1]->get_scope();
+
+       int i = addrstr.len() - 1;
+       while ((i>0) && (addrstr[i] != '%'))
+       {
+           addrstr.set_len(addrstr.len() - 1);
+           i--;
+       }
+       if (addrstr[i] == '%')
+           addrstr.set_len(addrstr.len() - 1);
+      }
+      if (inet_pton(AF_INET6, addrstr.get_printable(),
+                   &mgr_addr.sin6_addr) < 0)
+      {
+       LOG_BEGIN(ERROR_LOG | 1);
+       LOG("Snmp transport: inet_pton returns (errno) (str)");
+       LOG(errno);
+       LOG(strerror(errno));
+       LOG_END;
+       status = SNMP_CLASS_INVALID_ADDRESS;
+       return;
+      }
+
+      mgr_addr.sin6_family = AF_INET6;
+      mgr_addr.sin6_port = htons( port_v6);
+      mgr_addr.sin6_scope_id = scope;
+      // bind the socket
+      if (bind(iv_snmp_session_ipv6, (struct sockaddr*) &mgr_addr,
+               sizeof(mgr_addr)) < 0)
+      {
+#ifdef WIN32
+        int werr = WSAGetLastError();
+        if (WSAEADDRINUSE  == werr)
+          status = SNMP_CLASS_TL_IN_USE;
+        else if (WSAENOBUFS == werr)
+          status = SNMP_CLASS_RESOURCE_UNAVAIL;
+        else if (werr == WSAEAFNOSUPPORT)
+          status = SNMP_CLASS_TL_UNSUPPORTED;
+        else if (werr == WSAENETUNREACH)
+          status = SNMP_CLASS_TL_FAILED;
+        else if (werr == EACCES)
+          status = SNMP_CLASS_TL_ACCESS_DENIED;
+        else
+          status = SNMP_CLASS_INTERNAL_ERROR;
+#else
+        if (EADDRINUSE  == errno)
+          status = SNMP_CLASS_TL_IN_USE;
+        else if (ENOBUFS == errno)
+          status = SNMP_CLASS_RESOURCE_UNAVAIL;
+        else if (errno == EAFNOSUPPORT)
+          status = SNMP_CLASS_TL_UNSUPPORTED;
+        else if (errno == ENETUNREACH)
+          status = SNMP_CLASS_TL_FAILED;
+        else if (errno == EACCES)
+          status = SNMP_CLASS_TL_ACCESS_DENIED;
+        else
+          status = SNMP_CLASS_INTERNAL_ERROR;
+#endif
+       close(iv_snmp_session_ipv6);    // close the dynamic socket
+       iv_snmp_session_ipv6 = INVALID_SOCKET;
+      }
+      else
+      {
+        status = SNMP_CLASS_SUCCESS;
+#ifdef SNMP_BROADCAST
+        int enable_broadcast = 1;
+        setsockopt(iv_snmp_session_ipv6, SOL_SOCKET, SO_BROADCAST,
+                   (char*)&enable_broadcast, sizeof(enable_broadcast));
+#endif
+      }
+    }
+#else
+    debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
+#endif // SNMP_PP_IPv6
+  }
+  return;
+}
+
+
+//---------[ Snmp Class Destructor ]----------------------------------
+Snmp::~Snmp()
+{
+  stop_poll_thread();
+
+#ifdef _THREADS
+#ifdef WIN32
+  ::CloseHandle(m_hThreadEndEvent);
+#endif
+#endif
+
+  // if we failed during construction then don't try
+  // to free stuff up that was not allocated
+  if (iv_snmp_session != INVALID_SOCKET)
+  {
+    // go through the snmpEventList and delete any outstanding
+    // events on this socket
+    eventListHolder->snmpEventList()->DeleteSocketEntry(iv_snmp_session);
+
+    close(iv_snmp_session);    // close the dynamic socket
+  }
+  // if we failed during construction then don't try
+  // to free stuff up that was not allocated
+
+#ifdef SNMP_PP_IPv6
+  if (iv_snmp_session_ipv6 != INVALID_SOCKET)
+  {
+    // go through the snmpEventList and delete any outstanding
+    // events on this socket
+    eventListHolder->snmpEventList()->DeleteSocketEntry(iv_snmp_session_ipv6);
+
+    close(iv_snmp_session_ipv6);    // close the dynamic socket
+  }
+#endif
+
+  // shut down trap reception if used
+  notify_unregister();
+
+  delete eventListHolder;
+}
+
+// Get the version of the snmp++ library at runtime
+// This function MUST stay in the cpp file!
+const char *Snmp::get_version()
+{
+  return SNMP_PP_VERSION_STRING;
+}
+
+//-------------------[ returns error string ]--------------------------
+const char *Snmp::error_msg(const int c)
+{
+#ifdef _SNMPv3
+  if (c>=SNMPv3_USM_MIN_ERROR)
+    return ((c>SNMPv3_USM_MAX_ERROR)?pv3Errs[SNMPv3_USM_ERRORCOUNT]:pv3Errs[c-SNMPv3_USM_MIN_ERROR]);
+  if (c<=SNMPv3_MP_MAX_ERROR)
+    return ((c<SNMPv3_MP_MIN_ERROR)?nv3Errs[SNMPv3_MP_ERRORCOUNT]:nv3Errs[SNMPv3_MP_MAX_ERROR - c]);
+#endif
+  return ((c<0)?
+          ((c<MAX_NEG_ERROR)?nErrs[-(MAX_NEG_ERROR)+1]:nErrs[-c]):
+          ((c>MAX_POS_ERROR)?pErrs[MAX_POS_ERROR+1]:pErrs[c]));
+}
+
+#ifdef _SNMPv3
+const char* Snmp::error_msg(const Oid& v3Oid)
+{
+  // UsmStats
+  if (v3Oid == oidUsmStatsUnsupportedSecLevels)
+    return error_msg(SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL);
+
+  if (v3Oid == oidUsmStatsNotInTimeWindows)
+    return error_msg(SNMPv3_USM_NOT_IN_TIME_WINDOW);
+
+  if (v3Oid == oidUsmStatsUnknownUserNames )
+    return error_msg(SNMPv3_USM_UNKNOWN_SECURITY_NAME);
+
+  if (v3Oid == oidUsmStatsUnknownEngineIDs)
+    return error_msg(SNMPv3_USM_UNKNOWN_ENGINEID);
+
+  if (v3Oid == oidUsmStatsWrongDigests)
+    return error_msg(SNMPv3_USM_AUTHENTICATION_FAILURE);
+
+  if (v3Oid == oidUsmStatsDecryptionErrors)
+    return error_msg(SNMPv3_USM_DECRYPTION_ERROR);
+
+  // MPDstats
+  if (v3Oid == oidSnmpUnknownSecurityModels)
+    return error_msg(SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL);
+
+  if (v3Oid == oidSnmpInvalidMsgs)
+    return error_msg(SNMPv3_MP_INVALID_MESSAGE);
+
+  if (v3Oid == oidSnmpUnknownPDUHandlers)
+    return error_msg(SNMPv3_MP_UNKNOWN_PDU_HANDLERS);
+
+  if (v3Oid == oidSnmpUnavailableContexts)
+    return error_msg(SNMPv3_MP_UNAVAILABLE_CONTEXT);
+
+  if (v3Oid == oidSnmpUnknownContexts)
+    return error_msg(SNMPv3_MP_UNKNOWN_CONTEXT);
+
+  return error_msg(MAX_POS_ERROR + 1);
+}
+#endif
+
+//------------------------[ get ]---------------------------------------
+int Snmp::get(Pdu &pdu, const SnmpTarget &target)
+{
+  pdu.set_type( sNMP_PDU_GET);
+  return snmp_engine( pdu, 0, 0, target, NULL, 0);
+}
+
+//------------------------[ get async ]----------------------------------
+int Snmp::get(Pdu &pdu, const SnmpTarget &target,
+              const snmp_callback callback,
+              const void * callback_data)
+{
+  pdu.set_type( sNMP_PDU_GET_ASYNC);
+  return snmp_engine( pdu, 0, 0, target, callback, callback_data);
+}
+
+//------------------------[ get next ]-----------------------------------
+int Snmp::get_next(Pdu &pdu, const SnmpTarget &target)
+{
+  pdu.set_type( sNMP_PDU_GETNEXT);
+  return snmp_engine( pdu, 0, 0, target, NULL, 0);
+}
+
+//------------------------[ get next async ]-----------------------------
+int Snmp::get_next(Pdu &pdu, const SnmpTarget &target,
+                   const snmp_callback callback,
+                   const void * callback_data)
+{
+  pdu.set_type( sNMP_PDU_GETNEXT_ASYNC);
+  return snmp_engine( pdu, 0, 0, target, callback, callback_data);
+}
+
+//-------------------------[ set ]---------------------------------------
+int Snmp::set(Pdu &pdu, const SnmpTarget &target)
+{
+  pdu.set_type( sNMP_PDU_SET);
+  return snmp_engine( pdu, 0, 0, target, NULL, 0);
+}
+
+//------------------------[ set async ]----------------------------------
+int Snmp::set(Pdu &pdu, const SnmpTarget &target,
+              const snmp_callback callback,
+              const void * callback_data)
+{
+  pdu.set_type( sNMP_PDU_SET_ASYNC);
+  return snmp_engine( pdu, 0, 0, target, callback, callback_data);
+}
+
+//-----------------------[ get bulk ]------------------------------------
+int Snmp::get_bulk(Pdu &pdu,                // pdu to use
+                   const SnmpTarget &target,// destination target
+                   const int non_repeaters, // number of non repeaters
+                   const int max_reps)      // maximum number of repetitions
+{
+  pdu.set_type( sNMP_PDU_GETBULK);
+  return snmp_engine( pdu, non_repeaters, max_reps, target, NULL, 0);
+}
+
+//-----------------------[ get bulk async ]------------------------------
+int Snmp::get_bulk(Pdu &pdu,                 // pdu to use
+                   const SnmpTarget &target, // destination target
+                   const int non_repeaters,  // number of non repeaters
+                   const int max_reps,       // maximum number of repetitions
+                   const snmp_callback callback,// callback to use
+                   const void * callback_data)  // callback data
+{
+  pdu.set_type( sNMP_PDU_GETBULK_ASYNC);
+  return snmp_engine( pdu, non_repeaters, max_reps, target,
+                      callback, callback_data);
+}
+
+//------------------------[ inform_response ]----------------------------
+int Snmp::response(Pdu &pdu,                 // pdu to use
+                   const SnmpTarget &target, // response target
+                  const SnmpSocket fd)
+{
+  pdu.set_type( sNMP_PDU_RESPONSE);
+  return snmp_engine(pdu, 0, 0, target, NULL, 0, fd);
+}
+
+int Snmp::send_raw_data(unsigned char *send_buf,
+                        size_t send_len, UdpAddress &address, SnmpSocket fd)
+{
+  // REENTRANT() removed because of #ifdef
+  SnmpSynchronize _synchronize(*this);
+
+  if (fd != INVALID_SOCKET)
+    return send_snmp_request(fd, send_buf, send_len, address);
+  else
+  {
+#ifdef SNMP_PP_IPv6
+    if (address.get_ip_version() == Address::version_ipv4)
+    {
+      if (iv_snmp_session != INVALID_SOCKET)
+       return send_snmp_request(iv_snmp_session, send_buf,
+                                send_len, address);
+      else
+       address.map_to_ipv6();
+    }
+    return send_snmp_request(iv_snmp_session_ipv6, send_buf,
+                            send_len, address);
+#else
+    return send_snmp_request(iv_snmp_session, send_buf,
+                             send_len, address);
+#endif
+
+  }
+}
+
+//-----------------------[ cancel ]--------------------------------------
+int Snmp::cancel(const unsigned long request_id)
+{
+  eventListHolder->snmpEventList()->lock();
+  int status = eventListHolder->snmpEventList()->DeleteEntry(request_id);
+  eventListHolder->snmpEventList()->unlock();
+
+  return status;
+}
+
+
+//----------------------[ sending report, V3 only]-----------------------
+int Snmp::report(Pdu &pdu,                // pdu to send
+                 const SnmpTarget &target)// destination target
+{
+  pdu.set_type( sNMP_PDU_REPORT);
+  return snmp_engine( pdu, 0, 0, target, NULL, 0);
+}
+
+//----------------------[ blocking inform, V2 only]------------------------
+int Snmp::inform(Pdu &pdu,                // pdu to send
+                 const SnmpTarget &target)// destination target
+{
+  if (target.get_version() == version1)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("Snmp: Invalid Operation: Inform not defined for SNMPv1");
+    LOG_END;
+
+    return SNMP_CLASS_INVALID_OPERATION;
+  }
+
+  pdu.set_type( sNMP_PDU_INFORM);
+  check_notify_timestamp(pdu);
+  return snmp_engine( pdu, 0, 0, target, NULL, 0);
+}
+
+//----------------------[ asynch inform, V2 only]------------------------
+int Snmp::inform(Pdu &pdu,                // pdu to send
+                 const SnmpTarget &target,      // destination target
+                 const snmp_callback callback,  // callback function
+                 const void * callback_data)    // callback data
+{
+  if (target.get_version() == version1)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("Snmp: Invalid Operation: Inform not defined for SNMPv1");
+    LOG_END;
+
+    return SNMP_CLASS_INVALID_OPERATION;
+  }
+
+  pdu.set_type(sNMP_PDU_INFORM_ASYNC);
+  check_notify_timestamp(pdu);
+  return snmp_engine( pdu, 0, 0, target, callback, callback_data);
+}
+
+
+//---------------------[ send a trap ]-----------------------------------
+int Snmp::trap(Pdu &pdu,                        // pdu to send
+               const SnmpTarget &target)        // destination target
+{
+  OctetStr my_get_community;
+  OctetStr my_set_community;
+  GenAddress address;
+  unsigned long my_timeout;
+  int my_retry;
+  unsigned char version;
+  int status;
+
+  debugprintf(1, "++ SNMP++, Send a Trap");
+  //---------[ make sure pdu is valid ]---------------------------------
+  if (!pdu.valid())
+  {
+    debugprintf(0, "-- SNMP++, PDU Object Invalid");
+    return  SNMP_CLASS_INVALID_PDU;
+  }
+
+  //---------[ make sure target is valid ]------------------------------
+  if (!target.valid())
+  {
+    debugprintf(0, "-- SNMP++, Target Object Invalid");
+    return SNMP_CLASS_INVALID_TARGET;
+  }
+
+  CTarget* ctarget = NULL;
+  UTarget* utarget = NULL;
+  OctetStr security_name;
+  int security_model;
+
+  switch (target.get_type()) {
+    case SnmpTarget::type_ctarget:
+      ctarget = (CTarget*)(&target);
+      break;
+    case SnmpTarget::type_utarget:
+      utarget = (UTarget*)(&target);
+      break;
+    case SnmpTarget::type_base:
+      debugprintf(0, "-- SNMP++, do not use SnmpTarget, use a  CTarget or UTarget");
+      return SNMP_CLASS_INVALID_TARGET;
+    default:
+      // target is not known
+      debugprintf(0, "-- SNMP++, type of target is unknown!");
+      return SNMP_CLASS_UNSUPPORTED;
+  }
+
+  if (ctarget) {
+    debugprintf(3, "snmp::trap called with CTarget");
+    if (!ctarget->resolve_to_C( my_get_community, my_set_community, address,
+                                my_timeout, my_retry, version))
+    {
+      debugprintf(0, "-- SNMP++, Resolve Fail (CTarget)");
+      return SNMP_CLASS_UNSUPPORTED;
+    }
+#ifdef _SNMPv3
+    if (version == version3)
+    {
+      debugprintf(0, "-- SNMP++, use UTarget for SNMPv3");
+      return SNMP_CLASS_INVALID_TARGET;
+    }
+#endif
+  }
+  else { // target is not a CTarget:
+    if (utarget) {
+      debugprintf(3, "trap called with UTarget");
+      if (!utarget->resolve_to_U( security_name, security_model, address,
+                                 my_timeout, my_retry, version))
+      {
+        debugprintf(0, "-- SNMP++, Resolve Fail (UTarget)");
+        return SNMP_CLASS_UNSUPPORTED;
+      }
+#ifdef _SNMPv3
+      if (version != version3) {
+#endif
+        my_get_community = security_name;
+        if ((security_model != SNMP_SECURITY_MODEL_V1) &&
+            (security_model != SNMP_SECURITY_MODEL_V2)) {
+          debugprintf(0, "-- SNMP++, Target contains invalid security_model/version combination");
+          return SNMP_CLASS_INVALID_TARGET;
+        }
+#ifdef _SNMPv3
+      } // end if (version != version3)
+#endif
+    }
+    else { // target is neither CTarget nor UTarget:
+      debugprintf(0, "-- SNMP++, Resolve Fail");
+      return SNMP_CLASS_INVALID_TARGET;
+    }
+  }
+
+  //--------[ determine request id to use ]------------------------------
+  pdu.set_request_id( MyMakeReqId());
+
+  //--------[ check timestamp, if null use system time ]-----------------
+  check_notify_timestamp(pdu);
+
+  //------[ validate address to use ]-------------------------------------
+  if (!address.valid()) {
+    debugprintf(0, "-- SNMP++, Bad address");
+    return SNMP_CLASS_INVALID_TARGET;
+  }
+
+  if ((address.get_type() != Address::type_ip) &&
+      (address.get_type() != Address::type_udp) )
+    {
+      debugprintf(0, "-- SNMP++, Bad address type");
+      return SNMP_CLASS_TL_UNSUPPORTED;
+    }
+
+  UdpAddress udp_address(address);
+  if (!udp_address.valid()) {
+    debugprintf(0, "-- SNMP++, copy address failed");
+    return SNMP_CLASS_RESOURCE_UNAVAIL;
+  }
+
+  //----------[ choose the target address port ]-----------------------
+  if ((address.get_type() == Address::type_ip) || !udp_address.get_port())
+    udp_address.set_port(SNMP_TRAP_PORT);
+
+  //----------[ based on the target type, choose v1 or v1 trap type ]-----
+  if ( version == version1)
+    pdu.set_type( sNMP_PDU_V1TRAP);
+  else // v2 and v3 use v2TRAP
+    pdu.set_type( sNMP_PDU_TRAP);
+
+  SnmpMessage snmpmsg;
+
+#ifdef _SNMPv3
+  if ( version == version3) {
+
+    OctetStr engine_id = v3MP::I->get_local_engine_id();
+    if (!utarget) {
+      debugprintf(0, "-- SNMP++, dont know how to handle SNMPv3 without UTarget!");
+      return SNMP_CLASS_INVALID_TARGET;
+    }
+
+    // set context_engine_id of pdu, if it is not set
+    if (pdu.get_context_engine_id().len() == 0)
+    {
+      debugprintf(8, "Setting contextEngineID of Pdu to (%s)",
+                  engine_id.get_printable());
+      pdu.set_context_engine_id(engine_id);
+    }
+
+    debugprintf(4,"Snmp::trap:");
+    debugprintf(4," engineID (%s), securityName (%s)\n securityModel (%i) security_level (%i)",
+                engine_id.get_printable(), security_name.get_printable(),
+                security_model, pdu.get_security_level());
+    debugprintf(4," Addr/Port (%s)",udp_address.get_printable());
+
+    status = snmpmsg.loadv3( pdu, engine_id, security_name,
+                             security_model, (snmp_version)version);
+  }
+  else
+#endif
+    status = snmpmsg.load( pdu, my_get_community, (snmp_version) version);
+
+  if ( status != SNMP_CLASS_SUCCESS) {
+    debugprintf(0, "snmp message load error!");
+    return status;
+  }
+
+  lock();
+  //------[ send the trap ]
+#ifdef SNMP_PP_IPv6
+  if (udp_address.get_ip_version() == Address::version_ipv4)
+  {
+    if (iv_snmp_session != INVALID_SOCKET)
+      status = send_snmp_request(iv_snmp_session,
+                                snmpmsg.data(), (size_t)snmpmsg.len(),
+                                udp_address);
+    else
+    {
+      udp_address.map_to_ipv6();
+      status = send_snmp_request(iv_snmp_session_ipv6,
+                                snmpmsg.data(), (size_t)snmpmsg.len(),
+                                udp_address);
+    }
+  }
+  else
+    status = send_snmp_request(iv_snmp_session_ipv6,
+                               snmpmsg.data(), (size_t)snmpmsg.len(),
+                               udp_address);
+#else
+  status = send_snmp_request(iv_snmp_session, snmpmsg.data(),
+                             (size_t)snmpmsg.len(), udp_address);
+#endif
+
+  unlock();
+  if (status != 0)
+    return SNMP_CLASS_TL_FAILED;
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+//----------------[ set notify_timestamp if it is null ]-------------
+#if defined (CPU) && CPU == PPC603
+
+  struct SCommTimer
+  {
+       unsigned long NumMS;
+       unsigned long FractMS;
+  };
+
+  extern "C"
+  {
+  void GetTime (struct SCommTimer *  Time);
+  }
+#endif
+
+void Snmp::check_notify_timestamp(Pdu &pdu)
+{
+  // As we don't know, when the application was started,
+  // use a continuously increasing notify_timestamp
+  TimeTicks timestamp;
+  pdu.get_notify_timestamp( timestamp);
+  if (timestamp <= 0)
+  {
+#ifdef WIN32
+    struct _timeb timebuffer;
+    _ftime( &timebuffer );
+    timebuffer.time -= 1103760000;   // knock off 35 years worth of seconds
+    timestamp = SAFE_ULONG_CAST((timebuffer.time * 100) +
+                               (timebuffer.millitm / 10));
+#elif defined (CPU) && CPU == PPC603
+    SCommTimer theTime;
+
+    GetTime(&theTime); // This function must be defined by the application
+
+    timestamp = theTime.NumMS/10;
+#else
+    struct timeval tp;
+    gettimeofday(&tp, NULL);
+    tp.tv_sec -= 1103760000;   // knock off 35 years worth of seconds
+    timestamp = (tp.tv_sec * 100) + (tp.tv_usec / 10000);
+#endif
+
+    pdu.set_notify_timestamp( timestamp);
+  }
+}
+
+//-----------------------[ read the notification filters ]----------------
+int Snmp::get_notify_filter(OidCollection &trapids,
+                            TargetCollection &targets)
+{
+  CNotifyEvent *e = eventListHolder->notifyEventList()->GetEntry(this);
+
+  if (!e)  return SNMP_CLASS_INVALID;
+
+  e->get_filter(trapids, targets);
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+// Set the port for listening to traps and informs.
+void Snmp::notify_set_listen_port(const int port)
+{
+  eventListHolder->notifyEventList()->set_listen_port(port);
+}
+
+// Get the port that is used for listening to traps and informs.
+int Snmp::notify_get_listen_port()
+{
+  return eventListHolder->notifyEventList()->get_listen_port();
+}
+
+//-----------------------[ register to get traps]-------------------------
+int Snmp::notify_register(const OidCollection     &trapids,
+                          const TargetCollection  &targets,
+                          const snmp_callback      callback,
+                          const void              *callback_data)
+{
+  // remove any previous filters for this session
+  notify_unregister();
+
+  // assign callback and callback data info
+  notifycallback = callback;
+  notifycallback_data = (void *)callback_data;
+
+  // add to the notify queue
+  return eventListHolder->notifyEventList()->AddEntry(this, trapids, targets);
+}
+
+//-----------------------[ un-register to get traps]----------------------
+int Snmp::notify_unregister()
+{
+  // remove from the notify queue
+  eventListHolder->notifyEventList()->DeleteEntry(this);
+
+  // null out callback information
+  notifycallback = 0;
+  notifycallback_data = 0;
+
+  return SNMP_CLASS_SUCCESS;
+}
+
+//---------[ get / set engine ]-----------------------------------------
+// The main snmp engine used for all requests
+// async requests return out early and don't wait in here for
+// the response
+int Snmp::snmp_engine( Pdu &pdu,              // pdu to use
+                       long int non_reps,     // # of non repititions
+                       long int max_reps,     // # of max repititions
+                       const SnmpTarget &target,    // from this target
+                       const snmp_callback cb,// callback for async calls
+                       const void *cbd,      // callback data
+                      SnmpSocket fd,
+                      int reports_received)
+
+{
+  long req_id = 0;                   // pdu request id
+  int status;                        // send status
+
+#ifdef _SNMPv3
+  // save original PDU for later reference
+  Pdu backupPdu = pdu;
+
+  for (int maxloops=0; maxloops<3; maxloops++)
+  {
+#endif
+
+    unsigned short pdu_action;        // type of pdu to build
+    unsigned short action;        // type of pdu to build
+    unsigned long my_timeout;        // target specific timeout
+    int my_retry;                // target specific retry
+
+    OctetStr my_get_community;
+    OctetStr my_set_community;
+    GenAddress address;
+    unsigned char version;
+
+    //---------[ make sure pdu is valid ]--------------------------
+    if ( !pdu.valid())
+      return  SNMP_CLASS_INVALID_PDU;
+
+    //---------[ depending on user action, map the correct pdu action]
+    action = pdu.get_type();
+    map_action(action, pdu_action);
+
+    //---------[ check for correct mode ]---------------------------
+    // if the class was constructed as a blocked model, callback=0
+    // and async calls are attempted, an error is returned
+    if (( cb == 0) &&
+        ((action == sNMP_PDU_GET_ASYNC) ||
+         (action == sNMP_PDU_SET_ASYNC) ||
+         (action == sNMP_PDU_GETNEXT_ASYNC) ||
+         (action == sNMP_PDU_GETBULK_ASYNC) ||
+         (action == sNMP_PDU_INFORM_ASYNC)))
+      return SNMP_CLASS_INVALID_CALLBACK;
+
+    //---------[ more mode checking ]--------------------------------
+    // if the class was constructed as an async model, callback = something
+    // and blocked calls are attempted, an error is returned
+    if (( cb != 0) &&
+        ((action == sNMP_PDU_GET) ||
+         (action == sNMP_PDU_SET) ||
+         (action == sNMP_PDU_GETNEXT) ||
+         (action == sNMP_PDU_GETBULK) ||
+         (action == sNMP_PDU_INFORM)))
+      return SNMP_CLASS_INVALID_CALLBACK;
+
+    //---------[ make sure target is valid ]-------------------------
+    // make sure that the target is valid
+    if ( ! target.valid())
+      return SNMP_CLASS_INVALID_TARGET;
+
+    OctetStr community_string;
+    OctetStr security_name;
+    int security_model;
+    const CTarget* ctarget = NULL;
+    const UTarget* utarget = NULL;
+
+    switch (target.get_type())
+    {
+      case SnmpTarget::type_ctarget:
+        ctarget = (CTarget*)(&target);
+        break;
+      case SnmpTarget::type_utarget:
+        utarget = (UTarget*)(&target);
+        break;
+      case SnmpTarget::type_base:
+        debugprintf(0, "-- SNMP++, do not use SnmpTarget,"
+                    "use a  CTarget or UTarget");
+        return SNMP_CLASS_INVALID_TARGET;
+      default:
+        /* target is not known */
+        debugprintf(0, "-- SNMP++, type of target is unknown!");
+        return SNMP_CLASS_UNSUPPORTED;
+    }
+
+    if (ctarget) /* Is is a CTarget? */
+    {
+      debugprintf(3, "snmp_engine called with CTarget");
+      if (!ctarget->resolve_to_C( my_get_community, my_set_community,
+                                  address, my_timeout, my_retry, version))
+      {
+        debugprintf(0, "-- SNMP++, Resolve Fail (CTarget)");
+        return SNMP_CLASS_UNSUPPORTED;
+      }
+#ifdef _SNMPv3
+      if ((version == version3) ||
+          (action == sNMP_PDU_REPORT))
+      {
+        debugprintf(0, "-- SNMP++, use UTarget for SNMPv3");
+        return SNMP_CLASS_INVALID_TARGET;
+      }
+#endif
+      //----------[ use the appropriate community string ]-----------------
+      if (( action == sNMP_PDU_GET) ||
+          ( action == sNMP_PDU_GET_ASYNC) ||
+          ( action == sNMP_PDU_GETNEXT) ||
+          ( action == sNMP_PDU_GETNEXT_ASYNC) ||
+          ( action == sNMP_PDU_GETBULK) ||
+          ( action == sNMP_PDU_GETBULK_ASYNC) ||
+          ( action == sNMP_PDU_INFORM) ||
+          ( action == sNMP_PDU_INFORM_ASYNC) ||
+          ( action == sNMP_PDU_RESPONSE))
+        community_string = my_get_community;
+      else /* got to be a set */
+        community_string = my_set_community;
+    }
+    else if (utarget)  /* Is is a UTarget? */
+    {
+      debugprintf(3, "snmp_engine called with UTarget");
+      if (!utarget->resolve_to_U( security_name, security_model,
+                                  address, my_timeout,
+                                  my_retry, version))
+      {
+        debugprintf(0, "-- SNMP++, Resolve Fail (UTarget)");
+        return SNMP_CLASS_UNSUPPORTED;
+      }
+#ifdef _SNMPv3
+      if (version != version3)
+      {
+#endif
+        community_string = security_name;
+        if (((version == version1) && (security_model != SNMP_SECURITY_MODEL_V1)) ||
+           ((version == version2c) && (security_model != SNMP_SECURITY_MODEL_V2)))
+       {
+          LOG_BEGIN(ERROR_LOG | 1);
+          LOG("Snmp: Target does not match SNMP version: (security model) (version)");
+          LOG(security_model);
+          LOG(version);
+          LOG_END;
+
+          return SNMP_CLASS_INVALID_TARGET;
+        }
+#ifdef _SNMPv3
+      } // end if (version != version3)
+#endif
+    }
+    else
+    { // target is neither CTarget nor UTarget (should not happen)
+      debugprintf(0, "-- SNMP++, Resolve Fail");
+      return SNMP_CLASS_INVALID_TARGET;
+    }
+
+    if (!address.valid())
+    {
+      debugprintf(0, "-- SNMP++, Target contains invalid address");
+      return SNMP_CLASS_INVALID_TARGET;
+    }
+
+    //----------[ validate the target address ]--------------------------
+    if ((address.get_type() != Address::type_ip) &&
+        (address.get_type() != Address::type_udp) )
+    {
+      debugprintf(0, "-- SNMP++, Bad address type");
+      return SNMP_CLASS_TL_UNSUPPORTED;
+    }
+
+    UdpAddress udp_address(address);
+    if (!udp_address.valid())
+    {
+      debugprintf(0, "-- SNMP++, Bad address");
+      return SNMP_CLASS_RESOURCE_UNAVAIL;
+    }
+
+    //----------[ choose the target address port ]-----------------------
+    if ((address.get_type() == Address::type_ip) || !udp_address.get_port())
+    {
+      if (pdu_action == sNMP_PDU_INFORM)
+        udp_address.set_port(SNMP_TRAP_PORT);
+      else
+        udp_address.set_port(SNMP_PORT);
+    }
+    // otherwise port was already set
+
+    // check socket to use
+    SnmpSocket iv_session_used = fd;
+
+    if (fd == INVALID_SOCKET)
+    {
+#ifdef SNMP_PP_IPv6
+      if (udp_address.get_ip_version() == Address::version_ipv4)
+      {
+        if (iv_snmp_session != INVALID_SOCKET)
+         iv_session_used = iv_snmp_session;
+       else
+       {
+         udp_address.map_to_ipv6();
+         iv_session_used = iv_snmp_session_ipv6;
+       }
+      }
+      else
+       iv_session_used = iv_snmp_session_ipv6;
+#else
+      iv_session_used = iv_snmp_session;
+#endif
+    }
+
+    if ((pdu_action != sNMP_PDU_RESPONSE) &&
+        (pdu_action != sNMP_PDU_REPORT))
+    {
+      // set error index to none
+      pdu.set_error_index(0);
+
+      // determine request id to use
+      req_id = MyMakeReqId();
+      pdu.set_request_id(req_id);
+    }
+
+    //---------[ map GetBulk over v1 to GetNext ]-------------------------
+    if (( pdu_action == sNMP_PDU_GETBULK)&&( (snmp_version)version== version1))
+      pdu_action = sNMP_PDU_GETNEXT;
+    if ( pdu_action == sNMP_PDU_GETBULK) {
+      pdu.set_error_status((int) non_reps);
+      pdu.set_error_index((int) max_reps);
+    }
+
+    pdu.set_type( pdu_action);
+    SnmpMessage snmpmsg;
+
+#ifdef _SNMPv3
+    struct V3CallBackData *v3CallBackData = 0;
+
+    if (version == version3)
+    {
+      if (!utarget)
+      {
+        debugprintf(0, "-- SNMP++, need UTarget to send SNMPv3 message!");
+        return SNMP_CLASS_INVALID_TARGET;
+      }
+      OctetStr engine_id;
+      utarget->get_engine_id(engine_id);
+      if (engine_id.len() == 0)
+      {
+        if (v3MP::I->get_from_engine_id_table(engine_id,
+                                           (char*)udp_address.get_printable())
+            == SNMPv3_MP_OK )
+        {
+         // Override const here
+          ((UTarget*)utarget)->set_engine_id(engine_id);
+        }
+       else
+       {
+          // check if engine id discovery is enabled
+          if ((!v3MP::I->get_usm()->is_discovery_enabled()) &&
+              ((pdu_action == sNMP_PDU_GET) ||
+               (pdu_action == sNMP_PDU_SET) ||
+               (pdu_action == sNMP_PDU_GETNEXT) ||
+               (pdu_action == sNMP_PDU_GETBULK) ||
+               (pdu_action == sNMP_PDU_INFORM)))
+          {
+            // no engine id, discovery disabled and not authoritytive
+            LOG_BEGIN(ERROR_LOG | 1);
+            LOG("Not authoritative and discovery disabled. Target without engine id is invalid");
+            LOG_END;
+            return SNMP_CLASS_INVALID_TARGET;
+          }
+        }
+      }
+      // set context_engine_id of pdu, if it is not set
+      if (pdu.get_context_engine_id().len() == 0)
+      {
+        debugprintf(8, "Setting contextEngineID of Pdu to (%s)",
+                    engine_id.get_printable());
+        pdu.set_context_engine_id(engine_id);
+        backupPdu.set_context_engine_id(engine_id);
+      }
+
+      debugprintf(4,"Snmp::snmp_engine: engineID (%s), securityName (%s)"
+                  "securityModel (%i) security_level (%i)",
+                  engine_id.get_printable(), security_name.get_printable(),
+                  security_model, pdu.get_security_level());
+      debugprintf(4," Addr/Port (%s)",udp_address.get_printable());
+
+      status = snmpmsg.loadv3( pdu, engine_id, security_name,
+                               security_model, (snmp_version)version);
+    }
+    else
+#endif
+      status = snmpmsg.load( pdu, community_string,(snmp_version) version);
+
+    if ( status != SNMP_CLASS_SUCCESS)
+    {
+      debugprintf(0, "snmp message load error!");
+      return status;
+    }
+
+    // first add the message to the queue
+    if ((pdu_action != sNMP_PDU_RESPONSE) &&
+        (pdu_action != sNMP_PDU_REPORT))
+    {
+#ifdef _SNMPv3
+       if ((version == version3) && ((action == sNMP_PDU_GET_ASYNC) ||
+                                     (action == sNMP_PDU_SET_ASYNC) ||
+                                     (action == sNMP_PDU_GETNEXT_ASYNC) ||
+                                     (action == sNMP_PDU_GETBULK_ASYNC) ||
+                                     (action == sNMP_PDU_INFORM_ASYNC))) {
+           // add callback for v3
+           v3CallBackData = new struct V3CallBackData;
+
+           v3CallBackData->pdu = new Pdu(pdu);
+           v3CallBackData->pdu->set_type(backupPdu.get_type());
+           v3CallBackData->non_reps = non_reps;
+           v3CallBackData->max_reps = max_reps;
+
+           v3CallBackData->target = new UTarget(*utarget);
+           v3CallBackData->oldCallback = cb;
+           v3CallBackData->cbd = cbd;
+           v3CallBackData->reports_received = reports_received;
+
+           // Add the message to the message queue
+           eventListHolder->snmpEventList()->AddEntry(req_id, this, iv_session_used,
+                    target, pdu, snmpmsg.data(), (size_t) snmpmsg.len(),
+                    udp_address, v3CallBack, (void *)v3CallBackData);
+       }
+       else
+#endif
+       {
+           eventListHolder->snmpEventList()->AddEntry(req_id, this, iv_session_used,
+                    target, pdu, snmpmsg.data(), (size_t) snmpmsg.len(),
+                    udp_address, cb, (void *)cbd);
+       }
+    }
+
+    //------[ send the request ]
+    lock();
+    status = send_snmp_request(iv_session_used,
+                              snmpmsg.data(), (size_t) snmpmsg.len(),
+                              udp_address);
+    unlock();
+
+    if (status != 0)
+    {
+       if ((pdu_action != sNMP_PDU_RESPONSE) &&
+           (pdu_action != sNMP_PDU_REPORT))
+       {
+           // remove the id from message queue
+           eventListHolder->snmpEventList()->lock();
+           eventListHolder->snmpEventList()->DeleteEntry(req_id);
+           eventListHolder->snmpEventList()->unlock();
+
+#ifdef _SNMPv3
+           // dont forget to delete this
+           if (v3CallBackData) deleteV3Callback(v3CallBackData);
+#endif
+       }
+       return SNMP_CLASS_TL_FAILED;
+    }
+
+    if ((pdu_action == sNMP_PDU_RESPONSE) ||
+        (pdu_action == sNMP_PDU_REPORT))
+      return SNMP_CLASS_SUCCESS; // don't wait for an answer
+
+    //----[ if an async mode request then return success ]-----
+    if (( action == sNMP_PDU_GET_ASYNC) ||
+        ( action == sNMP_PDU_SET_ASYNC) ||
+        ( action == sNMP_PDU_GETNEXT_ASYNC) ||
+        ( action == sNMP_PDU_GETBULK_ASYNC) ||
+        ( action == sNMP_PDU_INFORM_ASYNC))
+      return SNMP_CLASS_SUCCESS;
+
+    // Now wait for the response (or timeout) for our message.
+    // This handles any necessary retries.
+    status = eventListHolder->SNMPBlockForResponse(req_id, pdu);
+
+    if (pdu.get_type() != REPORT_MSG) {
+#ifdef _SNMPv3
+      if (status == SNMPv3_MP_OK)
+        return SNMP_CLASS_SUCCESS;
+      else
+#endif
+        return status;
+    }
+#ifdef _SNMPv3
+    else
+      if (status == SNMPv3_USM_DECRYPTION_ERROR)
+        return status;
+
+    // We received a REPORT-MSG, check if we should try another time
+    Vb first_vb;
+    Oid first_oid;
+    pdu.get_vb(first_vb,0);
+    first_vb.get_oid(first_oid);
+
+    debugprintf(1,"received oid: %s with value: %s",
+                first_vb.get_printable_oid(), first_vb.get_printable_value());
+    debugprintf(1, "%s", error_msg(first_oid));
+
+    switch (maxloops)
+    {
+      case 0:
+      {
+       // This was our first try, so we may receive a unknown engine id 
+       // report or a not in time window report
+        if (first_oid == oidUsmStatsUnknownEngineIDs)
+        {
+         pdu = backupPdu; // restore pdu and try again
+         break;
+        }
+        else if (first_oid == oidUsmStatsNotInTimeWindows)
+        {
+          ++maxloops; // increase it, as the next request must succeed
+         pdu = backupPdu; // restore pdu and try again
+         break;
+        }
+        return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
+      }
+      case 1:
+      {
+       // This was the second try, engine id discovery should be ok
+       // so test only for not in time report
+        if (first_oid == oidUsmStatsNotInTimeWindows)
+        {
+         pdu = backupPdu; // restore pdu and try again
+         break;
+        }
+        return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
+      }
+      case 2:
+      {
+       // We tried three times: one for engine id discovery, one for
+       // time sync and we still get a report --> somethings wrong!
+        return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
+      }
+    }
+  }
+#endif
+  return status;
+}
+
+#ifdef _SNMPv3
+int Snmp::engine_id_discovery(OctetStr &engine_id,
+                             const int timeout_sec,
+                             const UdpAddress &addr)
+{
+  unsigned char *message;
+  int message_length;
+  SnmpSocket sock;
+  SnmpMessage snmpmsg;
+
+  unsigned char snmpv3_message[60] = {
+    0x30, 0x3a,
+          0x02, 0x01, 0x03,                   // Version: 3
+          0x30, 0x0f,                         // global header length 15
+                0x02, 0x03, 0x01, 0x00, 0x00, // message id
+                0x02, 0x02, 0x10, 0x00,       // message max size
+                0x04, 0x01, 0x04,             // flags (reportable set)
+                0x02, 0x01, 0x03,             // security model USM
+          0x04, 0x10,                         // security params
+                0x30, 0x0e,
+                      0x04, 0x00,             // no engine id
+                      0x02, 0x01, 0x00,       // boots 0
+                      0x02, 0x01, 0x00,       // time 0
+                      0x04, 0x00,             // no user name
+                      0x04, 0x00,             // no auth par
+                      0x04, 0x00,             // no priv par
+          0x30, 0x12,
+                0x04, 0x00,                   // no context engine id
+                0x04, 0x00,                   // no context name
+          0xa0, 0x0c,                         // GET PDU
+                0x02, 0x02, 0x34, 0x26,       // request id
+                0x02, 0x01, 0x00,             // error status no error
+                0x02, 0x01, 0x00,             // error index 0
+                0x30, 0x00                    // no data
+  };
+
+  message = (unsigned char *)snmpv3_message;
+  message_length = 60;
+
+  engine_id.clear();
+
+  UdpAddress uaddr(addr);
+
+#ifdef SNMP_PP_IPv6
+  if (uaddr.get_ip_version() == Address::version_ipv4)
+  {
+    if (iv_snmp_session != INVALID_SOCKET)
+      sock = iv_snmp_session;
+    else
+    {
+      uaddr.map_to_ipv6();
+      sock = iv_snmp_session_ipv6;
+    }
+  }
+  else
+    sock = iv_snmp_session_ipv6;
+#else
+  sock = iv_snmp_session;
+#endif
+
+  lock();
+  if (send_snmp_request(sock, message, message_length, uaddr) < 0)
+  {
+    debugprintf(0, "Error sending message.");
+    unlock();
+    return SNMP_CLASS_TL_FAILED;
+  }
+
+  // now wait for the responses
+  Pdu dummy_pdu;
+  int nfound = 0;
+  msec end_time;
+  struct timeval fd_timeout;
+
+  end_time += timeout_sec * 1000;
+
+#ifdef HAVE_POLL_SYSCALL
+  struct pollfd readfds;
+  int timeout;
+#else
+  fd_set readfds;
+#endif
+
+  do
+  {
+    bool something_to_receive = false;
+    end_time.GetDeltaFromNow(fd_timeout);
+
+#ifdef HAVE_POLL_SYSCALL
+    memset(&readfds, 0, sizeof(struct pollfd));
+    readfds.fd = sock;
+    readfds.events = POLLIN;
+    timeout = fd_timeout.tv_sec * 1000 + fd_timeout.tv_usec / 1000;
+    nfound = poll(&readfds, 1, timeout);
+    if ((nfound > 0) && (readfds.revents & POLLIN))
+       something_to_receive = true;
+#else
+    FD_ZERO(&readfds);
+    FD_SET(sock, &readfds);
+
+    nfound = select((int)(sock + 1), &readfds, NULL, NULL, &fd_timeout);
+    if ((nfound > 0) && (FD_ISSET(sock, &readfds)))
+       something_to_receive = true;
+#endif
+
+    if (something_to_receive)
+    {
+      // receive message
+      UdpAddress from;
+      int res = receive_snmp_response(sock, *this, dummy_pdu,
+                                     from, engine_id, true /* process_msg */);
+      if ((res == SNMP_CLASS_SUCCESS) ||
+         (res == SNMPv3_MP_UNKNOWN_PDU_HANDLERS))
+      {
+         //dummy_pdu.get_context_engine_id(engine_id);
+       debugprintf(3, "Response received from (%s) id %s.",
+                   from.get_printable(), engine_id.get_printable());
+       unlock();
+       return SNMP_CLASS_SUCCESS;
+      }
+      else
+      {
+       debugprintf(0, "Error receiving discovery response.");
+      }
+    }
+  } while ((nfound > 0) ||
+          (fd_timeout.tv_sec > 0) || (fd_timeout.tv_usec > 0));
+  unlock();
+
+  return SNMP_CLASS_TIMEOUT;
+}
+#endif
+
+// Send a SNMP Broadcast message.
+int Snmp::broadcast_discovery(UdpAddressCollection &addresses,
+                             const int timeout_sec,
+                             const UdpAddress &addr,
+                             const snmp_version version,
+                             const OctetStr *community)
+{
+  unsigned char *message;
+  int message_length;
+  SnmpSocket sock;
+  SnmpMessage snmpmsg;
+
+#ifdef _SNMPv3
+  unsigned char snmpv3_broadcast_message[60] = {
+    0x30, 0x3a,
+          0x02, 0x01, 0x03,                   // Version: 3
+          0x30, 0x0f,                         // global header length 15
+                0x02, 0x03, 0x01, 0x00, 0x00, // message id
+                0x02, 0x02, 0x10, 0x00,       // message max size
+                0x04, 0x01, 0x04,             // flags (reportable set)
+                0x02, 0x01, 0x03,             // security model USM
+          0x04, 0x10,                         // security params
+                0x30, 0x0e,
+                      0x04, 0x00,             // no engine id
+                      0x02, 0x01, 0x00,       // boots 0
+                      0x02, 0x01, 0x00,       // time 0
+                      0x04, 0x00,             // no user name
+                      0x04, 0x00,             // no auth par
+                      0x04, 0x00,             // no priv par
+          0x30, 0x12,
+                0x04, 0x00,                   // no context engine id
+                0x04, 0x00,                   // no context name
+          0xa0, 0x0c,                         // GET PDU
+                0x02, 0x02, 0x34, 0x26,       // request id
+                0x02, 0x01, 0x00,             // error status no error
+                0x02, 0x01, 0x00,             // error index 0
+                0x30, 0x00                    // no data
+  };
+
+  if (version == version3)
+  {
+    message = (unsigned char *)snmpv3_broadcast_message;
+    message_length = 60;
+  }
+  else
+#endif
+  {
+    Pdu pdu;
+    Vb vb;
+    OctetStr get_community;
+
+    vb.set_oid("1.3.6.1.2.1.1.1.0");
+    pdu +=vb;
+    pdu.set_error_index(0);            // set error index to none
+    pdu.set_request_id(MyMakeReqId()); // determine request id to use
+    pdu.set_type(sNMP_PDU_GET);        // set pdu type
+
+    if (community)
+      get_community = *community;
+    else
+      get_community = "public";
+
+    int status = snmpmsg.load(pdu, get_community, version);
+    if (status != SNMP_CLASS_SUCCESS)
+    {
+      debugprintf(0, "Error encoding broadcast pdu (%i).", status);
+      return status;
+    }
+    message        = snmpmsg.data();
+    message_length = snmpmsg.len();
+  }
+
+  UdpAddress uaddr(addr);
+
+#ifdef SNMP_PP_IPv6
+  if (uaddr.get_ip_version() == Address::version_ipv4)
+  {
+    if (iv_snmp_session != INVALID_SOCKET)
+      sock = iv_snmp_session;
+    else
+    {
+      uaddr.map_to_ipv6();
+      sock = iv_snmp_session_ipv6;
+    }
+  }
+  else
+    sock = iv_snmp_session_ipv6;
+#else
+  sock = iv_snmp_session;
+#endif
+
+  lock();
+  if (send_snmp_request(sock, message, message_length, uaddr) < 0)
+  {
+    debugprintf(0, "Error sending broadast.");
+    unlock();
+    return SNMP_CLASS_TL_FAILED;
+  }
+
+  // now wait for the responses
+  Pdu dummy_pdu;
+  OctetStr engine_id;
+  int nfound = 0;
+  msec end_time;
+  struct timeval fd_timeout;
+
+  end_time += timeout_sec * 1000;
+
+#ifdef HAVE_POLL_SYSCALL
+  struct pollfd readfds;
+  int timeout;
+#else
+  fd_set readfds;
+#endif
+
+  do
+  {
+    bool something_to_receive = false;
+    end_time.GetDeltaFromNow(fd_timeout);
+
+#ifdef HAVE_POLL_SYSCALL
+    memset(&readfds, 0, sizeof(struct pollfd));
+    readfds.fd = sock;
+    readfds.events = POLLIN;
+    timeout = fd_timeout.tv_sec * 1000 + fd_timeout.tv_usec / 1000;
+    nfound = poll(&readfds, 1, timeout);
+    if ((nfound > 0) && (readfds.revents & POLLIN))
+       something_to_receive = true;
+#else
+    FD_ZERO(&readfds);
+    FD_SET(sock, &readfds);
+
+    nfound = select((int)(sock + 1), &readfds, NULL, NULL, &fd_timeout);
+    if ((nfound > 0) && (FD_ISSET(sock, &readfds)))
+       something_to_receive = true;
+#endif
+
+    if (something_to_receive)
+    {
+      // receive message
+      UdpAddress from;
+      if (receive_snmp_response(sock, *this, dummy_pdu,
+                               from, engine_id, false /* process_msg */)
+         == SNMP_CLASS_SUCCESS)
+      {
+       addresses += from;
+      }
+      else
+      {
+       debugprintf(0, "Error receiving broadcast response.");
+      }
+    }
+  } while ((nfound > 0) ||
+          (fd_timeout.tv_sec > 0) || (fd_timeout.tv_usec > 0));
+  unlock();
+
+#ifdef __DEBUG
+  for (int i=0; i < addresses.size(); ++i)
+  {
+    debugprintf(3, "Broadcast response received from (%s).",
+               addresses[i].get_printable());
+  }
+#endif
+  return 0;
+}
+
+//     Starts the working thread for the recovery of the pending events
+bool Snmp::start_poll_thread(const int timeout)
+{
+#ifdef _THREADS        
+    // store the timeout value for later
+    m_iPollTimeOut = timeout;
+
+    // if we are already running return ok
+    if (m_bThreadRunning == true) return true;
+
+    // since we are here, things must be fine so far...
+    m_bThreadRunning = true;
+
+    // start the ProcessThread function....
+#ifdef WIN32
+    DWORD id;
+    m_hThread = CreateThread(NULL, 0,
+                      (LPTHREAD_START_ROUTINE)&Snmp::process_thread,
+                      this, 0, &id);
+    if (m_hThread == NULL)
+    {
+        debugprintf(0, "Could not create ProcessThread");
+       m_bThreadRunning = false;
+    }
+#elif defined (CPU) && CPU == PPC603
+       m_hThread = taskSpawn("Snmp::process_thread",  0, 0, 10000, (int (*)(...))Snmp::process_thread,  (int)this, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+    if (m_hThread == ERROR)
+    {
+       // Could not create thread.
+        debugprintf(0, "Could not create ProcessThread");
+       m_bThreadRunning = false;
+    }
+#else
+    int rc = pthread_create(&m_hThread, NULL, Snmp::process_thread,
+                           (void*) this);
+    if (rc)
+    {
+       // Could not create thread.
+        debugprintf(0, "Could not create ProcessThread");
+       m_bThreadRunning = false;
+    }
+#endif
+#endif
+    return m_bThreadRunning;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//     stop_poll_thread
+//     Stops the recovery of the pending events
+//
+///////////////////////////////////////////////////////////////////////////////
+void Snmp::stop_poll_thread()
+{
+    if (m_bThreadRunning == false) return;
+
+#ifdef _THREADS
+    // stop the thread
+    m_bThreadRunning = false;
+
+    // Wait for the working thread to stop....
+#ifdef WIN32
+    ::WaitForSingleObject(m_hThreadEndEvent, INFINITE);
+    CloseHandle(m_hThread);
+#elif defined (CPU) && CPU == PPC603
+    while (taskIdVerify(m_hThread) == OK)
+       taskDelay(10);
+#else
+    //int *status; // not used
+    pthread_join(m_hThread, NULL /*(void**) &status */); 
+#endif
+#endif
+}
+
+#ifdef WIN32
+int Snmp::process_thread(Snmp *pSnmp)
+{
+#else
+void* Snmp::process_thread(void *arg)
+{
+    Snmp* pSnmp = (Snmp*) arg;
+#endif // !WIN32
+
+    // Loop as long as we haven't stopped
+    while (pSnmp->is_running())
+    {
+       pSnmp->eventListHolder
+            ->SNMPProcessEvents(pSnmp->m_iPollTimeOut);
+    }
+
+#ifdef _THREADS
+#ifdef WIN32
+    ::SetEvent(pSnmp->m_hThreadEndEvent);
+#else
+#if defined (CPU) && CPU == PPC603
+       exit(0);
+#else
+    pthread_exit(0);
+#endif
+#endif
+#endif
+    return 0;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/v3.cpp b/3rdparty/snmp++/src/v3.cpp
new file mode 100644 (file)
index 0000000..070631c
--- /dev/null
@@ -0,0 +1,442 @@
+/*_############################################################################
+  _## 
+  _##  v3.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+
+char v3_cpp_version[]="#(@) SNMP++ $Id: v3.cpp 274 2006-11-03 19:21:16Z katz $";
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _MSC_VER
+#ifndef __BCPLUSPLUS__
+#include <unistd.h>
+#endif
+#endif
+
+#include "snmp_pp/log.h"
+#include "snmp_pp/v3.h"
+#include "snmp_pp/octet.h"
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define MAX_LINE_LEN 100
+
+const char *logfilename = NULL;
+int debug_level = 19;
+
+// Set the amount of log messages you want to get.
+void debug_set_level(const int db_level)
+{
+  debug_level = db_level;
+}
+
+#ifdef _DEBUG
+
+void debughexcprintf(int db_level, const char *comment,
+                     const unsigned char *data, const unsigned int len)
+{
+    if (db_level > debug_level) return;
+
+    char *buf = new char[MAX_LOG_SIZE];
+
+    if (NULL == buf) return;   // not good!
+
+    if (comment && (strlen(comment) < MAX_LOG_SIZE - 25))
+    {
+       sprintf(buf, "%s (length %i): \n", comment, len);
+       LOG_BEGIN(DEBUG_LOG | 3);
+       LOG(buf);
+       LOG_END;
+    }
+
+    char *tmp = new char[4];
+
+    if (NULL == tmp) { delete [] buf ; return; }
+
+    buf[0] = '\0';
+    for (unsigned int i=0; i<len; i++)
+    {
+       sprintf(tmp, "%02X ", data[i]);
+       strcat(buf, tmp);
+
+       if ((i+1)%4==0)
+       {
+           sprintf(tmp, " ");
+           strcat(buf, tmp);
+       }
+
+       if ((i+1)%16==0)
+       {
+           LOG_BEGIN(DEBUG_LOG | 3);
+           LOG(buf);
+           LOG_END;
+
+           // reset the buf
+           buf[0] = '\0';
+       }
+    }
+
+    if (buf[0] != '\0')
+    {
+       // print the last part of the message
+       LOG_BEGIN(DEBUG_LOG | 3);
+       LOG(buf);
+       LOG_END;
+    }
+
+    // and cleanup...
+    delete [] tmp;
+    delete [] buf;
+}
+
+void debugprintf(int db_level, const char *format, ...)
+{
+    if (db_level > debug_level) return;
+
+    va_list  args;
+
+    va_start(args, format);
+
+/////////////////////////////////////////////////////////////////
+//     NOTE: This would be the best way to go (by using _vscprintf), 
+//     but it is part of the VC7.0, and it can't be used in VC6.0
+/////////////////////////////////////////////////////////////////
+       // _vscprintf doesn't count terminating '\0' so we add one more
+//     int len = _vscprintf( format, args ) + 1;
+
+    char *buf = new char[MAX_LOG_SIZE];
+
+    if (NULL == buf) return; // not good!
+
+    vsprintf(buf, format, args);
+
+    va_end(args);
+
+    LOG_BEGIN(DEBUG_LOG | 1);
+    LOG(buf);
+    LOG_END;
+
+    // and cleanup...
+    delete [] buf;
+}
+
+#else
+#if (defined (__STRICT_ANSI__) || !defined (__GNUC__)) && !defined (_MSC_VER)
+void debugprintf(int, const char*, ...)
+{
+}
+#endif
+
+#endif
+
+#ifdef _SNMPv3
+
+unsigned char *v3strcpy(const unsigned char *src, const int srclen)
+{
+  unsigned char *res = new unsigned char[srclen+1];
+  if (!res) return NULL;
+  memcpy(res, src, srclen);
+  res[srclen] = '\0';
+  return res;
+}
+
+
+int unsignedCharCompare(const unsigned char *str1, const long int ptr1len,
+                        const unsigned char *str2, const long int ptr2len)
+{
+  if (ptr1len != ptr2len) return 0;
+
+  const unsigned char *ptr1 = str1;
+  const unsigned char *ptr2 = str2;
+
+  for (int i=0; i < ptr1len; ++i)
+    if (*ptr1++ != *ptr2++) return 0;
+
+  return 1;
+}
+
+// Encode the given string into the output buffer.
+void encodeString(const unsigned char* in, const int in_length, char* out)
+{
+  char* out_ptr = out;
+  const unsigned char* in_ptr = in;
+
+  for (int i=0; i<in_length; i++)
+  {
+    *out_ptr++ = 64 + ((*in_ptr >> 4) & 0xF);
+    *out_ptr++ = 64 + (*in_ptr++ & 0xF);
+  }
+}
+
+// Decode the given encoded string into the output buffer.
+void decodeString(const unsigned char* in, const int in_length, char* out)
+{
+  char* out_ptr = out;
+  const unsigned char* in_ptr = in;
+
+  if ((in_length % 2) || (in_length < 0))
+  {
+    LOG_BEGIN(WARNING_LOG | 3);
+    LOG("decodeString: Illegal input length (len)");
+    LOG(in_length);
+    LOG_END;
+
+    *out = 0;
+    return;
+  }
+
+  for (int i= in_length / 2; i > 0; i--)
+  {
+    *out_ptr = (*in_ptr++ & 0xF) << 4;
+    *out_ptr++ |= (*in_ptr++ & 0xF);
+  }
+  *out_ptr = 0; // make sure it is null terminated
+}
+
+// Read the bootCounter of the given engineID stored in the given file.
+int getBootCounter(const char *fileName,
+                   const OctetStr &engineId, unsigned int &boot)
+{
+  char line[MAX_LINE_LEN];
+  char encoded[MAXLENGTH_ENGINEID * 2 + 2];
+  int len = engineId.len();
+
+  FILE *file;
+
+  boot = 0;
+  file = fopen(fileName, "r");
+
+  if (!file)
+  {
+    LOG_BEGIN(ERROR_LOG | 1);
+    LOG("getBootCounter: Could not open (file)");
+    LOG(fileName);
+    LOG_END;
+
+    return SNMPv3_FILEOPEN_ERROR;
+  }
+
+  if (len > MAXLENGTH_ENGINEID)
+  {
+    LOG_BEGIN(ERROR_LOG | 3);
+    LOG("getBootCounter: engine id too long, ignoring last bytes (len) (max)");
+    LOG(len);
+    LOG(MAXLENGTH_ENGINEID);
+    LOG_END;
+
+    len = MAXLENGTH_ENGINEID;
+  }
+
+  encodeString(engineId.data(), len, encoded);
+  encoded[2*len]=' ';
+  encoded[2*len + 1] = 0;
+
+  while (fgets(line, MAX_LINE_LEN, file))
+  {
+    line[MAX_LINE_LEN - 1] = 0;
+    /* ignore comments */
+    if (line[0]=='#')
+      continue;
+
+    if (!strncmp(encoded, line, len*2 + 1))
+    {
+      /* line starts with engineId */
+      char* ptr = line;
+      /* skip until first space */
+      while (*ptr != 0 && *ptr != ' ')
+        ptr++;
+
+      if (*ptr == 0)
+      {
+        fclose(file);
+
+        LOG_BEGIN(ERROR_LOG | 3);
+        LOG("getBootCounter: Illegal line: (file) (line)");
+        LOG(fileName);
+        LOG(line);
+        LOG_END;
+
+        return SNMPv3_FILE_ERROR;
+      }
+      boot = atoi(ptr);
+      fclose(file);
+
+      LOG_BEGIN(DEBUG_LOG | 3);
+      LOG("getBootCounter: found entry (file) (engine id) (boot counter)");
+      LOG(fileName);
+      LOG(engineId.get_printable());
+      LOG(boot);
+      LOG_END;
+
+      return SNMPv3_OK;
+    }
+  }
+  fclose(file);
+
+  LOG_BEGIN(WARNING_LOG | 3);
+  LOG("getBootCounter: No entry found (file) (engine id)");
+  LOG(fileName);
+  LOG(engineId.get_printable());
+  LOG_END;
+
+  return SNMPv3_NO_ENTRY_ERROR;
+}
+
+// Store the bootCounter of the given engineID in the given file.
+int saveBootCounter(const char *fileName,
+                    const OctetStr &engineId, const unsigned int boot)
+{
+  char line[MAX_LINE_LEN];
+  char tmpFileName[MAXLENGTH_FILENAME];
+  char encoded[MAXLENGTH_ENGINEID * 2 + 2];
+  int found = FALSE;
+  int len = engineId.len();
+  FILE *file_in, *file_out;
+
+  tmpFileName[0] = 0;
+  sprintf(tmpFileName, "%s.tmp",fileName);
+  if (len > MAXLENGTH_ENGINEID)
+  {
+    LOG_BEGIN(ERROR_LOG | 3);
+    LOG("saveBootCounter: engine id too long, ignoring last bytes (len) (max)");
+    LOG(len);
+    LOG(MAXLENGTH_ENGINEID);
+    LOG_END;
+
+    len = MAXLENGTH_ENGINEID;
+  }
+
+  file_in = fopen(fileName, "r");
+  if (!file_in)
+  {
+    file_in = fopen(fileName, "w");
+    if (!file_in)
+    {
+      LOG_BEGIN(ERROR_LOG | 3);
+      LOG("saveBootCounter: could not create new file (file)");
+      LOG(fileName);
+      LOG_END;
+
+      return SNMPv3_FILECREATE_ERROR;
+    }
+
+    LOG_BEGIN(INFO_LOG | 3);
+    LOG("saveBootCounter: created new file (file)");
+    LOG(fileName);
+    LOG_END;
+
+    fputs("# \n",file_in);
+    fputs("# This file was created by an SNMP++v3 application,\n", file_in);
+    fputs("# it is used to store the snmpEngineBoots counters.\n", file_in);
+    fputs("# \n",file_in);
+    fputs("# Lines starting with '#' are comments.\n", file_in);
+    fputs("# The snmpEngineBoots counters are stored as\n", file_in);
+    fputs("# <encoded snmpEngineId> <bootCounter>\n", file_in);
+    fputs("# \n", file_in);
+    fclose(file_in);
+    file_in = fopen(fileName, "r");
+  }
+
+  file_out = fopen(tmpFileName, "w");
+
+  if ((file_in) && (file_out))
+  {
+    encodeString(engineId.data(), len, encoded);
+    encoded[len*2] = ' ';
+    encoded[len*2 + 1] = 0;
+
+    while (fgets(line, MAX_LINE_LEN, file_in))
+    {
+      line[MAX_LINE_LEN - 1] = 0;
+      if (!strncmp(encoded, line, len*2 + 1))
+      {
+        if (found)
+        {
+          LOG_BEGIN(WARNING_LOG | 3);
+          LOG("saveBootCounter: Removing doubled entry (file) (line)");
+          LOG(fileName);
+          LOG(line);
+          LOG_END;
+
+          continue;
+        }
+        sprintf(line,"%s%i\n", encoded, boot);
+        fputs(line, file_out);
+        found = TRUE;
+        continue;
+      }
+      fputs(line, file_out);
+    }
+    if (!found)
+    {
+      sprintf(line, "%s%i\n", encoded, boot);
+      fputs(line, file_out);
+    }
+    fclose(file_in);
+    fclose(file_out);
+#ifdef WIN32
+    _unlink(fileName);
+#endif
+    if (rename(tmpFileName, fileName))
+    {
+      LOG_BEGIN(ERROR_LOG | 1);
+      LOG("saveBootCounter: Failed to rename temporary file (tmp file) (file)");
+      LOG(tmpFileName);
+      LOG(fileName);
+      LOG_END;
+
+      return SNMPv3_FILERENAME_ERROR;
+    }
+
+    LOG_BEGIN(INFO_LOG | 5);
+    LOG("saveBootCounter: Saved counter (file) (engine id) (boot)");
+    LOG(fileName);
+    LOG(engineId.get_printable());
+    LOG(boot);
+    LOG_END;
+
+    return SNMPv3_OK;
+  }
+
+  LOG_BEGIN(ERROR_LOG | 1);
+  LOG("saveBootCounter: Failed to open both files (file) (tmp file)");
+  LOG(fileName);
+  LOG(tmpFileName);
+  LOG_END;
+
+  return SNMPv3_FILEOPEN_ERROR;
+}
+
+#endif
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/3rdparty/snmp++/src/vb.cpp b/3rdparty/snmp++/src/vb.cpp
new file mode 100644 (file)
index 0000000..9722d80
--- /dev/null
@@ -0,0 +1,378 @@
+/*_############################################################################
+  _## 
+  _##  vb.cpp  
+  _##
+  _##  SNMP++v3.2.25
+  _##  -----------------------------------------------
+  _##  Copyright (c) 2001-2010 Jochen Katz, Frank Fock
+  _##
+  _##  This software is based on SNMP++2.6 from Hewlett Packard:
+  _##  
+  _##    Copyright (c) 1996
+  _##    Hewlett-Packard Company
+  _##  
+  _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  _##  Permission to use, copy, modify, distribute and/or sell this software 
+  _##  and/or its documentation is hereby granted without fee. User agrees 
+  _##  to display the above copyright notice and this license notice in all 
+  _##  copies of the software and any documentation of the software. User 
+  _##  agrees to assume all liability for the use of the software; 
+  _##  Hewlett-Packard and Jochen Katz make no representations about the 
+  _##  suitability of this software for any purpose. It is provided 
+  _##  "AS-IS" without warranty of any kind, either express or implied. User 
+  _##  hereby grants a royalty-free license to any and all derivatives based
+  _##  upon this software code base. 
+  _##  
+  _##  Stuttgart, Germany, Thu Sep  2 00:07:47 CEST 2010 
+  _##  
+  _##########################################################################*/
+/*===================================================================
+
+  Copyright (c) 1999
+  Hewlett-Packard Company
+
+  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
+  Permission to use, copy, modify, distribute and/or sell this software
+  and/or its documentation is hereby granted without fee. User agrees
+  to display the above copyright notice and this license notice in all
+  copies of the software and any documentation of the software. User
+  agrees to assume all liability for the use of the software; Hewlett-Packard
+  makes no representations about the suitability of this software for any
+  purpose. It is provided "AS-IS" without warranty of any kind,either express
+  or implied. User hereby grants a royalty-free license to any and all
+  derivatives based upon this software code base.
+
+
+  V B . C P P
+
+  VARIABLE BINDING CLASS IMPLEMENTATION
+
+  DESCRIPTION:
+  This module contains the class implementation of the VB class.
+  The Vb class is an encapsulation of the snmp variable binding.
+
+  DESIGN + AUTHOR:  Peter E Mellquist
+=====================================================================*/
+char vb_cpp_version[]="#(@) SNMP++ $Id: vb.cpp 341 2008-08-29 21:37:48Z katz $";
+
+#include "snmp_pp/vb.h"            // include vb class defs
+
+#ifdef SNMP_PP_NAMESPACE
+namespace Snmp_pp {
+#endif
+
+#define IP_ADDR_SIZE  4
+#define IPX_ADDR_SIZE 10
+#define MAC_ADDR_SIZE 6
+
+//--------------[ Vb::valid() ]-----------------------------------------
+// returns validity of a Vb object
+// must have a valid oid and value
+bool Vb::valid() const
+{
+  if (iv_vb_oid.valid() &&
+#ifdef WHEN_WE_HAVE_SNMPNULL_CLASS
+      iv_vb_value && iv_vb_value->valid()
+#else
+      ((iv_vb_value == NULL) || (iv_vb_value && iv_vb_value->valid()))
+#endif
+    )
+    return true;
+  return false;
+}
+
+//---------------[ Vb& Vb::operator=(const Vb &vb) ]--------------------
+// overloaded assignment allows assigning one Vb to another
+// this involves deep memory thus target vb needs to be freed
+// before assigning source
+Vb& Vb::operator=(const Vb &vb)
+{
+  if (this == &vb) return *this;  // check for self assignment
+
+  free_vb(); // free up target to begin with
+
+  //-----[ reassign the Oid portion 1st ]
+  vb.get_oid(iv_vb_oid);
+
+  //-----[ next set the vb value portion ]
+  if (vb.iv_vb_value)
+    iv_vb_value = vb.iv_vb_value->clone();
+
+  exception_status = vb.exception_status;
+
+  return *this; // return self reference
+}
+
+//----------------[ void Vb::free_vb() ]--------------------------------
+// protected method to free memory
+// this method is used to free memory when assigning new vbs
+// or destructing
+// in the case of oids and octets, we need to do a deep free
+void Vb::free_vb()
+{
+  if (iv_vb_value)
+  {
+    delete iv_vb_value;
+    iv_vb_value = NULL;
+  }
+  exception_status = SNMP_CLASS_SUCCESS;
+}
+
+//---------------------[ Vb::get_value(int &i) ]----------------------
+// get value int
+// returns 0 on success and value
+int Vb::get_value(int &i) const
+{
+   if (iv_vb_value &&
+       iv_vb_value->valid() &&
+       (iv_vb_value->get_syntax() == sNMP_SYNTAX_INT32 ))
+   {
+     long lval;
+     lval = *((SnmpInt32 *)iv_vb_value);// SnmpInt32 includes cast to long,
+     i = (int) lval;                    // but not to int.
+     return SNMP_CLASS_SUCCESS;
+   }
+   return SNMP_CLASS_INVALID;
+}
+
+// get the unsigned int
+// returns 0 on success and a value
+int Vb::get_value(unsigned int &i) const
+{
+  if (iv_vb_value &&
+      iv_vb_value->valid() &&
+      ((iv_vb_value->get_syntax() == sNMP_SYNTAX_UINT32 ) ||
+       (iv_vb_value->get_syntax() == sNMP_SYNTAX_CNTR32 ) ||
+       (iv_vb_value->get_syntax() == sNMP_SYNTAX_GAUGE32 ) ||
+       (iv_vb_value->get_syntax() == sNMP_SYNTAX_TIMETICKS )))
+  {
+    unsigned long lval;
+    lval = *((SnmpUInt32 *)iv_vb_value);
+    i = (unsigned int)lval;
+    return SNMP_CLASS_SUCCESS;
+  }
+  return SNMP_CLASS_INVALID;
+}
+
+
+//--------------[ Vb::get_value(long int &i) ]-------------------------
+// get the signed long int
+// returns 0 on success and a value
+int Vb::get_value(long &i) const
+{
+   if (iv_vb_value &&
+       iv_vb_value->valid() &&
+       (iv_vb_value->get_syntax() == sNMP_SYNTAX_INT32 ))
+   {
+     i = *((SnmpInt32 *)iv_vb_value);  // SnmpInt32 includes cast to long
+     return SNMP_CLASS_SUCCESS;
+   }
+   return SNMP_CLASS_INVALID;
+}
+
+
+//-----------------[  Vb::get_value(unsigned long int &i) ]--------------
+// get the unsigned long int
+// returns 0 on success and a value
+int Vb::get_value(unsigned long &i) const
+{
+  if (iv_vb_value &&
+      iv_vb_value->valid() &&
+      ((iv_vb_value->get_syntax() == sNMP_SYNTAX_UINT32 ) ||
+       (iv_vb_value->get_syntax() == sNMP_SYNTAX_CNTR32 ) ||
+       (iv_vb_value->get_syntax() == sNMP_SYNTAX_GAUGE32 ) ||
+       (iv_vb_value->get_syntax() == sNMP_SYNTAX_TIMETICKS )))
+  {
+    i = *((SnmpUInt32 *)iv_vb_value);  // SnmpUint32 has includes to ulong
+    return SNMP_CLASS_SUCCESS;
+  }
+  return SNMP_CLASS_INVALID;
+}
+
+
+//--------------[ Vb::get_value(unsigned char WINFAR * ptr, unsigned long &len)
+// get a unsigned char string value
+// destructive, copies into given ptr
+// also returned is the length
+//
+// Note!! The user must provide a target string
+// which is big enough to hold the string
+int Vb::get_value(unsigned char *ptr, unsigned long &len) const
+{
+  if (iv_vb_value &&
+      iv_vb_value->valid() &&
+      (iv_vb_value->get_syntax() == sNMP_SYNTAX_OCTETS))
+  {
+    OctetStr *p_os = (OctetStr *)iv_vb_value;
+    len = p_os->len();
+    memcpy(ptr, p_os->data(), len);
+    ptr[len] = 0;
+    return SNMP_CLASS_SUCCESS;
+  }
+
+  if (ptr) ptr[0] = 0;
+  len = 0;
+  return SNMP_CLASS_INVALID;
+}
+
+//---------------[ Vb::get_value ]-------------------------------------
+// get an unsigned char array
+// caller specifies max len of target space
+int Vb::get_value(unsigned char *ptr, unsigned long &len,
+                 const unsigned long maxlen,
+                 const bool add_null_byte) const
+{
+  if (iv_vb_value &&
+      iv_vb_value->valid() &&
+      (iv_vb_value->get_syntax() == sNMP_SYNTAX_OCTETS) &&
+      (maxlen > 0))
+  {
+    OctetStr *p_os = (OctetStr *)iv_vb_value;
+    len = p_os->len();
+    if (len > maxlen) len = maxlen;
+    memcpy(ptr, p_os->data(), len);
+    if (add_null_byte)
+    {
+      if (len == maxlen)
+       ptr[len-1] = 0;
+      else
+       ptr[len] = 0;
+    }
+    return SNMP_CLASS_SUCCESS;
+  }
+
+  if (ptr) ptr[0] = 0;
+  len = 0;
+  return SNMP_CLASS_INVALID;
+}
+
+
+//---------------[ Vb::get_value(Value &val) ]--------
+int Vb::get_value(SnmpSyntax &val) const
+{
+  if (iv_vb_value)
+  {
+    val = *iv_vb_value;
+    if (val.valid())
+      return SNMP_CLASS_SUCCESS;
+    return SNMP_CLASS_INVALID;
+  }
+  // TM: should set val to be invalid
+  return SNMP_CLASS_INVALID;
+}
+
+//--------------[ Vb::get_value(char WINFAR *ptr) ]-------------------
+// get a char * from an octet string
+// the user must provide space or
+// memory will be stepped on
+int Vb::get_value(char *ptr) const
+{
+  if (iv_vb_value &&
+      iv_vb_value->valid() &&
+      (iv_vb_value->get_syntax() == sNMP_SYNTAX_OCTETS))
+  {
+    OctetStr *p_os = (OctetStr *)iv_vb_value;
+    unsigned long len = p_os->len();
+    memcpy(ptr, p_os->data(), len);
+    ptr[len] = 0;
+    return SNMP_CLASS_SUCCESS;
+  }
+
+  if (ptr) ptr[0] = 0;
+  return SNMP_CLASS_INVALID;
+}
+
+
+
+//-----[ misc]--------------------------------------------------------
+
+// return the current syntax
+// This method violates Object Orientation but may be useful if
+// the caller has a vb object and does not know what it is.
+// This would be useful in the implementation of a browser.
+SmiUINT32 Vb::get_syntax() const
+{
+  if (exception_status != SNMP_CLASS_SUCCESS)
+    return exception_status;
+  else
+    return (iv_vb_value ? iv_vb_value->get_syntax() : sNMP_SYNTAX_NULL);
+}
+
+void Vb::set_syntax(const SmiUINT32 syntax)
+{
+       free_vb(); // setting to SNMP_SYNTAX_NULL
+
+       exception_status = SNMP_CLASS_SUCCESS;
+
+       switch (syntax) {
+       case sNMP_SYNTAX_INT32:
+               iv_vb_value = new SnmpInt32();
+               break;
+       case sNMP_SYNTAX_TIMETICKS:
+               iv_vb_value = new TimeTicks();
+               break;
+       case sNMP_SYNTAX_CNTR32:
+               iv_vb_value = new Counter32();
+               break;
+       case sNMP_SYNTAX_GAUGE32:
+               iv_vb_value = new Gauge32();
+               break;
+/* Not distinguishable from Gauge32
+       case sNMP_SYNTAX_UINT32:
+               iv_vb_value = new SnmpUInt32();
+               break;
+*/
+       case sNMP_SYNTAX_CNTR64:
+               iv_vb_value = new Counter64();
+               break;
+       case sNMP_SYNTAX_BITS:
+       case sNMP_SYNTAX_OCTETS:
+               iv_vb_value = new OctetStr();
+               break;
+       case sNMP_SYNTAX_OPAQUE:
+               iv_vb_value = new OpaqueStr();
+               break;
+       case sNMP_SYNTAX_IPADDR:
+               iv_vb_value = new IpAddress();
+               break;
+       case sNMP_SYNTAX_OID:
+               iv_vb_value = new Oid();
+               break;
+       case sNMP_SYNTAX_NULL:
+               break;
+       case sNMP_SYNTAX_NOSUCHINSTANCE:
+               exception_status = sNMP_SYNTAX_NOSUCHINSTANCE;
+               break;
+       case sNMP_SYNTAX_NOSUCHOBJECT:
+               exception_status = sNMP_SYNTAX_NOSUCHOBJECT;
+               break;
+       case sNMP_SYNTAX_ENDOFMIBVIEW:
+               exception_status = sNMP_SYNTAX_ENDOFMIBVIEW;
+               break;
+       case sNMP_SYNTAX_SEQUENCE:
+               break;
+       }
+}
+
+static char blank_string[] = "";
+
+// return the printabel value
+const char WINFAR *Vb::get_printable_value() const
+{
+  if (iv_vb_value)
+    return iv_vb_value->get_printable();
+  return blank_string;
+}
+
+int Vb::get_asn1_length() const
+{
+  // Header for vbs is always 4 Bytes! FIXME
+  if (iv_vb_value)
+    return iv_vb_oid.get_asn1_length() + iv_vb_value->get_asn1_length() + 4;
+
+  return iv_vb_oid.get_asn1_length() + 2 + 4;
+}
+
+#ifdef SNMP_PP_NAMESPACE
+}; // end of namespace Snmp_pp
+#endif 
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..ab3acd3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,56 @@
+DEFS = 
+INCS = -Iinclude -I3rdparty/snmp++/include
+CXXFLAGS += -W -Wall -Wextra $(INCS) $(DEFS)
+LIBS = -lpthread \
+       -lssl \
+       -lcurl \
+       -lboost_system \
+       -lboost_program_options \
+       3rdparty/snmp++/libsnmp++.a
+PROG = gssmd # GTS SNMP Switch Management Daemon
+VERSION = 1.0.4
+
+SOURCES = src/main.cpp \
+         src/pidfile.cpp \
+         src/settings.cpp \
+         src/settingsfileparser.cpp \
+         src/logger.cpp \
+         src/syncer.cpp \
+         src/subscriber.cpp \
+         src/switch.cpp \
+         src/acl.cpp \
+         src/snmptable.cpp \
+         src/dataparser.cpp
+
+.PHONY: all clean snmplib version tests
+
+all: $(PROG)
+
+tests:
+       $(MAKE) $(MAKECMDGOALS) -C tests
+
+snmplib:
+       $(MAKE) $(MAKECMDGOALS) -C 3rdparty
+
+include/version.h: version
+
+version:
+       @sed 's/@VERSION@/$(VERSION)/g' include/version.h.in > include/version.h
+       @sed -i 's/@GIT_SHA@/'`git rev-parse --short HEAD`'/g' include/version.h
+
+$(PROG): version $(subst .cpp,.o,$(SOURCES)) snmplib
+       $(CXX) $(subst .cpp,.o,$(SOURCES)) $(LIBS) -o $@
+
+clean: snmplib
+       rm -f src/*.o src/*.d $(PROG) include/version.h
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+-include $(subst .cpp,.d,$(SOURCES))
+endif
+endif
+
+%.d: %.cpp
+       @$(CXX) -MM $(CXXFLAGS) $< > $@.$$$$; \
+       sed 's,\($*\).o[ :]*,src\/\1.o $@ : ,g' < $@.$$$$ > $@; \
+       rm -f $@.$$$$
diff --git a/gssmd.conf b/gssmd.conf
new file mode 100644 (file)
index 0000000..4daf70b
--- /dev/null
@@ -0,0 +1,40 @@
+[general]
+
+# 'daemon' flag defines whether to daemonize or no
+# Default - no
+daemon
+
+
+# 'debug' flag make output a bit more verbose
+# Default - no
+#debug
+
+# Log file path
+# Default: /var/log/gssmd.log
+log_file = /home/faust/Projects/GTS/snmp-daemon/gssmd.log
+
+# PID file path
+# Default: /var/run/gssmd.pid
+pid_file = /home/faust/Projects/GTS/snmp-daemon/gssmd.pid
+
+[sync]
+
+# Switch sync interval, sec
+# Default: 60 sec
+switch_interval = 1
+
+# Info sync interval, sec
+# Default: 180 sec
+info_interval = 10
+
+# Upload profile ID
+# Default: 1
+up_profile_id = 1
+
+# Download profile ID
+# Default: 1
+down_profile_id = 2
+
+# Data access URL
+# No default value
+data_url = http://db.loc/?mm=api&mode=sh_switches
diff --git a/include/.switch.h.swp b/include/.switch.h.swp
new file mode 100644 (file)
index 0000000..c1dcb40
Binary files /dev/null and b/include/.switch.h.swp differ
diff --git a/include/.syncer.h.swp b/include/.syncer.h.swp
new file mode 100644 (file)
index 0000000..e093572
Binary files /dev/null and b/include/.syncer.h.swp differ
diff --git a/include/acl.h b/include/acl.h
new file mode 100644 (file)
index 0000000..468671f
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __GTS_ACL_H__
+#define __GTS_ACL_H__
+
+#include <string>
+
+class Pdu;
+
+namespace GTS {
+
+class ACL {
+    public:
+        ACL(unsigned id,
+            unsigned profileId,
+            const std::string & mac,
+            unsigned port,
+            unsigned shape,
+            unsigned burst,
+            bool isUpload);
+        ACL(const ACL & rvalue);
+        ~ACL();
+
+        ACL & operator=(const ACL & rvalue);
+
+        unsigned getId() const { return _id; }
+        unsigned getProfileId() const { return _profileId; }
+        const std::string & getMAC() const { return _mac; }
+        std::string getPort() const { return _port; }
+        unsigned getShape() const { return _shape; }
+        unsigned getBurst() const { return _burst; }
+
+        bool isUpload() const { return _isUpload; }
+
+        void appendPdu(Pdu & pdu) const;
+
+    private:
+        unsigned _id;
+        unsigned _profileId;
+        std::string _mac;
+        std::string _port;
+        unsigned _shape;
+        unsigned _burst;
+
+        bool _isUpload;
+
+        std::string getSuffix() const;
+};
+
+}
+
+#endif
diff --git a/include/datatypes.h b/include/datatypes.h
new file mode 100644 (file)
index 0000000..28983df
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __GTS_DATA_TYPES_H__
+#define __GTS_DATA_TYPES_H__
+
+#include <string>
+#include <list>
+
+namespace GTS {
+
+struct LineType {
+    std::string switchIP;
+    std::string readCommunity;
+    std::string writeCommunity;
+    unsigned uplinkPort;
+    unsigned userPort;
+    std::string mac;
+    unsigned upShape;
+    unsigned downShape;
+    unsigned upBurst;
+    unsigned downBurst;
+};
+
+typedef std::list<LineType> Lines;
+
+bool parseData(std::string & data, Lines & lines);
+
+}
+
+#endif
diff --git a/include/logger.h b/include/logger.h
new file mode 100644 (file)
index 0000000..35d3e46
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __GTS_LOGGER_H__
+#define __GTS_LOGGER_H__
+
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#define LOG_IT logger << __FILE__ << "(" << __LINE__ << ") : "
+
+namespace GTS {
+
+class Logger {
+public:
+    Logger()
+        : fout(),
+          consoleLog(true)
+    {}
+    Logger(const std::string & fileName)
+        : fout(fileName.c_str(), std::ios::app),
+          logFile(fileName),
+          consoleLog(!fout.is_open())
+    {}
+    ~Logger() 
+    {};
+
+    bool setLogFile(const std::string & fileName);
+
+    std::ostream & operator<<(const std::string & str);
+private:
+    std::ofstream fout;
+    std::string logFile;
+    bool consoleLog;
+
+    void _logDate();
+};
+
+}
+
+extern GTS::Logger logger;
+
+#endif
diff --git a/include/oids.h b/include/oids.h
new file mode 100644 (file)
index 0000000..510fb4d
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __GTS_OIDS_H__
+#define __GTS_OIDS_H__
+
+#define swACLEtherRuleProfileID ".1.3.6.1.4.1.171.12.9.2.1.1.1"
+#define swACLEtherRuleAccessID ".1.3.6.1.4.1.171.12.9.3.1.1.2"
+#define swACLEtherRuleRowStatus ".1.3.6.1.4.1.171.12.9.3.1.1.15"
+#define swACLEtherRuleSrcMacAddress ".1.3.6.1.4.1.171.12.9.3.1.1.4"
+#define swACLEtherRuleDstMacAddress ".1.3.6.1.4.1.171.12.9.3.1.1.5"
+#define swACLEtherRulePermit ".1.3.6.1.4.1.171.12.9.3.1.1.13"
+#define swACLEtherRulePort ".1.3.6.1.4.1.171.12.9.3.1.1.14"
+#define swACLEtherRuleRxRate ".1.3.6.1.4.1.171.12.9.3.1.1.17"
+#define swACLMeterBurstSize ".1.3.6.1.4.1.171.12.9.6.1.1.6"
+
+#endif
diff --git a/include/pidfile.h b/include/pidfile.h
new file mode 100644 (file)
index 0000000..d2422bd
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __GTS_PIDFILE_H__
+#define __GTS_PIDFILE_H__
+
+#include <string>
+
+#include <boost/noncopyable.hpp>
+
+namespace GTS {
+
+class PIDFile : private boost::noncopyable {
+    public:
+        PIDFile();
+        PIDFile(const std::string & file);
+        ~PIDFile();
+    private:
+        const std::string fileName;
+        void _create();
+};
+
+}
+
+#endif
diff --git a/include/settings.h b/include/settings.h
new file mode 100644 (file)
index 0000000..e061b96
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef __GTS_SETTINGS_H__
+#define __GTS_SETTINGS_H__
+
+#include <string>
+
+#include <boost/noncopyable.hpp>
+#include <boost/program_options.hpp>
+
+namespace po = boost::program_options;
+
+namespace GTS {
+
+class SettingsParser;
+class Settings {
+    public:
+        // Construction / destruction
+        Settings();
+        Settings(const Settings & rvalue);
+        ~Settings();
+
+        const Settings & operator=(const Settings & rvalue);
+        
+        // Accessors
+        bool isHelp() const throw() { return _isHelp; }
+        bool isVersion() const throw() { return _isVersion; }
+        bool isDebug() const throw() { return _isDebug; }
+        bool isDaemon() const throw() { return _isDaemon; }
+
+        const std::string & configFile() const throw() { return _configFile; }
+        const std::string & logFile() const throw() { return _logFile; }
+        const std::string & PIDFile() const throw() { return _PIDFile; }
+
+        time_t switchSyncInterval() const throw() { return _switchSyncInterval; }
+        time_t infoSyncInterval() const throw() { return _infoSyncInterval; }
+
+        unsigned upProfileId() const throw() { return _upProfileId; }
+        unsigned downProfileId() const throw() { return _downProfileId; }
+
+        const std::string & dataURL() const throw() { return _dataURL; }
+
+        // Setters
+        void setIsHelp(bool value) throw() { _isHelp = value; }
+        void setIsVersion(bool value) throw() { _isVersion = value; }
+        void setIsDebug(bool value) throw() { _isDebug = value; }
+        void setIsDaemon(bool value) throw() { _isDaemon = value; }
+
+        void setConfigFile(const std::string & value) throw() { _configFile = value; }
+        void setLogFile(const std::string & value) throw() { _logFile = value; }
+        void setPIDFile(const std::string & value) throw() { _PIDFile = value; }
+
+        void setSwitchSyncInterval(time_t value) throw() { _switchSyncInterval = value; }
+        void setInfoSyncInterval(time_t value) throw() { _infoSyncInterval = value; }
+
+        void setUpProfileId(unsigned value) throw() { _upProfileId = value; }
+        void setDownProfileId(unsigned value) throw() { _downProfileId = value; }
+
+        void setDataURL(const std::string & value) throw() { _dataURL = value; }
+
+    private:
+        bool _isHelp;
+        bool _isVersion;
+        bool _isDebug;
+        bool _isDaemon;
+
+        std::string _configFile;
+        std::string _logFile;
+        std::string _PIDFile;
+
+        time_t _switchSyncInterval;
+        time_t _infoSyncInterval;
+
+        unsigned _upProfileId;
+        unsigned _downProfileId;
+
+        std::string _dataURL;
+
+        friend class SettingsParser;
+};
+
+class SettingsParser : private boost::noncopyable {
+    public:
+        SettingsParser();
+        ~SettingsParser();
+
+        void init(int argc, char * argv[]);
+        void reloadConfig();
+        void printHelp() const;
+
+        const Settings & settings() const { return _settings; };
+    private:
+        po::options_description _desc;
+        Settings _settings;
+
+        void parseFile(const std::string & fileName);
+};
+
+}
+
+#include "settings.inl.h"
+
+#endif
diff --git a/include/settings.inl.h b/include/settings.inl.h
new file mode 100644 (file)
index 0000000..e67aab7
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef __GTS_SETTINGS_INL_H__
+#define __GTS_SETTINGS_INL_H__
+
+#include <iostream>
+#include <sstream>
+
+namespace GTS {
+
+inline
+Settings::Settings()
+    : _isHelp(true),
+      _isVersion(false),
+      _isDebug(false),
+      _isDaemon(false),
+      _configFile("/etc/gssmd/gssmd.conf"),
+      _logFile("/var/log/gssmd.log"),
+      _PIDFile("/var/run/gssmd.pid"),
+      _switchSyncInterval(180),
+      _infoSyncInterval(60),
+      _upProfileId(1),
+      _downProfileId(2)
+{
+}
+
+inline
+Settings::Settings(const Settings & rvalue)
+    : _isHelp(rvalue._isHelp),
+      _isVersion(rvalue._isVersion),
+      _isDebug(rvalue._isDebug),
+      _isDaemon(rvalue._isDaemon),
+      _configFile(rvalue._configFile),
+      _logFile(rvalue._logFile),
+      _PIDFile(rvalue._PIDFile),
+      _switchSyncInterval(rvalue._switchSyncInterval),
+      _infoSyncInterval(rvalue._infoSyncInterval),
+      _upProfileId(rvalue._upProfileId),
+      _downProfileId(rvalue._downProfileId),
+      _dataURL(rvalue._dataURL)
+{
+}
+
+inline
+Settings::~Settings()
+{
+}
+
+inline
+const Settings & Settings::operator=(const Settings & rvalue)
+{
+    _isHelp = rvalue._isHelp;
+    _isVersion = rvalue._isVersion;
+    _isDebug = rvalue._isDebug;
+    _isDaemon = rvalue._isDaemon;
+    _configFile = rvalue._configFile;
+    _logFile = rvalue._logFile;
+    _PIDFile = rvalue._PIDFile;
+    _switchSyncInterval = rvalue._switchSyncInterval;
+    _infoSyncInterval = rvalue._infoSyncInterval;
+    _upProfileId = rvalue._upProfileId;
+    _downProfileId = rvalue._downProfileId;
+    _dataURL = rvalue._dataURL;
+    return *this;
+}
+
+inline
+SettingsParser::~SettingsParser()
+{
+}
+
+inline
+void SettingsParser::printHelp() const
+{
+    std::cout << _desc << std::endl;
+}
+
+}
+
+#endif
diff --git a/include/snmptable.h b/include/snmptable.h
new file mode 100644 (file)
index 0000000..81efb56
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __GTS_SNMPTABLE_H__
+#define __GTS_SNMPTABLE_H__
+
+#include <list>
+
+#include "snmp_pp/snmp_pp.h"
+
+namespace GTS {
+
+typedef std::list<Vb> SNMPList;
+
+class SNMPTable {
+    public:
+        SNMPTable(Snmp & snmp,
+                  const CTarget & target,
+                  const Oid & oid);
+        ~SNMPTable();
+
+        bool valid() const { return _valid; }
+        bool empty() const { return _list.empty(); }
+
+        template <typename T>
+        bool valueExists(const T & value) const;
+        bool getByOid(const Oid & oid, Vb & vb) const;
+        const SNMPList & getList() const { return _list; }
+
+    private:
+        SNMPList _list;
+        bool _valid;
+};
+
+}
+
+#include "snmptable.inl.h"
+
+#endif
diff --git a/include/snmptable.inl.h b/include/snmptable.inl.h
new file mode 100644 (file)
index 0000000..63ff217
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __GTS_SNMPTABLE_INL_H__
+#define __GTS_SNMPTABLE_INL_H__
+
+namespace GTS {
+    
+template <typename T>
+inline
+bool SNMPTable::valueExists(const T & value) const
+{
+    SNMPList::const_iterator it;
+    for (it = _list.begin(); it != _list.end(); ++it) {
+        T v;
+        if (it->get_value(v) != SNMP_CLASS_SUCCESS) {
+            continue;
+        }
+        if (v == value)
+            return true;
+    }
+    return false;
+}
+
+}
+
+#endif
diff --git a/include/subscriber.h b/include/subscriber.h
new file mode 100644 (file)
index 0000000..44d6db3
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef __GTS_SUBSCRIBER_H__
+#define __GTS_SUBSCRIBER_H__
+
+#include <string>
+
+namespace GTS {
+
+class Subscriber {
+    public:
+        Subscriber(const std::string & mac,
+                   unsigned port,
+                   unsigned upShape,
+                   unsigned downShape,
+                   unsigned upBurst,
+                   unsigned downBurst);
+        ~Subscriber();
+
+        std::string getHexMAC() const;
+        const std::string & getMAC() const { return _mac; }
+        unsigned getPort() const { return _port; }
+        unsigned getUpShape() const { return _upShape; }
+        unsigned getUpBurst() const { return _upBurst; }
+        unsigned getDownShape() const { return _downShape; }
+        unsigned getDownBurst() const { return _downBurst; }
+
+    private:
+        std::string _mac;
+        unsigned _port;
+        unsigned _upShape;
+        unsigned _downShape;
+        unsigned _upBurst;
+        unsigned _downBurst;
+};
+
+}
+
+#endif
diff --git a/include/switch.h b/include/switch.h
new file mode 100644 (file)
index 0000000..fc43284
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef __GTS_SWITCH_H__
+#define __GTS_SWITCH_H__
+
+#include <string>
+#include <vector>
+
+class Snmp;
+class CTarget;
+
+namespace GTS {
+
+class Settings;
+class Subscriber;
+class ACL;
+class SNMPTable;
+
+class Switch {
+    public:
+        Switch(const Settings & settings,
+               Snmp & snmp,
+               const std::string & ip,
+               const std::string & readCommunity,
+               const std::string & writeCommunity,
+               unsigned uplinkPort);
+        Switch(const Switch & rvalue);
+        ~Switch();
+
+        Switch & operator=(const Switch & rvalue);
+
+        const std::string & getIP() const { return _ip; }
+        const std::string & getReadCommunity() const { return _readCommunity; }
+        const std::string & getWriteCommunity() const { return _writeCommunity; }
+        unsigned getUplinkPort() const { return _uplinkPort; }
+
+        void addSubscriber(const Subscriber & subscriber);
+
+        void sync();
+
+    private:
+        const Settings & _settings;
+        Snmp & _snmp;
+
+        std::string _ip;
+        std::string _readCommunity;
+        std::string _writeCommunity;
+        unsigned _uplinkPort;
+
+        unsigned _nextUpACL;
+        unsigned _nextDownACL;
+
+        std::vector<ACL> _acls;
+
+        bool checkProfiles(const CTarget & target);
+        bool dropACLs(const CTarget & target);
+        bool dropACLsByTable(const CTarget & target, unsigned profileId, const SNMPTable & table);
+        bool createACLs(const CTarget & target);
+};
+
+}
+
+#endif
diff --git a/include/syncer.h b/include/syncer.h
new file mode 100644 (file)
index 0000000..5d5aaa7
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __GTS_SYNCER_H__
+#define __GTS_SYNCER_H__
+
+#include <ctime>
+#include <list>
+#include <map>
+
+#include <boost/function.hpp>
+
+class Snmp;
+
+namespace GTS {
+
+class SettingsParser;
+class Switch;
+
+class Timer {
+    public:
+        Timer(boost::function<void ()> callback, time_t interval);
+        ~Timer();
+
+        void fire();
+
+        time_t getInterval() const { return _interval; }
+        time_t getLastFire() const { return _lastFire; }
+        int getTimeout() const;
+    private:
+        time_t _interval;
+        time_t _lastFire;
+        boost::function<void ()> _callback;
+};
+
+typedef std::list<Timer>::iterator TimerIterator;
+typedef std::pair<Switch, TimerIterator> TimedSwitch;
+
+class Syncer {
+    public:
+        Syncer(SettingsParser & sp,
+               Snmp & snmp);
+        ~Syncer();
+
+        void run(const bool & running, bool & reload);
+
+    private:
+        SettingsParser & _settingsParser;
+        Snmp & _snmp;
+        std::list<Timer> _timers;
+        std::list<TimedSwitch> _switches;
+
+        bool wait();
+        void syncInfo();
+        Timer & getNextTimer();
+        bool getSwitchesState(std::map<std::string, Switch> & switches);
+        bool getDBData(std::string & data) const;
+};
+
+}
+
+#endif
diff --git a/include/version.h.in b/include/version.h.in
new file mode 100644 (file)
index 0000000..e4db5ca
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __GTS_VERSION_H__
+#define __GTS_VERSION_H__
+
+#include <string>
+
+namespace GTS {
+    static const std::string version("@VERSION@");
+    static const std::string revision("git sha @GIT_SHA@");
+}
+
+#endif
diff --git a/src/.main.cpp.swp b/src/.main.cpp.swp
new file mode 100644 (file)
index 0000000..57a74d5
Binary files /dev/null and b/src/.main.cpp.swp differ
diff --git a/src/.switch.cpp.swp b/src/.switch.cpp.swp
new file mode 100644 (file)
index 0000000..6332d06
Binary files /dev/null and b/src/.switch.cpp.swp differ
diff --git a/src/.syncer.cpp.swp b/src/.syncer.cpp.swp
new file mode 100644 (file)
index 0000000..d65f4ff
Binary files /dev/null and b/src/.syncer.cpp.swp differ
diff --git a/src/acl.cpp b/src/acl.cpp
new file mode 100644 (file)
index 0000000..08f0405
--- /dev/null
@@ -0,0 +1,116 @@
+#include <boost/lexical_cast.hpp>
+#include <boost/format.hpp>
+
+#include "snmp_pp/snmp_pp.h"
+
+#include "acl.h"
+#include "oids.h"
+#include "logger.h"
+
+using GTS::ACL;
+
+ACL::ACL(unsigned id,
+         unsigned profileId,
+         const std::string & mac,
+         unsigned port,
+         unsigned shape,
+         unsigned burst,
+         bool isUpload)
+    : _id(id),
+      _profileId(profileId),
+      _mac(mac),
+      _shape(shape),
+      _burst(burst),
+      _isUpload(isUpload)
+{
+    port = 1 << (32 - port);
+    _port = (boost::format("%|08x|") % port).str();
+}
+
+ACL::ACL(const ACL & rvalue)
+    : _id(rvalue._id),
+      _profileId(rvalue._profileId),
+      _mac(rvalue._mac),
+      _port(rvalue._port),
+      _shape(rvalue._shape),
+      _burst(rvalue._burst),
+      _isUpload(rvalue._isUpload)
+{
+}
+
+ACL::~ACL()
+{
+}
+
+ACL & ACL::operator=(const ACL & rvalue)
+{
+    _id = rvalue._id;
+    _profileId = rvalue._profileId;
+    _mac = rvalue._mac;
+    _port = rvalue._port;
+    _shape = rvalue._shape;
+    _burst = rvalue._burst;
+    _isUpload = rvalue._isUpload;
+
+    return *this;
+}
+
+void ACL::appendPdu(Pdu & pdu) const
+{
+    std::string oidValue;
+    // MAC
+    if (_isUpload) {
+        oidValue = swACLEtherRuleSrcMacAddress;
+        oidValue += getSuffix();
+    } else {
+        oidValue = swACLEtherRuleDstMacAddress;
+        oidValue += getSuffix();
+    }
+    Vb vb(Oid(oidValue.c_str()));
+    vb.set_value(OctetStr::from_hex_string(_mac.c_str()));
+    pdu += vb;
+
+    // Permit rule
+    oidValue = swACLEtherRulePermit;
+    oidValue += getSuffix();
+    vb.set_oid(Oid(oidValue.c_str()));
+    vb.set_value(int(2));
+    pdu += vb;
+
+    // Port
+    oidValue = swACLEtherRulePort;
+    oidValue += getSuffix();
+    vb.set_oid(Oid(oidValue.c_str()));
+    vb.set_value(OctetStr::from_hex_string(_port.c_str()));
+    pdu += vb;
+
+    // Shape
+    oidValue = swACLEtherRuleRxRate;
+    oidValue += getSuffix();
+    vb.set_oid(Oid(oidValue.c_str()));
+    vb.set_value(int(_shape));
+    pdu += vb;
+
+    // Create ACL
+    oidValue = swACLEtherRuleRowStatus;
+    oidValue += getSuffix();
+    vb.set_oid(Oid(oidValue.c_str()));
+    vb.set_value(int(4));
+    pdu += vb;
+
+    // Burst
+    /*oidValue = swACLMeterBurstSize;
+    oidValue += getSuffix();
+    vb.set_oid(Oid(oidValue.c_str()));
+    vb.set_value(int(_burst));
+    pdu += vb;*/
+}
+
+inline
+std::string ACL::getSuffix() const
+{
+    return std::string(".") +
+           boost::lexical_cast<std::string>(_profileId) +
+           "." +
+           boost::lexical_cast<std::string>(_id);
+}
diff --git a/src/dataparser.cpp b/src/dataparser.cpp
new file mode 100644 (file)
index 0000000..f83dbe5
--- /dev/null
@@ -0,0 +1,84 @@
+#include <string>
+#include <list>
+
+#include <boost/spirit/include/qi.hpp>
+#include <boost/fusion/include/std_pair.hpp>
+#include <boost/fusion/include/adapt_struct.hpp>
+
+#include "datatypes.h"
+#include "logger.h"
+
+namespace qi = boost::spirit::qi;
+
+using GTS::LineType;
+using GTS::Lines;
+
+BOOST_FUSION_ADAPT_STRUCT(
+    GTS::LineType,
+    (std::string, switchIP)
+    (std::string, readCommunity)
+    (std::string, writeCommunity)
+    (unsigned, uplinkPort)
+    (unsigned, userPort)
+    (std::string, mac)
+    (unsigned, upShape)
+    (unsigned, downShape)
+    (unsigned, upBurst)
+    (unsigned, downBurst)
+)
+
+template <typename Iterator>
+struct LinesGrammar 
+  : qi::grammar<Iterator, Lines()>
+{
+    LinesGrammar()
+      : LinesGrammar::base_type(query)
+    {
+        query          = +line;
+        line           =  ip        >> qi::lit(",") >>
+                          community >> qi::lit(",") >>
+                          community >> qi::lit(",") >>
+                          port      >> qi::lit(",") >>
+                          port      >> qi::lit(",") >>
+                          mac       >> qi::lit(",") >>
+                          shape     >> qi::lit(",") >>
+                          shape     >> qi::lit(",") >>
+                          shape     >> qi::lit(",") >>
+                          shape     >> eol;
+        ip             = +qi::digit >> qi::char_('.') >>
+                         +qi::digit >> qi::char_('.') >>
+                         +qi::digit >> qi::char_('.') >>
+                         +qi::digit;
+        community      = +qi::char_("a-zA-Z0-9_");
+        port           =  qi::int_;
+        mac            =  qi::xdigit >> qi::xdigit >>
+                          qi::xdigit >> qi::xdigit >>
+                          qi::xdigit >> qi::xdigit >>
+                          qi::xdigit >> qi::xdigit >>
+                          qi::xdigit >> qi::xdigit >>
+                          qi::xdigit >> qi::xdigit;
+        shape          =  qi::int_;
+        eol            =  qi::lit("\r\n") | '\r' | '\n';
+    }
+
+    qi::rule<Iterator, Lines()> query;
+    qi::rule<Iterator, LineType()> line;
+    qi::rule<Iterator, std::string()> ip, community, mac;
+    qi::rule<Iterator, unsigned()> port, shape;
+    qi::rule<Iterator> eol;
+};
+
+bool GTS::parseData(std::string & data, Lines & lines)
+{
+    std::string::iterator begin(data.begin());
+    std::string::iterator end(data.end());
+
+    LinesGrammar<std::string::iterator> parser; //  Our parser
+
+    if (!qi::parse(begin, end, parser, lines)) {
+        logger << "parseData() - Failed to parse data" << std::endl;
+        return false;
+    }
+
+    return true;
+}
diff --git a/src/logger.cpp b/src/logger.cpp
new file mode 100644 (file)
index 0000000..13e1f0f
--- /dev/null
@@ -0,0 +1,57 @@
+#include <ctime>
+
+#include "logger.h"
+
+using GTS::Logger;
+
+bool Logger::setLogFile(const std::string & fileName)
+{
+    fout.open(fileName.c_str(), std::ios::app);
+    logFile = fileName;
+    return !(consoleLog = !fout.is_open());
+}
+
+std::ostream & Logger::operator<<(const std::string & str)
+{
+    _logDate();
+    if (consoleLog) {
+        return std::cout << str;
+    } else {
+        fout.close();
+        fout.open(logFile.c_str(), std::ios::app);
+        if (fout) {
+            fout << str;
+        }
+        return fout;
+    }
+}
+
+inline
+void Logger::_logDate()
+{
+    time_t t = time(NULL);
+    struct tm *ts = localtime(&t);
+    if (consoleLog) {
+        std::cout << "["
+                  << (ts->tm_year + 1900) << "-"
+                  << (ts->tm_mon < 9 ? "0" : "") << (ts->tm_mon + 1) << "-"
+                  << (ts->tm_mday < 10 ? "0" : "") << ts->tm_mday << " "
+                  << (ts->tm_hour < 10 ? "0" : "") << ts->tm_hour << ":"
+                  << (ts->tm_min < 10 ? "0" : "") << ts->tm_min << ":"
+                  << (ts->tm_sec < 10 ? "0" : "") << ts->tm_sec
+                  << "] ";
+    } else {
+        fout.close();
+        fout.open(logFile.c_str(), std::ios::app);
+        if (fout) {
+            fout << "["
+                 << (ts->tm_year + 1900) << "-"
+                 << (ts->tm_mon < 9 ? "0" : "") << (ts->tm_mon + 1) << "-"
+                 << (ts->tm_mday < 10 ? "0" : "") << ts->tm_mday << " "
+                 << (ts->tm_hour < 10 ? "0" : "") << ts->tm_hour << ":"
+                 << (ts->tm_min < 10 ? "0" : "") << ts->tm_min << ":"
+                 << (ts->tm_sec < 10 ? "0" : "") << ts->tm_sec
+                 << "] ";
+        }
+    }
+}
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644 (file)
index 0000000..71133c2
--- /dev/null
@@ -0,0 +1,164 @@
+#include <unistd.h> // daemon
+
+#include <cerrno> // errno
+#include <cstring> // strerror
+#include <csignal>
+#include <iostream>
+#include <exception>
+
+#include "snmp_pp/snmp_pp.h"
+
+#include "syncer.h"
+#include "version.h"
+#include "settings.h"
+#include "pidfile.h"
+#include "logger.h"
+
+GTS::Logger logger;
+static bool running = true;
+static bool reload = false;
+
+void setSignalHandlers();
+
+int main(int argc, char * argv[])
+{
+    GTS::SettingsParser sParser;
+
+    // Set filter for logging
+    DefaultLog::log()->set_filter(ERROR_LOG, 7);
+    DefaultLog::log()->set_filter(WARNING_LOG, 7);
+    DefaultLog::log()->set_filter(EVENT_LOG, 0);
+    DefaultLog::log()->set_filter(INFO_LOG, 0);
+    DefaultLog::log()->set_filter(DEBUG_LOG, 0);
+
+    try {
+        sParser.init(argc, argv);
+    }
+    catch (const std::exception & ex) {
+        logger << ex.what() << std::endl;
+        return -1;
+    }
+
+    if (sParser.settings().isHelp()) {
+        sParser.printHelp();
+        return 0;
+    }
+
+    if (sParser.settings().isVersion()) {
+        std::cout << "GTS SNMP Switch Management Daemon " << GTS::version << " (revision: " << GTS::revision << ")" << std::endl;
+        return 0;
+    }
+
+    if (sParser.settings().isDebug()) {
+        std::cout << "Settings dump:\n"
+                  << "\t- help: " << (sParser.settings().isHelp() ? "yes" : "no") << "\n"
+                  << "\t- version: " << (sParser.settings().isVersion() ? "yes" : "no") << "\n"
+                  << "\t- debug: " << (sParser.settings().isDebug() ? "yes" : "no") << "\n"
+                  << "\t- daemon: " << (sParser.settings().isDaemon() ? "yes" : "no") << "\n"
+                  << "\t- config file: " << sParser.settings().configFile() << "\n"
+                  << "\t- log file: " << sParser.settings().logFile() << "\n"
+                  << "\t- PID file: " << sParser.settings().PIDFile() << "\n"
+                  << "\t- switch sync interval: " << sParser.settings().switchSyncInterval() << "\n"
+                  << "\t- info sync interval: " << sParser.settings().infoSyncInterval() << "\n"
+                  << "\t- switch's upload profile id: " << sParser.settings().upProfileId() << "\n"
+                  << "\t- switch's download profile id: " << sParser.settings().downProfileId() << "\n"
+                  << "\t- data URL: " << sParser.settings().dataURL() << std::endl;
+    }
+
+    if (sParser.settings().isDaemon()) {
+        if (daemon(0, sParser.settings().isDebug())) {
+            logger << "Failed to daemonize: " << strerror(errno) << std::endl;
+            return -1;
+        }
+    }
+    logger.setLogFile(sParser.settings().logFile());
+
+    try {
+        int status = 0;
+        Snmp snmp(status);
+
+        if (status) {
+            logger << "Failed to initialize SNMP" << std::endl;
+            return -1;
+        }
+
+        GTS::PIDFile pf(sParser.settings().PIDFile());
+        GTS::Syncer syncer(sParser, snmp);
+
+        logger << "Starting gssmd main thread..." << std::endl;
+
+        setSignalHandlers();
+
+        // Start main thread
+        syncer.run(running, reload);
+
+        logger << "Main thread stopped." << std::endl;
+    }
+    catch (std::exception & ex) {
+        logger << "Exception: " << ex.what() << std::endl;
+        return -1;
+    }
+
+    return 0;
+}
+
+void catchTERM(int)
+{
+    running = false;
+
+    struct sigaction newsa, oldsa;
+    sigset_t sigmask;
+
+    sigemptyset(&sigmask);
+    sigaddset(&sigmask, SIGTERM);
+    newsa.sa_handler = SIG_IGN;
+    newsa.sa_mask = sigmask;
+    newsa.sa_flags = 0;
+    sigaction(SIGTERM, &newsa, &oldsa);
+
+    sigemptyset(&sigmask);
+    sigaddset(&sigmask, SIGINT);
+    newsa.sa_handler = SIG_IGN;
+    newsa.sa_mask = sigmask;
+    newsa.sa_flags = 0;
+    sigaction(SIGINT, &newsa, &oldsa);
+}
+
+void catchHUP(int)
+{
+    reload = true;
+}
+
+void setSignalHandlers()
+{
+    struct sigaction newsa, oldsa;
+    sigset_t sigmask;
+
+    sigemptyset(&sigmask);
+    sigaddset(&sigmask, SIGTERM);
+    newsa.sa_handler = catchTERM;
+    newsa.sa_mask = sigmask;
+    newsa.sa_flags = 0;
+    sigaction(SIGTERM, &newsa, &oldsa);
+
+    sigemptyset(&sigmask);
+    sigaddset(&sigmask, SIGINT);
+    newsa.sa_handler = catchTERM;
+    newsa.sa_mask = sigmask;
+    newsa.sa_flags = 0;
+    sigaction(SIGINT, &newsa, &oldsa);
+
+    sigemptyset(&sigmask);
+    sigaddset(&sigmask, SIGPIPE);
+    newsa.sa_handler = SIG_IGN;
+    newsa.sa_mask = sigmask;
+    newsa.sa_flags = 0;
+    sigaction(SIGPIPE, &newsa, &oldsa);
+
+    sigemptyset(&sigmask);
+    sigaddset(&sigmask, SIGHUP);
+    newsa.sa_handler = catchHUP;
+    newsa.sa_mask = sigmask;
+    newsa.sa_flags = 0;
+    sigaction(SIGHUP, &newsa, &oldsa);
+}
diff --git a/src/pidfile.cpp b/src/pidfile.cpp
new file mode 100644 (file)
index 0000000..1b0ecbd
--- /dev/null
@@ -0,0 +1,45 @@
+#include <sys/types.h> // pid_t
+#include <unistd.h> // getpid
+
+#include <cerrno>
+#include <cstring>
+#include <fstream>
+
+#include "pidfile.h"
+#include "logger.h"
+
+using GTS::PIDFile;
+
+PIDFile::PIDFile()
+    : fileName("/var/run/gssmd.pid")
+{
+    _create();
+}
+
+PIDFile::PIDFile(const std::string & file)
+    : fileName(file)
+{
+    _create();
+}
+
+PIDFile::~PIDFile()
+{
+    if (unlink(fileName.c_str())) {
+        logger << "Failed to unlink pid-file: " << strerror(errno) << std::endl;
+        return;
+    }
+}
+
+void PIDFile::_create()
+{
+    std::ofstream file(fileName.c_str());
+
+    if (!file.is_open()) {
+        logger << "Failed to create pid-file: " << strerror(errno) << std::endl;
+        return;
+    }
+
+    pid_t pid = getpid();
+    file << pid;
+    logger << "PID: " << pid << std::endl;
+}
diff --git a/src/settings.cpp b/src/settings.cpp
new file mode 100644 (file)
index 0000000..5d04ad2
--- /dev/null
@@ -0,0 +1,89 @@
+#include "logger.h"
+#include "settings.h"
+
+using GTS::Settings;
+using GTS::SettingsParser;
+
+SettingsParser::SettingsParser()
+    : _desc("Allowed options")
+{
+    // Declare the supported options.
+    _desc.add_options()
+        ("help", "produce help message")
+        ("config,c", po::value<std::string>()->default_value("/etc/gssmd/gssmd.conf"), "config file location")
+        ("daemon,d", "daemonize after start")
+        ("debug", "gssmd debugging")
+        ("log-file", po::value<std::string>(), "log file location")
+        ("pid-file", po::value<std::string>(), "PID file location")
+        ("switch-sync-interval,s", po::value<time_t>(), "switch synchronization interval")
+        ("info-sync-interval,i", po::value<time_t>(), "info synchronization interval")
+        ("up-profile-id", po::value<unsigned>(), "switch's upload profile id")
+        ("down-profile-id", po::value<unsigned>(), "switch's download profile id")
+        ("data-url", po::value<std::string>(), "data access URL")
+        ("version,v", "show gssmd version and exit")
+    ;
+}
+
+void SettingsParser::init(int argc, char * argv[])
+{
+    po::variables_map vm;
+    po::store(po::parse_command_line(argc, argv, _desc), vm);
+    po::notify(vm);    
+
+    _settings._isHelp = vm.count("help");
+    _settings._isVersion = vm.count("version");
+
+    if (vm.count("config")) {
+        _settings._configFile = vm["config"].as<std::string>();
+    }
+
+    if (!_settings._isHelp &&
+        !_settings._isVersion) {
+        try {
+            parseFile(_settings._configFile);
+        }
+        catch (std::exception & ex) {
+            logger << "Error parsing config file '" << _settings._configFile << "': " << ex.what() << std::endl;
+        }
+    }
+
+    if (vm.count("debug")) {
+        _settings._isDebug = true;
+    }
+    if (vm.count("daemon")) {
+        _settings._isDaemon = true;
+    }
+
+    if (vm.count("log-file")) {
+        _settings._logFile = vm["log-file"].as<std::string>();
+    }
+
+    if (vm.count("pid-file")) {
+        _settings._PIDFile = vm["pid-file"].as<std::string>();
+    }
+
+    if (vm.count("switch-sync-interval")) {
+        _settings._switchSyncInterval = vm["switch-sync-interval"].as<time_t>();
+    }
+
+    if (vm.count("info-sync-interval")) {
+        _settings._infoSyncInterval = vm["info-sync-interval"].as<time_t>();
+    }
+
+    if (vm.count("up-profile-id")) {
+        _settings._upProfileId = vm["up-profile-id"].as<unsigned>();
+    }
+
+    if (vm.count("down-profile-id")) {
+        _settings._downProfileId = vm["down-profile-id"].as<unsigned>();
+    }
+
+    if (vm.count("data-url")) {
+        _settings._dataURL = vm["data-url"].as<std::string>();
+    }
+}
+
+void SettingsParser::reloadConfig()
+{
+    parseFile(_settings._configFile);
+}
diff --git a/src/settingsfileparser.cpp b/src/settingsfileparser.cpp
new file mode 100644 (file)
index 0000000..64f0d0b
--- /dev/null
@@ -0,0 +1,125 @@
+#include <fstream>
+#include <numeric>
+#include <map>
+#include <string>
+
+#include <boost/spirit/include/qi.hpp>
+#include <boost/fusion/include/std_pair.hpp>
+
+#include "settings.h"
+
+namespace qi = boost::spirit::qi;
+
+namespace {
+
+typedef std::map<std::string, std::string> PairsType;
+typedef std::map<std::string, PairsType> SectionsType;
+
+template <typename Iterator>
+struct IniGrammar 
+  : qi::grammar<Iterator, SectionsType()>
+{
+    IniGrammar()
+      : IniGrammar::base_type(query)
+    {
+        query          = +(section | (comment >> eol) | (space >> eol));
+        section        =  sectionHeader >> -sectionContent;
+        sectionHeader  =  '[' >> space >> key >> space >> ']' >> eol;
+        sectionContent = +((line | comment | space) >> eol);
+        comment        =  (qi::char_(';') | '#') >> *qi::print;
+        line           =  space >> key >> space >> -('=' >> space >> value >> space);
+        key            =  qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9");
+        value          = +qi::print;
+        space          = *qi::char_("\t ");
+        eol            =  qi::lit("\r\n") | '\r' | '\n';
+    }
+
+    qi::rule<Iterator, SectionsType()> query;
+    qi::rule<Iterator, std::pair<std::string, PairsType>()> section;
+    qi::rule<Iterator, PairsType()> sectionContent;
+    qi::rule<Iterator, std::pair<std::string, std::string>()> line;
+    qi::rule<Iterator, std::string()> key, value, sectionHeader;
+    qi::rule<Iterator> comment, space, eol;
+};
+
+inline
+bool sectionExists(const SectionsType & data, const std::string & sectionName) throw()
+{
+    return data.find(sectionName) != data.end();
+}
+
+inline
+bool fieldExists(const SectionsType & data, const std::string & sectionName, const std::string & fieldName) throw()
+{
+    const SectionsType::const_iterator sectionIterator(data.find(sectionName));
+    if (sectionIterator == data.end())
+        return false;
+    return sectionIterator->second.find(fieldName) != sectionIterator->second.end();
+}
+
+inline
+bool fieldValue(const SectionsType & data, const std::string & sectionName, const std::string & fieldName, std::string & value) throw()
+{
+    const SectionsType::const_iterator sectionIterator(data.find(sectionName));
+    if (sectionIterator == data.end())
+        return false;
+    const PairsType::const_iterator pairIterator(sectionIterator->second.find(fieldName));
+    if (pairIterator == sectionIterator->second.end())
+        return false;
+    value = pairIterator->second;
+    return true;
+}
+
+}
+
+using GTS::SettingsParser;
+
+void SettingsParser::parseFile(const std::string & fileName)
+{
+    std::ifstream in(fileName.c_str());
+    if (!in) {
+        throw std::runtime_error("Can't open file");
+    }
+
+    std::string text;
+    while(!in.eof()) {
+        std::string s;
+        std::getline(in, s);
+        text += s + "\n";
+    }
+
+    std::string::iterator begin = text.begin();
+    std::string::iterator end = text.end();
+
+    SectionsType data;
+    IniGrammar<std::string::iterator> parser; //  Our parser
+
+    if (!qi::parse(begin, end, parser, data)) {
+        throw std::runtime_error("Parse error");
+    }
+
+    std::string res;
+    _settings._isDaemon = fieldExists(data, "general", "daemon");
+    _settings._isDebug = fieldExists(data, "general", "debug");
+    if (fieldValue(data, "general", "log_file", res)){
+        _settings._logFile = res;
+    }
+    if (fieldValue(data, "general", "pid_file", res)){
+        _settings._PIDFile = res;
+    }
+    if (fieldValue(data, "sync", "switch_interval", res)){
+        _settings._switchSyncInterval = boost::lexical_cast<time_t>(res);
+    }
+    if (fieldValue(data, "sync", "info_interval", res)){
+        _settings._infoSyncInterval = boost::lexical_cast<time_t>(res);
+    }
+    if (fieldValue(data, "sync", "up_profile_id", res)){
+        _settings._upProfileId = boost::lexical_cast<unsigned>(res);
+    }
+    if (fieldValue(data, "sync", "down_profile_id", res)){
+        _settings._downProfileId = boost::lexical_cast<unsigned>(res);
+    }
+    if (fieldValue(data, "sync", "data_url", res)){
+        _settings._dataURL = res;
+    }
+}
diff --git a/src/snmptable.cpp b/src/snmptable.cpp
new file mode 100644 (file)
index 0000000..b0aaba3
--- /dev/null
@@ -0,0 +1,41 @@
+#include "snmptable.h"
+#include "logger.h"
+
+using GTS::SNMPTable;
+
+SNMPTable::SNMPTable(Snmp & snmp,
+                     const CTarget & target,
+                     const Oid & oid)
+    : _valid(false)
+{
+    Vb vb(oid);
+    Pdu pdu(&vb, 1);
+    while (true) {
+        if (snmp.get_next(pdu, target) != SNMP_CLASS_SUCCESS) {
+            logger << "SNMPTable::SNMPTable() - failed to invoke Snmp::get_next (oid: '" << oid.get_printable() << "')" << std::endl;
+            return;
+        }
+        if (pdu.get_vb(0).get_oid().nCompare(oid.len(), oid) != 0) {
+            break;
+        }
+        _list.push_back(pdu.get_vb(0));
+    }
+
+    _valid = true;
+}
+
+SNMPTable::~SNMPTable()
+{
+}
+
+bool SNMPTable::getByOid(const Oid & oid, Vb & vb) const
+{
+    SNMPList::const_iterator it;
+    for (it = _list.begin(); it != _list.end(); ++it) {
+        if (it->valid() && it->get_oid() == oid) {
+            vb = *it;
+            return true;
+        }
+    }
+    return false;
+}
diff --git a/src/subscriber.cpp b/src/subscriber.cpp
new file mode 100644 (file)
index 0000000..046d29b
--- /dev/null
@@ -0,0 +1,27 @@
+#include "subscriber.h"
+
+using GTS::Subscriber;
+
+Subscriber::Subscriber(const std::string & mac,
+                       unsigned port,
+                       unsigned upShape,
+                       unsigned downShape,
+                       unsigned upBurst,
+                       unsigned downBurst)
+    : _mac(mac),
+      _port(port),
+      _upShape(upShape),
+      _downShape(downShape),
+      _upBurst(upBurst),
+      _downBurst(downBurst)
+{
+}
+
+Subscriber::~Subscriber()
+{
+}
+
+std::string Subscriber::getHexMAC() const
+{
+    return _mac;
+}
diff --git a/src/switch.cpp b/src/switch.cpp
new file mode 100644 (file)
index 0000000..43c83da
--- /dev/null
@@ -0,0 +1,210 @@
+#include <boost/lexical_cast.hpp>
+
+#include "snmp_pp/snmp_pp.h"
+
+#include "switch.h"
+#include "settings.h"
+#include "subscriber.h"
+#include "acl.h"
+#include "logger.h"
+#include "snmptable.h"
+#include "oids.h"
+
+using GTS::Switch;
+using GTS::SNMPTable;
+
+Switch::Switch(const Settings & settings,
+               Snmp & snmp,
+               const std::string & ip,
+               const std::string & readCommunity,
+               const std::string & writeCommunity,
+               unsigned uplinkPort)
+    : _settings(settings),
+      _snmp(snmp),
+      _ip(ip),
+      _readCommunity(readCommunity),
+      _writeCommunity(writeCommunity),
+      _uplinkPort(uplinkPort),
+      _nextUpACL(1),
+      _nextDownACL(1)
+{
+}
+
+Switch::Switch(const Switch & rvalue)
+    : _settings(rvalue._settings),
+      _snmp(rvalue._snmp),
+      _ip(rvalue._ip),
+      _readCommunity(rvalue._readCommunity),
+      _writeCommunity(rvalue._writeCommunity),
+      _uplinkPort(rvalue._uplinkPort),
+      _nextUpACL(rvalue._nextUpACL),
+      _nextDownACL(rvalue._nextDownACL),
+      _acls(rvalue._acls)
+{
+}
+
+Switch::~Switch()
+{
+}
+
+Switch & Switch::operator=(const Switch & rvalue)
+{
+    _ip = rvalue._ip;
+    _readCommunity = rvalue._readCommunity;
+    _writeCommunity = rvalue._writeCommunity;
+    _uplinkPort = rvalue._uplinkPort;
+    _nextUpACL = rvalue._nextUpACL;
+    _nextDownACL = rvalue._nextDownACL;
+    _acls = rvalue._acls;
+
+    return *this;
+}
+
+void Switch::addSubscriber(const Subscriber & subscriber)
+{
+    _acls.push_back(ACL(_nextUpACL++,
+                        _settings.upProfileId(),
+                        subscriber.getMAC(),
+                        subscriber.getPort(),
+                        subscriber.getUpShape(),
+                        subscriber.getUpBurst(),
+                        true));
+    _acls.push_back(ACL(_nextDownACL++,
+                        _settings.downProfileId(),
+                        subscriber.getMAC(),
+                        _uplinkPort,
+                        subscriber.getDownShape(),
+                        subscriber.getDownBurst(),
+                        false));
+}
+
+void Switch::sync()
+{
+    IpAddress addr(_ip.c_str());
+    if (!addr.valid()) {
+        logger << "Switch::sync() - ivalid switch ip: '" << _ip << "'" << std::endl;
+        return;
+    }
+
+    CTarget target(addr, _readCommunity.c_str(), _writeCommunity.c_str());
+    if (!target.valid()) {
+        logger << "Switch::sync() - failed to create target for the switch '" << _ip << "'" << std::endl;
+        return;
+    }
+
+    target.set_version(version2c);
+
+    if (!checkProfiles(target)) {
+        logger << "Switch::sync() - no upload and download profiles defined for the switch '" << _ip << "'" << std::endl;
+        return;
+    }
+
+    if (!dropACLs(target)) {
+        logger << "Switch::sync() - failed to drop ACLs for the switch '" << _ip << "'" << std::endl;
+        return;
+    }
+
+    if (!createACLs(target)) {
+        logger << "Switch::sync() - failed to create ACLs for the switch '" << _ip << "'" << std::endl;
+    }
+
+    if (_settings.isDebug()) {
+        logger << "Switch::sync() - switch '" << _ip << "' synchronized successfully, ACLs: " << _acls.size() << std::endl;
+    }
+}
+
+bool Switch::checkProfiles(const CTarget & target)
+{
+    SNMPTable table(_snmp, target, Oid(swACLEtherRuleProfileID));
+    if (!table.valid()) {
+        logger << "Switch::checkProfiles() - profiles SNMPTable is invalid for the switch '" << _ip << "'" << std::endl;
+        return false;
+    }
+    if (table.empty()) {
+        // Ok, just an empty table
+        return false;
+    }
+    if (table.valueExists(
+            static_cast<int>(_settings.upProfileId())
+        ) &&
+        table.valueExists(
+            static_cast<int>(_settings.downProfileId())
+        )) {
+        return true;
+    }
+    return false;
+}
+
+bool Switch::dropACLs(const CTarget & target)
+{
+    std::string upOidValue(swACLEtherRuleAccessID);
+    upOidValue += ".";
+    upOidValue += boost::lexical_cast<std::string>(_settings.upProfileId());
+    std::string downOidValue(swACLEtherRuleAccessID);
+    downOidValue += ".";
+    downOidValue += boost::lexical_cast<std::string>(_settings.downProfileId());
+    SNMPTable aclsUpTable(_snmp, target, Oid(upOidValue.c_str()));
+    SNMPTable aclsDownTable(_snmp, target, Oid(downOidValue.c_str()));
+    if (!aclsUpTable.valid()) {
+        logger << "Switch::dropACLs() - upload profile acls SNMPTable is invalid for the switch '" << _ip << "'" << std::endl;
+        return false;
+    }
+    if (!aclsDownTable.valid()) {
+        logger << "Switch::dropACLs() - download profile acls SNMPTable is invalid for the switch '" << _ip << "'" << std::endl;
+        return false;
+    }
+    if (!aclsUpTable.empty()) {
+        if (!dropACLsByTable(target, _settings.upProfileId(), aclsUpTable)) {
+            logger << "Switch::dropACLs() - failed to drop acls from upload table for the switch '" << _ip << "'" << std::endl;
+            return false;
+        }
+    }
+    if (!aclsDownTable.empty()) {
+        if (!dropACLsByTable(target, _settings.downProfileId(), aclsDownTable)) {
+            logger << "Switch::dropACLs() - failed to drop acls from download table for the switch '" << _ip << "'" << std::endl;
+            return false;
+        }
+    }
+    return true;
+}
+
+bool Switch::dropACLsByTable(const CTarget & target, unsigned profileId, const SNMPTable & table)
+{
+    std::string dropACLOidPrefix(swACLEtherRuleRowStatus);
+    dropACLOidPrefix += ".";
+    dropACLOidPrefix += boost::lexical_cast<std::string>(profileId);
+    SNMPList aclsList(table.getList());
+    Pdu pdu;
+    SNMPList::const_iterator it;
+    for (it = aclsList.begin(); it != aclsList.end(); ++it) {
+        int id;
+        if (it->get_value(id) != SNMP_CLASS_SUCCESS) {
+            return false;
+        }
+        std::string dropACLOid(dropACLOidPrefix);
+        dropACLOid += ".";
+        dropACLOid += boost::lexical_cast<std::string>(id);
+        Vb vb(Oid(dropACLOid.c_str()));
+        vb.set_value(int(6));
+        pdu += vb;
+    }
+    if (_snmp.set(pdu, target) != SNMP_CLASS_SUCCESS) {
+        logger << "Switch::dropACLsByTable() - failed to invoke Snmp::set for the switch '" << _ip << "'" << std::endl;
+        return false;
+    }
+    return true;
+}
+
+bool Switch::createACLs(const CTarget & target)
+{
+    std::vector<ACL>::const_iterator it;
+    for (it = _acls.begin(); it != _acls.end(); ++it) {
+        Pdu pdu;
+        it->appendPdu(pdu);
+        if (_snmp.set(pdu, target) != SNMP_CLASS_SUCCESS) {
+            logger << "Switch::createACLs() - failed to invoke Snmp::set for the switch '" << _ip << "'" << std::endl;
+            return false;
+        }
+    }
+    return true;
+}
diff --git a/src/syncer.cpp b/src/syncer.cpp
new file mode 100644 (file)
index 0000000..9d5d7a5
--- /dev/null
@@ -0,0 +1,234 @@
+#include <sys/select.h>
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+#include <cassert>
+#include <algorithm>
+#include <exception>
+
+#include <boost/bind.hpp>
+
+#include "snmp_pp/snmp_pp.h"
+
+#include "syncer.h"
+#include "settings.h"
+#include "switch.h"
+#include "subscriber.h"
+#include "datatypes.h"
+#include "logger.h"
+
+using GTS::Syncer;
+using GTS::Timer;
+using GTS::Switch;
+using GTS::Subscriber;
+using GTS::Lines;
+
+Timer::Timer(boost::function<void ()> callback, time_t interval)
+    : _interval(interval),
+      _lastFire(0),
+      _callback(callback)
+{
+}
+
+Timer::~Timer()
+{
+}
+
+int Timer::getTimeout() const
+{
+    double delta = difftime(time(NULL), _lastFire);
+    return _interval - delta;
+}
+
+void Timer::fire()
+{
+    _callback();
+    time(&_lastFire);
+}
+
+Syncer::Syncer(SettingsParser & sp,
+               Snmp & snmp)
+    : _settingsParser(sp),
+      _snmp(snmp)
+{
+    // 1 db syncer
+    _timers.push_back(Timer(boost::bind(&Syncer::syncInfo, this),
+                            _settingsParser.settings().infoSyncInterval()));
+}
+
+Syncer::~Syncer()
+{
+}
+
+void Syncer::run(const bool & running, bool & reload)
+{
+    logger << "Syncer::run()" << std::endl;
+    while (running) {
+        if (wait()) {
+            logger << "Syncer::run() - wait stopped by signal" << std::endl;
+            if (!running)
+                break;
+            if (reload) {
+                logger << "Syncer::run() - reload" << std::endl;
+                try {
+                    _settingsParser.reloadConfig();
+                }
+                catch (std::exception & ex) {
+                    logger << "Syncer::run() - exception: " << ex.what() << std::endl;
+                }
+                reload = false;
+            }
+        }
+    }
+}
+
+bool Syncer::wait()
+{
+    Timer & timer(getNextTimer());
+
+    if (timer.getTimeout() > 0) {
+        fd_set rfds;
+
+        FD_ZERO(&rfds);
+
+        struct timeval tv;
+        tv.tv_sec = timer.getTimeout();
+        tv.tv_usec = 0;
+
+        int retval = select(1, &rfds, NULL, NULL, &tv);
+
+        if (retval == -1) {
+            return true;
+        }
+    }
+
+    timer.fire();
+
+    return false;
+}
+
+Timer & Syncer::getNextTimer()
+{
+    assert(_timers.size() && "Timer list must not be empty!");
+    int timeout = _timers.begin()->getTimeout();
+    std::list<Timer>::iterator it(_timers.begin());
+    std::list<Timer>::iterator pos(_timers.begin());
+    ++it;
+    while (it != _timers.end()) {
+        if (it->getTimeout() < timeout) {
+            pos = it;
+            timeout = pos->getTimeout();
+        }
+        ++it;
+    }
+    return *pos;
+}
+
+void Syncer::syncInfo()
+{
+    std::map<std::string, Switch> switches;
+    if (!getSwitchesState(switches)) {
+        logger << "Syncer::syncInfo() - failed to get new switch states" << std::endl;
+        return;
+    }
+    std::list<TimedSwitch>::iterator it(_switches.begin());
+    while (it != _switches.end()) {
+        _timers.erase(it->second);
+        _switches.erase(it++);
+    }
+    std::map<std::string, Switch>::const_iterator sit;
+    for (sit = switches.begin(); sit != switches.end(); ++sit) {
+        // Insert switch with no timer
+        _switches.push_back(std::make_pair(sit->second, _timers.end()));
+        // Insert timer for this switch
+        TimerIterator tit = _timers.insert(
+                _timers.end(),
+                Timer(boost::bind(&Switch::sync, &_switches.back().first),
+                      _settingsParser.settings().switchSyncInterval()));
+        // Set timer iterator for this switch
+        _switches.back().second = tit;
+    }
+    logger << "Syncer::syncInfo() - data synchronization successfull, switches: " << _switches.size() << std::endl;
+}
+
+size_t curlWriteFunction(void * ptr, size_t size, size_t nmemb, void * userdata)
+{
+    char * data = static_cast<char *>(ptr);
+    std::string * dest = static_cast<std::string *>(userdata);
+    dest->append(data, size * nmemb);
+    return size * nmemb;
+}
+
+bool Syncer::getDBData(std::string & data) const
+{
+    CURL * handle = curl_easy_init();
+    if (handle) {
+        char errorBuffer[CURL_ERROR_SIZE];
+        curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); // Accept self-signed certs
+        curl_easy_setopt(handle, CURLOPT_LOW_SPEED_LIMIT, 1); // Less than 1 bps
+        curl_easy_setopt(handle, CURLOPT_LOW_SPEED_TIME, 60); // During 60 secs
+        curl_easy_setopt(handle, CURLOPT_URL, _settingsParser.settings().dataURL().c_str()); // Our URL
+        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curlWriteFunction); // Our write callback
+        curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data); // Our callback data
+        curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errorBuffer); // Buffer for an error messages
+        CURLcode res = curl_easy_perform(handle);
+        if (res) {
+            logger << "Syncer::getDBData() - DB communication error: '" << errorBuffer << "'" << std::endl;
+            curl_easy_cleanup(handle);
+            return false;
+        }
+        curl_easy_cleanup(handle);
+        return true;
+    }
+    logger << "Syncer::getDBData() - failed to init CURL library" << std::endl;
+    return false;
+}
+
+bool Syncer::getSwitchesState(std::map<std::string, Switch> & switches)
+{
+    if (_settingsParser.settings().dataURL().empty()) {
+        logger << "Switch::getSwitchesState() - data URL is empty" << std::endl;
+        return false;
+    }
+    std::string data;
+    if (!getDBData(data)) {
+        logger << "Syncer::getSwitchesState() - failed to fetch data from the URL: '" << _settingsParser.settings().dataURL() << "'" << std::endl;
+        return false;
+    }
+    Lines lines;
+    if (!parseData(data, lines)) {
+        logger << "Syncer::getSwitchesState() - failed to parse data:\n" << data << std::endl;
+        return false;
+    }
+    Lines::const_iterator it;
+    for (it = lines.begin(); it != lines.end(); ++it) {
+        std::pair<std::map<std::string, Switch>::iterator, bool> res(
+            switches.insert(
+                std::make_pair(
+                    it->switchIP,
+                    Switch(
+                        _settingsParser.settings(),
+                        _snmp,
+                        it->switchIP,
+                        it->readCommunity,
+                        it->writeCommunity,
+                        it->uplinkPort
+                    )
+                )
+            )
+        );
+        res.first->second.addSubscriber(
+            Subscriber(
+                it->mac,
+                it->userPort,
+                it->upShape,
+                it->downShape,
+                it->upBurst,
+                it->downBurst
+            )
+        );
+    }
+    return true;
+}
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644 (file)
index 0000000..5ab197a
--- /dev/null
@@ -0,0 +1,50 @@
+DEFS = 
+INCS = -I../include -I../3rdparty/snmp++/include
+CXXFLAGS += -W -Wall -Wextra $(INCS) $(DEFS)
+LIBS = -lpthread \
+       -lssl \
+       -lboost_system \
+       -lboost_program_options \
+       ../3rdparty/snmp++/libsnmp++.a
+
+SOURCES1 = test_switch.cpp \
+          ../src/settings.cpp \
+          ../src/settingsfileparser.cpp \
+          ../src/logger.cpp \
+          ../src/subscriber.cpp \
+          ../src/switch.cpp \
+          ../src/acl.cpp \
+          ../src/snmptable.cpp
+
+SOURCES2 = test_data_parser.cpp \
+          ../src/logger.cpp \
+          ../src/dataparser.cpp
+
+.PHONY: all clean snmplib tests
+
+all: tests
+
+tests: test_switch test_data_parser
+
+snmplib:
+       $(MAKE) all -C ../3rdparty
+
+test_switch: $(subst .cpp,.o,$(SOURCES1)) snmplib
+       $(CXX) $(subst .cpp,.o,$(SOURCES1)) $(LIBS) -o $@
+
+test_data_parser: $(subst .cpp,.o,$(SOURCES2))
+       $(CXX) $(subst .cpp,.o,$(SOURCES2)) $(LIBS) -o $@
+
+clean: snmplib
+       rm -f *.o *.d test_switch test_data_parser
+
+ifneq ($(MAKECMDGOALS),distclean)
+ifneq ($(MAKECMDGOALS),clean)
+-include $(subst .cpp,.d,$(SOURCES))
+endif
+endif
+
+%.d: %.cpp
+       @$(CXX) -MM $(CXXFLAGS) $< > $@.$$$$; \
+       sed 's,\($*\).o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+       rm -f $@.$$$$
diff --git a/tests/test_data_parser.cpp b/tests/test_data_parser.cpp
new file mode 100644 (file)
index 0000000..3c3292e
--- /dev/null
@@ -0,0 +1,40 @@
+#include <iostream>
+
+#include "datatypes.h"
+#include "logger.h"
+
+GTS::Logger logger;
+
+int main()
+{
+    GTS::Lines lines;
+    std::string data(
+"172.16.47.10,gts_community_r,gts_community_w,10,1,001CC0B16177,64,128,64,128\n"
+"172.16.47.11,gts_community_r,gts_community_w,10,1,001CC0B16178,65,129,66,138\n"
+"172.16.47.10,gts_community_r,gts_community_w,16,1,001CC0B16179,66,130,68,148\n"
+"172.16.47.10,gts_community_r,gts_community_w,16,8,001CC0B16180,67,131,70,158\n"
+    );
+
+    std::cout << data << std::endl;
+
+    if (!parseData(data, lines)) {
+        logger << "Failed to parse data" << std::endl;
+    } else {
+        GTS::Lines::const_iterator it;
+        for (it = lines.begin(); it != lines.end(); ++it) {
+            logger << "line: "
+                   << it->switchIP << ","
+                   << it->readCommunity << ","
+                   << it->writeCommunity << ","
+                   << it->uplinkPort << ","
+                   << it->userPort << ","
+                   << it->mac << ","
+                   << it->upShape << ","
+                   << it->downShape << ","
+                   << it->upBurst << ","
+                   << it->downBurst << std::endl;
+        }
+    }
+
+    return 0;
+}
diff --git a/tests/test_switch.cpp b/tests/test_switch.cpp
new file mode 100644 (file)
index 0000000..7d68c0f
--- /dev/null
@@ -0,0 +1,49 @@
+#include <iostream>
+#include <exception>
+
+#include "snmp_pp/snmp_pp.h"
+
+#include "settings.h"
+#include "switch.h"
+#include "subscriber.h"
+#include "logger.h"
+
+GTS::Logger logger;
+
+int main()
+{
+    GTS::Settings settings;
+
+    settings.setIsDebug(true);
+    settings.setUpProfileId(1);
+    settings.setDownProfileId(2);
+
+    int status = 0;
+    Snmp snmp(status);
+
+    if (status) {
+        logger << "Failed to initialize SNMP" << std::endl;
+        return -1;
+    }
+
+    GTS::Switch sw(settings,
+                   snmp,
+                   "172.16.47.10",
+                   "gts_community_r",
+                   "gts_community_w",
+                   10);
+
+    sw.addSubscriber(
+            GTS::Subscriber(
+                "485b3936a273",
+                1,
+                8192,
+                8192,
+                256,
+                512
+            )
+    );
+
+    sw.sync();
+    return 0;
+}