uxsnmp.cpp
上传用户:cnryan
上传日期:2008-12-15
资源大小:260k
文件大小:66k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*_############################################################################
  2.   _## 
  3.   _##  uxsnmp.cpp  
  4.   _##
  5.   _##  SNMP++v3.2.21
  6.   _##  -----------------------------------------------
  7.   _##  Copyright (c) 2001-2006 Jochen Katz, Frank Fock
  8.   _##
  9.   _##  This software is based on SNMP++2.6 from Hewlett Packard:
  10.   _##  
  11.   _##    Copyright (c) 1996
  12.   _##    Hewlett-Packard Company
  13.   _##  
  14.   _##  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
  15.   _##  Permission to use, copy, modify, distribute and/or sell this software 
  16.   _##  and/or its documentation is hereby granted without fee. User agrees 
  17.   _##  to display the above copyright notice and this license notice in all 
  18.   _##  copies of the software and any documentation of the software. User 
  19.   _##  agrees to assume all liability for the use of the software; 
  20.   _##  Hewlett-Packard and Jochen Katz make no representations about the 
  21.   _##  suitability of this software for any purpose. It is provided 
  22.   _##  "AS-IS" without warranty of any kind, either express or implied. User 
  23.   _##  hereby grants a royalty-free license to any and all derivatives based
  24.   _##  upon this software code base. 
  25.   _##  
  26.   _##  Stuttgart, Germany, Fri Jun 16 17:48:57 CEST 2006 
  27.   _##  
  28.   _##########################################################################*/
  29. /*===================================================================
  30.       U X S N M P . C P P
  31.       UXSNMP CLASS DECLARATION
  32.       Description:    HPUX version of Snmp class
  33.       Language:       ANSI C++
  34.       Author:         Peter E Mellquist
  35. =====================================================================*/
  36. char snmp_cpp_version[]="#(@) SNMP++ $Id: uxsnmp.cpp,v 1.32 2006/04/05 19:28:09 katz Exp $";
  37. /* CK Ng    added support for WIN32 in the whole file */
  38. //-----[ includes ]----------------------------------------------------
  39. #ifdef WIN32
  40. #include <winsock.h>
  41. #include <sys/types.h>     // system types
  42. #include <sys/timeb.h>     // _timeb and _ftime
  43. #else
  44. #include <unistd.h>        // unix
  45. #include <sys/socket.h>    // bsd socket stuff
  46. #include <netinet/in.h>    // network types
  47. #include <arpa/inet.h>     // arpa types
  48. #include <sys/types.h>     // system types
  49. #if !(defined CPU && CPU == PPC603)
  50. #include <sys/time.h>      // time stuff
  51. #endif
  52. #endif
  53. #ifdef _AIX
  54. #define ss_family __ss_family
  55. #endif
  56. #include <stdlib.h>        // need for malloc
  57. #include <errno.h>         // ux errs
  58. #define _INCLUDE_SNMP_ERR_STRINGS
  59. //----[ snmp++ includes ]----------------------------------------------
  60. #include "snmp_pp/uxsnmp.h"        // class def for this module
  61. #include "snmp_pp/oid_def.h"       // class def for well known trap oids
  62. #include "snmp_pp/v3.h"
  63. #include "snmp_pp/msgqueue.h"      // message queue
  64. #include "snmp_pp/notifyqueue.h"   // notification queue
  65. #include "snmp_pp/snmpmsg.h"       // asn serialization class
  66. #include "snmp_pp/eventlistholder.h"
  67. #include "snmp_pp/usm_v3.h"
  68. #include "snmp_pp/vb.h"
  69. #if defined (CPU) && CPU == PPC603
  70. #include <sockLib.h> 
  71. #include <taskLib.h> 
  72. #endif
  73. #ifdef SNMP_PP_NAMESPACE
  74. namespace Snmp_pp {
  75. #endif
  76. //-----[ special includes ]-------------------------------------------
  77. extern "C"
  78. {
  79.   //------------[ if using Wind-U, then bring in the ms-windows header ]
  80. #ifndef WIN32
  81. #ifdef WU_APP
  82.   WORD app_hinst;
  83. #else
  84.   typedef short WORD;
  85.   typedef long DWORD;
  86. #endif
  87. #endif
  88. }
  89. //-----[ macros ]------------------------------------------------------
  90. #define DEFAULT_TIMEOUT 1000  // one second default timeout
  91. #define DEFAULT_RETRIES 1     // no retry default
  92. #define SNMP_PORT 161         // port # for SNMP
  93. #define SNMP_TRAP_PORT 162    // port # for SNMP traps
  94. #ifdef WIN32
  95. #ifdef __BCPLUSPLUS__
  96. #define _timeb timeb
  97. #define _ftime ftime
  98. #endif
  99. #define close closesocket
  100. #endif
  101. //--------[ globals ]---------------------------------------------------
  102. //--------------[ well known trap ids ]-----------------------------------
  103. const coldStartOid coldStart;
  104. const warmStartOid warmStart;
  105. const linkDownOid linkDown;
  106. const linkUpOid linkUp;
  107. const authenticationFailureOid authenticationFailure;
  108. const egpNeighborLossOid egpNeighborLoss;
  109. const snmpTrapEnterpriseOid snmpTrapEnterprise;
  110. #ifdef _SNMPv3
  111. void v3CallBack(int reason, Snmp *snmp, Pdu &pdu, SnmpTarget &target, void *v3cd)
  112. {
  113.   Snmp::V3CallBackData *cbData;
  114.   cbData = (Snmp::V3CallBackData*)v3cd;
  115.   Vb tmpvb;
  116.   pdu.get_vb(tmpvb,0);
  117.   debugprintf(5, "v3CallBack: received oid: %s with value: %s",
  118.               tmpvb.get_printable_oid(), tmpvb.get_printable_value());
  119.   debugprintf(5, "v3CallBack: error_msg (%s), pdu_type (%i)",
  120.       snmp->error_msg(tmpvb.get_oid()), pdu.get_type());
  121.   if ((pdu.get_type() == REPORT_MSG) &&
  122.       (((tmpvb.get_oid() == oidUsmStatsUnknownEngineIDs) &&
  123. (cbData->reports_received == 0)) ||
  124.        ((tmpvb.get_oid() == oidUsmStatsNotInTimeWindows) &&
  125. (cbData->reports_received <= 1)))) {
  126.     // hide those reports from user
  127.     int rc;
  128.     if ((cbData->pdu) && (cbData->target)) {
  129.       rc = snmp->snmp_engine(*(cbData->pdu), cbData->non_reps,
  130.                              cbData->max_reps, *(cbData->target),
  131.                              (snmp_callback)(cbData->oldCallback),
  132.                              (void *)cbData->cbd, INVALID_SOCKET,
  133.      cbData->reports_received + 1);
  134.       debugprintf(3,"v3CallBack: snmp_engine called, rc (%i)", rc);
  135.     }
  136.     else
  137.       rc = SNMP_CLASS_ERROR;
  138.     if (rc != SNMP_CLASS_SUCCESS) {
  139.       // call callback if snmp_engine failed or pdu or target was 0
  140.       debugprintf(3,"v3CallBack: calling user callback");
  141.       snmp_callback tmp_callBack;
  142.       tmp_callBack = (snmp_callback)(cbData->oldCallback);
  143.       tmp_callBack(rc, snmp, pdu, target, (void *)cbData->cbd);
  144.     }
  145.   }
  146.   else {
  147.     debugprintf(3,"v3CallBack: calling user callback");
  148.     snmp_callback tmp_callBack;
  149.     tmp_callBack = (snmp_callback)(cbData->oldCallback);
  150.     tmp_callBack(reason, snmp, pdu, target, (void *)cbData->cbd);
  151.   }
  152.   // save to delete it here, because either snmp_engine created a new
  153.   // callback entry or the user specified callback has been called
  154.   if (cbData->pdu) {
  155.     delete cbData->pdu;
  156.     cbData->pdu = 0;
  157.   }
  158.   if (cbData->target) {
  159.     delete cbData->target;
  160.     cbData->target = 0;
  161.   }
  162.   delete cbData;
  163.   return;
  164. }
  165. #endif
  166. //--------[ make the pdu request id ]-----------------------------------
  167. // return a unique rid, clock can be too slow , so use current_rid
  168. long Snmp::MyMakeReqId()
  169. {
  170.   long rid;
  171.   eventListHolder->snmpEventList()->lock();
  172.   do {
  173.     rid = ++current_rid;
  174. #ifdef INVALID_REQID
  175.     debugprintf(-10, "nWARNING: Using constand RequestID!n");
  176.     rid = 0xc0de;
  177. #endif
  178.     if ( current_rid > PDU_MAX_RID)
  179.     {
  180.       current_rid = rid = PDU_MIN_RID;
  181.       // let other tasks proceed
  182.       eventListHolder->snmpEventList()->unlock();
  183.       struct timeval tv;
  184.       tv.tv_sec = 0;
  185.       tv.tv_usec = 100;
  186.       select(0, 0, 0, 0, &tv);
  187.       eventListHolder->snmpEventList()->lock();
  188.     }
  189.   } while (eventListHolder->snmpEventList()->GetEntry(rid));
  190.   eventListHolder->snmpEventList()->unlock();
  191.   return rid;
  192. }
  193. //---------[ Send SNMP Request ]---------------------------------------
  194. // Send out a snmp request
  195. DLLOPT int send_snmp_request(SnmpSocket sock, unsigned char *send_buf,
  196.                              size_t send_len, Address & address)
  197. {
  198.   // UX only supports UDP type addresses (addr and port) right now
  199.   if (address.get_type() != Address::type_udp)
  200.     return -1;// unsupported address type
  201.   debugprintf(1, "++ SNMP++: sending to %s:",
  202.               ((UdpAddress &)address).UdpAddress::get_printable());
  203.   debughexprintf(5, send_buf, SAFE_UINT_CAST(send_len));
  204.   int send_result;
  205.   if (((UdpAddress &)address).get_ip_version() == Address::version_ipv4)
  206.   {
  207.     // prepare the destination address
  208.     struct sockaddr_in agent_addr;  // send socket struct
  209.     memset(&agent_addr, 0, sizeof(agent_addr));
  210.     agent_addr.sin_family = AF_INET;
  211.     agent_addr.sin_addr.s_addr
  212.               = inet_addr(((IpAddress &)address).IpAddress::get_printable());
  213.     agent_addr.sin_port = htons(((UdpAddress &)address).get_port());
  214.     send_result = sendto(sock, (char*) send_buf, SAFE_INT_CAST(send_len), 0,
  215.                          (struct sockaddr*) &agent_addr, sizeof(agent_addr));
  216.   }
  217.   else
  218.   {
  219. #ifdef SNMP_PP_IPv6
  220.     struct sockaddr_in6 agent_addr;
  221.     memset(&agent_addr, 0, sizeof(agent_addr));
  222.     inet_pton(AF_INET6, ((IpAddress &)address).IpAddress::get_printable(),
  223.               &agent_addr.sin6_addr);
  224.     agent_addr.sin6_family = AF_INET6;
  225.     agent_addr.sin6_port = htons(((UdpAddress &)address).get_port());
  226.     send_result = sendto( sock, (char*) send_buf, send_len, 0,
  227.                           (struct sockaddr*) &agent_addr, sizeof(agent_addr));
  228. #else
  229.     debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
  230.     return -1;
  231. #endif
  232.   }
  233.   if (send_result < 0)
  234.   {
  235.     debugprintf(0, "Error sending packet: %s", strerror(errno));
  236.     return -1; // send error!
  237.   }
  238.   return 0;
  239. }
  240. //---------[ receive a snmp response ]---------------------------------
  241. // Receive a response from the specified socket.
  242. // This function does not set the request id in the pdu if
  243. // any error occur in receiving or parsing.  This is important
  244. // because the caller initializes this to zero and checks it to
  245. // see whether it has been changed to a valid value.  The
  246. // return value is the normal PDU status or SNMP_CLASS_SUCCESS.
  247. // when we are successful in receiving a pdu.  Otherwise it
  248. // is an error status.
  249. int receive_snmp_response(SnmpSocket sock, Snmp &snmp_session,
  250.                           Pdu &pdu, UdpAddress &fromaddress,
  251.   bool process_msg = true)
  252. {
  253.   unsigned char receive_buffer[MAX_SNMP_PACKET + 1];
  254.   long receive_buffer_len; // len of received data
  255. #ifdef SNMP_PP_IPv6
  256.   struct sockaddr_storage from_addr;
  257. #else
  258.   struct sockaddr_in from_addr;
  259. #endif
  260. #if !(defined (CPU) && CPU == PPC603) && (defined __GNUC__ || defined __FreeBSD__ || defined _AIX) && ! defined __MINGW32__
  261.   socklen_t fromlen;
  262. #else
  263.   int fromlen;
  264. #endif
  265.   fromlen = sizeof(from_addr);
  266.   memset(&from_addr, 0, sizeof(from_addr));
  267.   // do the read
  268.   do {
  269.     receive_buffer_len = (long) recvfrom(sock, (char *) receive_buffer,
  270.                                          MAX_SNMP_PACKET + 1, 0,
  271.                                          (struct sockaddr*) &from_addr,
  272.                                          &fromlen);
  273.     debugprintf(2, "++ SNMP++: something received...");
  274.   } while ((receive_buffer_len < 0) && (EINTR == errno));
  275.   if (receive_buffer_len < 0 )                // error or no data pending
  276.     return SNMP_CLASS_TL_FAILED;
  277.   debugprintf(6, "Length received %i from socket %i; fromlen %i",
  278.               receive_buffer_len, sock, fromlen);
  279.   if (receive_buffer_len == MAX_SNMP_PACKET + 1)
  280.   {
  281.     // Message is too long...
  282.     debugprintf(1, "Received message is ignored (packet too long)");
  283.     return SNMP_CLASS_ERROR;
  284.   }
  285.   if (((sockaddr_in&)from_addr).sin_family == AF_INET)
  286.   {
  287.     // IPv4
  288.     fromaddress = inet_ntoa(((sockaddr_in&)from_addr).sin_addr);
  289.     fromaddress.set_port(ntohs(((sockaddr_in&)from_addr).sin_port));
  290.   }
  291. #ifdef SNMP_PP_IPv6
  292.   else if (from_addr.ss_family == AF_INET6)
  293.   {
  294.     // IPv6
  295.     char tmp_buffer[INET6_ADDRSTRLEN+1];
  296.     inet_ntop(AF_INET6, &(((sockaddr_in6&)from_addr).sin6_addr),
  297.               tmp_buffer, INET6_ADDRSTRLEN);
  298.     fromaddress = tmp_buffer;
  299.     fromaddress.set_port(ntohs(((sockaddr_in6&)from_addr).sin6_port));
  300.   }
  301. #endif // SNMP_PP_IPv6
  302.   else
  303.   {
  304.     debugprintf(0, "Unknown socket address family (%i).",
  305.                 ((sockaddr_in&)from_addr).sin_family);
  306.     return SNMP_CLASS_ERROR;
  307.   }
  308.   debugprintf(1, "++ SNMP++: data received from %s.",
  309.               fromaddress.get_printable());
  310.   debughexprintf(5, receive_buffer, receive_buffer_len);
  311.   if (process_msg == false)
  312.     return SNMP_CLASS_SUCCESS;   // return success
  313.   SnmpMessage snmpmsg;
  314.   if ( snmpmsg.load( receive_buffer, receive_buffer_len) != SNMP_CLASS_SUCCESS)
  315.     return SNMP_CLASS_ERROR;
  316.   OctetStr community_name;
  317.   snmp_version version;
  318.   OctetStr engine_id;
  319.   OctetStr security_name;
  320. #ifdef _SNMPv3
  321.   long int security_model;
  322.   if (snmpmsg.is_v3_message() == TRUE)
  323.   {
  324.     int returncode = snmpmsg.unloadv3(pdu, version, engine_id,
  325.                                       security_name, security_model,
  326.                                       fromaddress, snmp_session);
  327.     if (returncode != SNMP_CLASS_SUCCESS)
  328.       return returncode;
  329.   }
  330.   else
  331.   {
  332. #endif
  333.     int returncode = snmpmsg.unload( pdu, community_name, version);
  334.     if (returncode != SNMP_CLASS_SUCCESS)
  335.       return SNMP_CLASS_ERROR;
  336. #ifdef _SNMPv3
  337.   }
  338.   if (version == version3) {
  339.     v3MP::I->add_to_engine_id_table(engine_id,
  340.        (char*)fromaddress.IpAddress::get_printable(),
  341.        fromaddress.get_port());
  342.     debugprintf(4,"receive_snmp_response: engine_id (%s), security_name (%s), "
  343. "security_model (%i), security_level (%i)",
  344.                 engine_id.get_printable(), security_name.get_printable(),
  345.                 security_model, pdu.get_security_level());
  346.     debugprintf(5," addtoengineidtable: (%s)",
  347.                 (unsigned char*)fromaddress.get_printable());
  348.   }
  349. #endif
  350.   //-----[ check for error status stuff..]
  351.   // an error status is a valid pdu,
  352.   // the caller needs to know about it
  353.   if ( pdu.get_error_status() != 0)
  354.     return pdu.get_error_status();
  355.   debugprintf(5,"receive_snmp_response requestID = %li, "
  356.       "returning SUCCESS.", pdu.get_request_id());
  357.   return SNMP_CLASS_SUCCESS;   // Success! return
  358. }
  359. //---------[ receive a snmp trap ]---------------------------------
  360. // Receive a trap from the specified socket
  361. // note: caller has to delete target!
  362. int receive_snmp_notification(SnmpSocket sock, Snmp &snmp_session,
  363.                               Pdu &pdu, SnmpTarget **target)
  364. {
  365.   unsigned char receive_buffer[MAX_SNMP_PACKET + 1];
  366.   long receive_buffer_len; // len of received data
  367. #ifdef SNMP_PP_IPv6
  368.   struct sockaddr_storage from_addr;
  369. #else
  370.   struct sockaddr_in from_addr;
  371. #endif // SNMP_PP_IPv6
  372. #if !(defined (CPU) && CPU == PPC603) && (defined __GNUC__ || defined __FreeBSD__ || defined _AIX) && ! defined __MINGW32__
  373.   socklen_t fromlen;
  374. #else
  375.   int fromlen;
  376. #endif
  377.   fromlen = sizeof(from_addr);
  378.   memset(&from_addr, 0, sizeof(from_addr));
  379.   // do the read
  380.   do {
  381.     receive_buffer_len = (long) recvfrom(sock, (char *) receive_buffer,
  382.                                          MAX_SNMP_PACKET + 1, 0,
  383.                                          (struct sockaddr*)&from_addr,
  384.                                          &fromlen);
  385.   } while (receive_buffer_len < 0 && EINTR == errno);
  386.   if (receive_buffer_len < 0 )                // error or no data pending
  387.     return SNMP_CLASS_TL_FAILED;
  388.   if (receive_buffer_len == MAX_SNMP_PACKET + 1)
  389.   {
  390.     // Message is too long...
  391.     debugprintf(1, "Received message is ignored (packet too long)");
  392.     return SNMP_CLASS_ERROR;
  393.   }
  394.   // copy fromaddress and remote port
  395.   UdpAddress fromaddress;
  396.   if (((sockaddr_in&)from_addr).sin_family == AF_INET)
  397.   {
  398.     // IPv4
  399.     fromaddress = inet_ntoa(((sockaddr_in&)from_addr).sin_addr);
  400.     fromaddress.set_port(ntohs(((sockaddr_in&)from_addr).sin_port));
  401.   }
  402. #ifdef SNMP_PP_IPv6
  403.   else if (from_addr.ss_family == AF_INET6)
  404.   {
  405.     // IPv6
  406.     char tmp_buffer[INET6_ADDRSTRLEN+1];
  407.     inet_ntop(AF_INET6, &(((sockaddr_in6&)from_addr).sin6_addr),
  408.               tmp_buffer, INET6_ADDRSTRLEN);
  409.     fromaddress = tmp_buffer;
  410.     fromaddress.set_port(ntohs(((sockaddr_in6&)from_addr).sin6_port));
  411.   }
  412. #endif // SNMP_PP_IPv6
  413.   else
  414.   {
  415.     debugprintf(0, "Unknown socket address family (%i).",
  416.                 ((sockaddr_in&)from_addr).sin_family);
  417.     return SNMP_CLASS_TL_FAILED;
  418.   }
  419.   debugprintf(1, "++ SNMP++: data received from %s.",
  420.               fromaddress.get_printable());
  421.   debughexprintf(5, receive_buffer, receive_buffer_len);
  422.   SnmpMessage snmpmsg;
  423.   if ( snmpmsg.load( receive_buffer, receive_buffer_len) != SNMP_CLASS_SUCCESS)
  424.     return SNMP_CLASS_ERROR;
  425.   OctetStr community_name;
  426.   snmp_version version;
  427.   OctetStr engine_id;
  428.   OctetStr security_name;
  429. #ifdef _SNMPv3
  430.   long int security_model;
  431.   if (snmpmsg.is_v3_message() == TRUE)
  432.   {
  433.     int returncode = snmpmsg.unloadv3(pdu, version, engine_id,
  434.                                       security_name, security_model,
  435.                                       fromaddress, snmp_session);
  436.     if (returncode != SNMP_CLASS_SUCCESS)
  437.       return returncode;
  438.   }
  439.   else
  440.   {
  441. #endif
  442.     int returncode = snmpmsg.unload( pdu, community_name, version);
  443.     if (returncode != SNMP_CLASS_SUCCESS)
  444.       return SNMP_CLASS_ERROR;
  445. #ifdef _SNMPv3
  446.   }
  447.   if (version == version3) {
  448.     *target = new UTarget();
  449.     (*target)->set_address(fromaddress);
  450.     (*target)->set_version(version);
  451.     ((UTarget*)*target)->set_engine_id(engine_id);
  452.     ((UTarget*)*target)->set_security_name(security_name);
  453.     ((UTarget*)*target)->set_security_model(security_model);
  454.     v3MP::I->add_to_engine_id_table(engine_id,
  455.                          (char*)((IpAddress &)fromaddress).get_printable(),
  456.                          fromaddress.get_port());
  457.     debugprintf(4,"receive_snmp_notification: engine_id (%s), security_name "
  458. "(%s), security_model (%i), security_level (%i)",
  459.                 engine_id.get_printable(), security_name.get_printable(),
  460.                 security_model, pdu.get_security_level());
  461.   }
  462.   else
  463.   {
  464. #endif
  465.     *target = new CTarget();
  466.     (*target)->set_version(version);
  467.     (*target)->set_address(fromaddress);
  468.     ((CTarget*)*target)->set_readcommunity( community_name);
  469.     ((CTarget*)*target)->set_writecommunity( community_name);
  470. #ifdef _SNMPv3
  471.   }
  472. #endif
  473.   return SNMP_CLASS_SUCCESS;   // Success! return
  474. }
  475. //--------[ map action ]------------------------------------------------
  476. // map the snmp++ action to a SMI pdu type
  477. void Snmp::map_action( unsigned short action, unsigned short & pdu_action)
  478. {
  479.   switch( action)
  480.     {
  481.     case sNMP_PDU_GET:
  482.     case sNMP_PDU_GET_ASYNC:
  483.       pdu_action = sNMP_PDU_GET;
  484.       break;
  485.     case sNMP_PDU_SET:
  486.     case sNMP_PDU_SET_ASYNC:
  487.       pdu_action = sNMP_PDU_SET;
  488.       break;
  489.     case sNMP_PDU_GETNEXT:
  490.     case sNMP_PDU_GETNEXT_ASYNC:
  491.       pdu_action = sNMP_PDU_GETNEXT;
  492.       break;
  493.     case sNMP_PDU_GETBULK:
  494.     case sNMP_PDU_GETBULK_ASYNC:
  495.       pdu_action = sNMP_PDU_GETBULK;
  496.       break;
  497.     case sNMP_PDU_RESPONSE:
  498.       pdu_action = sNMP_PDU_RESPONSE;
  499.       break;
  500.     case sNMP_PDU_INFORM:
  501.     case sNMP_PDU_INFORM_ASYNC:
  502.       pdu_action = sNMP_PDU_INFORM;
  503.       break;
  504.     case sNMP_PDU_REPORT:
  505.       pdu_action = sNMP_PDU_REPORT;
  506.       break;
  507.     default:
  508.       pdu_action = sNMP_PDU_GET;  // TM ?? error ??
  509.       break;
  510.     };  // end switch
  511. }
  512. //------[ Snmp Class Constructor ]--------------------------------------
  513. Snmp::Snmp(int &status, const unsigned short port, const bool bind_ipv6)
  514.     : SnmpSynchronized(),
  515.       m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
  516. {
  517.   IpAddress *addresses[2];
  518.   if (bind_ipv6)
  519.   {
  520.     listen_address = "::";
  521.     addresses[0] = NULL;
  522.     addresses[1] = &listen_address;
  523.     init(status, addresses, 0, port);
  524.   }
  525.   else
  526.   {
  527.     listen_address = "0.0.0.0";
  528.     addresses[0] = &listen_address;
  529.     addresses[1] = NULL;
  530.     init(status, addresses, port, 0);
  531.   }
  532. }
  533. Snmp::Snmp( int &status, const UdpAddress& addr)
  534.     : SnmpSynchronized(),
  535.       m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
  536. {
  537.   IpAddress *addresses[2];
  538.   listen_address = addr;
  539.   if (listen_address.get_ip_version() == Address::version_ipv4)
  540.   {
  541.     addresses[0] = &listen_address;
  542.     addresses[1] = NULL;
  543.     init(status, addresses, addr.get_port(), 0);
  544.   }
  545.   else
  546.   {
  547.     addresses[0] = NULL;
  548.     addresses[1] = &listen_address;
  549.     init(status, addresses, 0, addr.get_port());
  550.   }
  551. }
  552. Snmp::Snmp( int &status,  const UdpAddress& addr_v4,
  553.             const UdpAddress& addr_v6)
  554.     : SnmpSynchronized(),
  555.       m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
  556. {
  557.   IpAddress *addresses[2];
  558.   listen_address = addr_v4;
  559.   IpAddress address_v6((IpAddress)addr_v6);
  560.   addresses[0] = &listen_address;
  561.   addresses[1] = &address_v6;
  562.   init(status, addresses, addr_v4.get_port(), addr_v6.get_port());
  563. }
  564. void Snmp::socket_startup()
  565. {
  566. #ifdef WIN32
  567.   WSADATA WSAData;
  568.   (void)WSAStartup(0x0101, &WSAData);
  569. #endif
  570. }
  571. void Snmp::socket_cleanup()
  572. {
  573. #ifdef WIN32
  574.   int iRetValue = WSACleanup();
  575.   debugprintf(4, "WSACleanup: ReturnValue (%i)", iRetValue);
  576. #endif
  577. }
  578. void Snmp::init(int& status, IpAddress *addresses[2],
  579.                 const unsigned short port_v4,
  580.                 const unsigned short port_v6)
  581. {
  582.   eventListHolder = new EventListHolder(this);
  583.   // initialize the request_id
  584.   eventListHolder->snmpEventList()->lock();
  585. //  srand(time(0)); // better than nothing
  586.   current_rid = (rand() % (PDU_MAX_RID - PDU_MIN_RID -1)) + PDU_MIN_RID;
  587.   debugprintf(4, "Initialized request_id to %i.", current_rid);
  588.   eventListHolder->snmpEventList()->unlock();
  589.   // intialize all the trap receiving member variables
  590.   notifycallback = 0;
  591.   notifycallback_data = 0;
  592. #ifdef HPUX
  593.   int errno = 0;
  594. #endif
  595.   status = SNMP_CLASS_ERROR;
  596.   iv_snmp_session = INVALID_SOCKET;
  597.   iv_snmp_session_ipv6 = INVALID_SOCKET;
  598.   /* Open IPv4 socket */
  599.   if (addresses[0])
  600.   {
  601.     // open a socket to be used for the session
  602.     if (( iv_snmp_session = socket( AF_INET, SOCK_DGRAM,0)) == INVALID_SOCKET)
  603.     {
  604. #ifdef WIN32
  605.       int werr = WSAGetLastError();
  606.       debugprintf(1, "Call to socket throws error %d", werr);
  607.       if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
  608.         status = SNMP_CLASS_RESOURCE_UNAVAIL;
  609.       else if (WSAEHOSTDOWN == werr)
  610.         status = SNMP_CLASS_TL_FAILED;
  611.       else
  612.         status = SNMP_CLASS_TL_UNSUPPORTED;
  613. #else
  614.       if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
  615.         status = SNMP_CLASS_RESOURCE_UNAVAIL;
  616.       else if (EHOSTDOWN == errno)
  617.         status = SNMP_CLASS_TL_FAILED;
  618.       else
  619.         status = SNMP_CLASS_TL_UNSUPPORTED;
  620. #endif
  621.     }
  622.     else
  623.     {
  624.       // set up the manager socket attributes
  625.       unsigned long inaddr = inet_addr(addresses[0]->get_printable());
  626.       struct sockaddr_in mgr_addr;
  627.       memset(&mgr_addr, 0, sizeof(mgr_addr));
  628.       mgr_addr.sin_family = AF_INET;
  629.       mgr_addr.sin_addr.s_addr = inaddr;
  630.       mgr_addr.sin_port = htons( port_v4);
  631. #ifdef CYGPKG_NET_OPENBSD_STACK
  632.       mgr_addr.sin_len = sizeof(mgr_addr);
  633. #endif
  634.       // bind the socket
  635.       if (bind(iv_snmp_session, (struct sockaddr*)&mgr_addr,
  636.                sizeof(mgr_addr)) < 0)
  637.       {
  638. #ifdef WIN32
  639.         int werr = WSAGetLastError();
  640. debugprintf(1, "Call to bind throws error %d", werr);
  641.         if (WSAEADDRINUSE  == werr)
  642.           status = SNMP_CLASS_TL_IN_USE;
  643.         else if (WSAENOBUFS == werr)
  644.           status = SNMP_CLASS_RESOURCE_UNAVAIL;
  645.         else if (werr == WSAEAFNOSUPPORT)
  646.           status = SNMP_CLASS_TL_UNSUPPORTED;
  647.         else if (werr == WSAENETUNREACH)
  648.           status = SNMP_CLASS_TL_FAILED;
  649.         else if (werr == EACCES)
  650.           status = SNMP_CLASS_TL_ACCESS_DENIED;
  651.         else
  652.           status = SNMP_CLASS_INTERNAL_ERROR;
  653. #else
  654.         if (EADDRINUSE  == errno)
  655.           status = SNMP_CLASS_TL_IN_USE;
  656.         else if (ENOBUFS == errno)
  657.           status = SNMP_CLASS_RESOURCE_UNAVAIL;
  658.         else if (errno == EAFNOSUPPORT)
  659.           status = SNMP_CLASS_TL_UNSUPPORTED;
  660.         else if (errno == ENETUNREACH)
  661.           status = SNMP_CLASS_TL_FAILED;
  662.         else if (errno == EACCES)
  663.           status = SNMP_CLASS_TL_ACCESS_DENIED;
  664.         else
  665. {
  666.   debugprintf(0, "Uncatched errno value %d, returning internal error.",
  667.       errno);
  668.           status = SNMP_CLASS_INTERNAL_ERROR;
  669. }
  670. #endif
  671. close(iv_snmp_session);    // close the dynamic socket
  672. iv_snmp_session = INVALID_SOCKET;
  673.       }
  674.       else
  675.       {
  676.         status = SNMP_CLASS_SUCCESS;
  677. #ifdef SNMP_BROADCAST
  678.         int enable_broadcast = 1;
  679.         setsockopt(iv_snmp_session, SOL_SOCKET, SO_BROADCAST,
  680.                    (char*)&enable_broadcast, sizeof(enable_broadcast));
  681. #endif
  682.       }
  683.     }
  684.     if (status != SNMP_CLASS_SUCCESS)
  685.       return;
  686.   }
  687.   /* Open IPv6 socket */
  688.   if (addresses[1])
  689.   {
  690. #ifdef SNMP_PP_IPv6
  691.     // open a socket to be used for the session
  692.     if (( iv_snmp_session_ipv6 = socket( AF_INET6, SOCK_DGRAM,0)) 
  693. == INVALID_SOCKET)
  694.     {
  695. #ifdef WIN32
  696.       int werr = WSAGetLastError();
  697.       if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
  698.         status = SNMP_CLASS_RESOURCE_UNAVAIL;
  699.       else if (WSAEHOSTDOWN == werr)
  700.         status = SNMP_CLASS_TL_FAILED;
  701.       else
  702.         status = SNMP_CLASS_TL_UNSUPPORTED;
  703. #else
  704.       if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
  705.         status = SNMP_CLASS_RESOURCE_UNAVAIL;
  706.       else if (EHOSTDOWN == errno)
  707.         status = SNMP_CLASS_TL_FAILED;
  708.       else
  709.         status = SNMP_CLASS_TL_UNSUPPORTED;
  710. #endif
  711.     }
  712.     else
  713.     {
  714.       // set up the manager socket attributes
  715.       struct sockaddr_in6 mgr_addr;
  716.       memset(&mgr_addr, 0, sizeof(mgr_addr));
  717.       inet_pton(AF_INET6, addresses[1]->get_printable(), &mgr_addr.sin6_addr);
  718.       mgr_addr.sin6_family = AF_INET6;
  719.       mgr_addr.sin6_port = htons( port_v6);
  720.       // bind the socket
  721.       if (bind(iv_snmp_session_ipv6, (struct sockaddr*) &mgr_addr,
  722.                sizeof(mgr_addr)) < 0)
  723.       {
  724. #ifdef WIN32
  725.         int werr = WSAGetLastError();
  726.         if (WSAEADDRINUSE  == werr)
  727.           status = SNMP_CLASS_TL_IN_USE;
  728.         else if (WSAENOBUFS == werr)
  729.           status = SNMP_CLASS_RESOURCE_UNAVAIL;
  730.         else if (werr == WSAEAFNOSUPPORT)
  731.           status = SNMP_CLASS_TL_UNSUPPORTED;
  732.         else if (werr == WSAENETUNREACH)
  733.           status = SNMP_CLASS_TL_FAILED;
  734.         else if (werr == EACCES)
  735.           status = SNMP_CLASS_TL_ACCESS_DENIED;
  736.         else
  737.           status = SNMP_CLASS_INTERNAL_ERROR;
  738. #else
  739.         if (EADDRINUSE  == errno)
  740.           status = SNMP_CLASS_TL_IN_USE;
  741.         else if (ENOBUFS == errno)
  742.           status = SNMP_CLASS_RESOURCE_UNAVAIL;
  743.         else if (errno == EAFNOSUPPORT)
  744.           status = SNMP_CLASS_TL_UNSUPPORTED;
  745.         else if (errno == ENETUNREACH)
  746.           status = SNMP_CLASS_TL_FAILED;
  747.         else if (errno == EACCES)
  748.           status = SNMP_CLASS_TL_ACCESS_DENIED;
  749.         else
  750.           status = SNMP_CLASS_INTERNAL_ERROR;
  751. #endif
  752. close(iv_snmp_session_ipv6);    // close the dynamic socket
  753. iv_snmp_session_ipv6 = INVALID_SOCKET;
  754.       }
  755.       else
  756.       {
  757.         status = SNMP_CLASS_SUCCESS;
  758. #ifdef SNMP_BROADCAST
  759.         int enable_broadcast = 1;
  760.         setsockopt(iv_snmp_session_ipv6, SOL_SOCKET, SO_BROADCAST,
  761.                    (char*)&enable_broadcast, sizeof(enable_broadcast));
  762. #endif
  763.       }
  764.     }
  765. #else
  766.     debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
  767. #endif // SNMP_PP_IPv6
  768.   }
  769.   return;
  770. }
  771. //---------[ Snmp Class Destructor ]----------------------------------
  772. Snmp::~Snmp()
  773. {
  774.   stop_poll_thread();
  775.   // if we failed during construction then don't try
  776.   // to free stuff up that was not allocated
  777.   if (iv_snmp_session != INVALID_SOCKET)
  778.   {
  779.     // go through the snmpEventList and delete any outstanding
  780.     // events on this socket
  781.     eventListHolder->snmpEventList()->DeleteSocketEntry(iv_snmp_session);
  782.     close(iv_snmp_session);    // close the dynamic socket
  783.   }
  784.   // if we failed during construction then don't try
  785.   // to free stuff up that was not allocated
  786.   if (iv_snmp_session_ipv6 != INVALID_SOCKET)
  787.   {
  788.     // go through the snmpEventList and delete any outstanding
  789.     // events on this socket
  790.     eventListHolder->snmpEventList()->DeleteSocketEntry(iv_snmp_session_ipv6);
  791.     close(iv_snmp_session_ipv6);    // close the dynamic socket
  792.   }
  793.   // shut down trap reception if used
  794.   notify_unregister();
  795.   delete eventListHolder;
  796. }
  797. // Get the version of the snmp++ library at runtime
  798. // This function MUST stay in the cpp file!
  799. const char *Snmp::get_version()
  800. {
  801.   return SNMP_PP_VERSION_STRING;
  802. }
  803. //-------------------[ returns error string ]--------------------------
  804. const char *Snmp::error_msg(const int c)
  805. {
  806. #ifdef _SNMPv3
  807.   if (c>=SNMPv3_USM_MIN_ERROR)
  808.     return ((c>SNMPv3_USM_MAX_ERROR)?pv3Errs[SNMPv3_USM_ERRORCOUNT]:pv3Errs[c-SNMPv3_USM_MIN_ERROR]);
  809.   if (c<=SNMPv3_MP_MAX_ERROR)
  810.     return ((c<SNMPv3_MP_MIN_ERROR)?nv3Errs[SNMPv3_MP_ERRORCOUNT]:nv3Errs[SNMPv3_MP_MAX_ERROR - c]);
  811. #endif
  812.   return ((c<0)?
  813.           ((c<MAX_NEG_ERROR)?nErrs[-(MAX_NEG_ERROR)+1]:nErrs[-c]):
  814.           ((c>MAX_POS_ERROR)?pErrs[MAX_POS_ERROR+1]:pErrs[c]));
  815. }
  816. #ifdef _SNMPv3
  817. const char* Snmp::error_msg(const Oid& v3Oid)
  818. {
  819.   // UsmStats
  820.   if (v3Oid == oidUsmStatsUnsupportedSecLevels)
  821.     return error_msg(SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL);
  822.   if (v3Oid == oidUsmStatsNotInTimeWindows)
  823.     return error_msg(SNMPv3_USM_NOT_IN_TIME_WINDOW);
  824.   if (v3Oid == oidUsmStatsUnknownUserNames )
  825.     return error_msg(SNMPv3_USM_UNKNOWN_SECURITY_NAME);
  826.   if (v3Oid == oidUsmStatsUnknownEngineIDs)
  827.     return error_msg(SNMPv3_USM_UNKNOWN_ENGINEID);
  828.   if (v3Oid == oidUsmStatsWrongDigests)
  829.     return error_msg(SNMPv3_USM_AUTHENTICATION_FAILURE);
  830.   if (v3Oid == oidUsmStatsDecryptionErrors)
  831.     return error_msg(SNMPv3_USM_DECRYPTION_ERROR);
  832.   // MPDstats
  833.   if (v3Oid == oidSnmpUnknownSecurityModels)
  834.     return error_msg(SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL);
  835.   if (v3Oid == oidSnmpInvalidMsgs)
  836.     return error_msg(SNMPv3_MP_INVALID_MESSAGE);
  837.   if (v3Oid == oidSnmpUnknownPDUHandlers)
  838.     return error_msg(SNMPv3_MP_UNKNOWN_PDU_HANDLERS);
  839.   if (v3Oid == oidSnmpUnavailableContexts)
  840.     return error_msg(SNMPv3_MP_UNAVAILABLE_CONTEXT);
  841.   if (v3Oid == oidSnmpUnknownContexts)
  842.     return error_msg(SNMPv3_MP_UNKNOWN_CONTEXT);
  843.   return error_msg(MAX_POS_ERROR + 1);
  844. }
  845. #endif
  846. //------------------------[ get ]---------------------------------------
  847. int Snmp::get(Pdu &pdu, const SnmpTarget &target)
  848. {
  849.   pdu.set_type( sNMP_PDU_GET);
  850.   return snmp_engine( pdu, 0, 0, target, NULL, 0);
  851. }
  852. //------------------------[ get async ]----------------------------------
  853. int Snmp::get(Pdu &pdu, const SnmpTarget &target,
  854.               const snmp_callback callback,
  855.               const void * callback_data)
  856. {
  857.   pdu.set_type( sNMP_PDU_GET_ASYNC);
  858.   return snmp_engine( pdu, 0, 0, target, callback, callback_data);
  859. }
  860. //------------------------[ get next ]-----------------------------------
  861. int Snmp::get_next(Pdu &pdu, const SnmpTarget &target)
  862. {
  863.   pdu.set_type( sNMP_PDU_GETNEXT);
  864.   return snmp_engine( pdu, 0, 0, target, NULL, 0);
  865. }
  866. //------------------------[ get next async ]-----------------------------
  867. int Snmp::get_next(Pdu &pdu, const SnmpTarget &target,
  868.                    const snmp_callback callback,
  869.                    const void * callback_data)
  870. {
  871.   pdu.set_type( sNMP_PDU_GETNEXT_ASYNC);
  872.   return snmp_engine( pdu, 0, 0, target, callback, callback_data);
  873. }
  874. //-------------------------[ set ]---------------------------------------
  875. int Snmp::set(Pdu &pdu, const SnmpTarget &target)
  876. {
  877.   pdu.set_type( sNMP_PDU_SET);
  878.   return snmp_engine( pdu, 0, 0, target, NULL, 0);
  879. }
  880. //------------------------[ set async ]----------------------------------
  881. int Snmp::set(Pdu &pdu, const SnmpTarget &target,
  882.               const snmp_callback callback,
  883.               const void * callback_data)
  884. {
  885.   pdu.set_type( sNMP_PDU_SET_ASYNC);
  886.   return snmp_engine( pdu, 0, 0, target, callback, callback_data);
  887. }
  888. //-----------------------[ get bulk ]------------------------------------
  889. int Snmp::get_bulk(Pdu &pdu,                // pdu to use
  890.                    const SnmpTarget &target,// destination target
  891.                    const int non_repeaters, // number of non repeaters
  892.                    const int max_reps)      // maximum number of repetitions
  893. {
  894.   pdu.set_type( sNMP_PDU_GETBULK);
  895.   return snmp_engine( pdu, non_repeaters, max_reps, target, NULL, 0);
  896. }
  897. //-----------------------[ get bulk async ]------------------------------
  898. int Snmp::get_bulk(Pdu &pdu,                 // pdu to use
  899.                    const SnmpTarget &target, // destination target
  900.                    const int non_repeaters,  // number of non repeaters
  901.                    const int max_reps,       // maximum number of repetitions
  902.                    const snmp_callback callback,// callback to use
  903.                    const void * callback_data)  // callback data
  904. {
  905.   pdu.set_type( sNMP_PDU_GETBULK_ASYNC);
  906.   return snmp_engine( pdu, non_repeaters, max_reps, target,
  907.                       callback, callback_data);
  908. }
  909. //------------------------[ inform_response ]----------------------------
  910. int Snmp::response(Pdu &pdu,                 // pdu to use
  911.                    const SnmpTarget &target, // response target
  912.    const SnmpSocket fd)
  913. {
  914.   pdu.set_type( sNMP_PDU_RESPONSE);
  915.   return snmp_engine(pdu, 0, 0, target, NULL, 0, fd);
  916. }
  917. int Snmp::send_raw_data(unsigned char *send_buf,
  918.                         size_t send_len, UdpAddress &address, SnmpSocket fd)
  919.   REENTRANT(
  920. {
  921.   if (fd != INVALID_SOCKET)
  922.     return send_snmp_request(fd, send_buf, send_len, address);
  923.   else
  924.   {
  925.     if (address.get_ip_version() == Address::version_ipv4)
  926.     {
  927.       if (iv_snmp_session != INVALID_SOCKET)
  928. return send_snmp_request(iv_snmp_session, send_buf,
  929.  send_len, address);
  930.       else
  931. address.map_to_ipv6();
  932.     }
  933.     return send_snmp_request(iv_snmp_session_ipv6, send_buf,
  934.      send_len, address);
  935.   }
  936. })
  937. //-----------------------[ cancel ]--------------------------------------
  938. int Snmp::cancel( const unsigned long request_id)
  939. {
  940.   eventListHolder->snmpEventList()->lock();
  941.   int status = eventListHolder->snmpEventList()->DeleteEntry(request_id);
  942.   eventListHolder->snmpEventList()->unlock();
  943.   return status;
  944. }
  945. //----------------------[ sending report, V3 only]-----------------------
  946. int Snmp::report(Pdu &pdu,                // pdu to send
  947.                  const SnmpTarget &target)// destination target
  948. {
  949.   pdu.set_type( sNMP_PDU_REPORT);
  950.   return snmp_engine( pdu, 0, 0, target, NULL, 0);
  951. }
  952. //----------------------[ blocking inform, V2 only]------------------------
  953. int Snmp::inform(Pdu &pdu,                // pdu to send
  954.                  const SnmpTarget &target)// destination target
  955. {
  956.   pdu.set_type( sNMP_PDU_INFORM);
  957.   check_notify_timestamp(pdu);
  958.   return snmp_engine( pdu, 0, 0, target, NULL, 0);
  959. }
  960. //----------------------[ asynch inform, V2 only]------------------------
  961. int Snmp::inform(Pdu &pdu,                // pdu to send
  962.                  const SnmpTarget &target,      // destination target
  963.                  const snmp_callback callback,  // callback function
  964.                  const void * callback_data)    // callback data
  965. {
  966.   pdu.set_type( sNMP_PDU_INFORM);
  967.   check_notify_timestamp(pdu);
  968.   return snmp_engine( pdu, 0, 0, target, callback, callback_data);
  969. }
  970. //---------------------[ send a trap ]-----------------------------------
  971. int Snmp::trap(Pdu &pdu,                        // pdu to send
  972.                const SnmpTarget &target)        // destination target
  973. {
  974.   OctetStr my_get_community;
  975.   OctetStr my_set_community;
  976.   GenAddress address;
  977.   unsigned long my_timeout;
  978.   int my_retry;
  979.   unsigned char version;
  980.   int status;
  981.   debugprintf(1, "++ SNMP++, Send a Trap");
  982.   //---------[ make sure pdu is valid ]---------------------------------
  983.   if ( !pdu.valid())
  984.     {
  985.       debugprintf(0, "-- SNMP++, PDU Object Invalid");
  986.       return  SNMP_CLASS_INVALID_PDU;
  987.     }
  988.   //---------[ make sure target is valid ]------------------------------
  989.   if ( !target.valid())
  990.     {
  991.       debugprintf(0, "-- SNMP++, Target Object Invalid");
  992.       return SNMP_CLASS_INVALID_TARGET;
  993.     }
  994.   CTarget* ctarget = NULL;
  995.   UTarget* utarget = NULL;
  996.   OctetStr security_name;
  997.   int security_model;
  998.   switch (target.get_type()) {
  999.     case SnmpTarget::type_ctarget:
  1000.       ctarget = (CTarget*)(&target);
  1001.       break;
  1002.     case SnmpTarget::type_utarget:
  1003.       utarget = (UTarget*)(&target);
  1004.       break;
  1005.     case SnmpTarget::type_base:
  1006.       debugprintf(0, "-- SNMP++, do not use SnmpTarget, use a  CTarget or UTarget");
  1007.       return SNMP_CLASS_INVALID_TARGET;
  1008.     default:
  1009.       // target is not known
  1010.       debugprintf(0, "-- SNMP++, type of target is unknown!");
  1011.       return SNMP_CLASS_UNSUPPORTED;
  1012.   }
  1013.   if (ctarget) {
  1014.     debugprintf(3, "snmp::trap called with CTarget");
  1015.     if (!ctarget->resolve_to_C( my_get_community, my_set_community, address,
  1016.                                 my_timeout, my_retry, version))
  1017.     {
  1018.       debugprintf(0, "-- SNMP++, Resolve Fail (CTarget)");
  1019.       return SNMP_CLASS_UNSUPPORTED;
  1020.     }
  1021. #ifdef _SNMPv3
  1022.     if (version == version3)
  1023.     {
  1024.       debugprintf(0, "-- SNMP++, use UTarget for SNMPv3");
  1025.       return SNMP_CLASS_INVALID_TARGET;
  1026.     }
  1027. #endif
  1028.   }
  1029.   else { // target is not a CTarget:
  1030.     if (utarget) {
  1031.       debugprintf(3, "trap called with UTarget");
  1032.       if (!utarget->resolve_to_U( security_name, security_model, address,
  1033.   my_timeout, my_retry, version))
  1034.       {
  1035.         debugprintf(0, "-- SNMP++, Resolve Fail (UTarget)");
  1036.         return SNMP_CLASS_UNSUPPORTED;
  1037.       }
  1038. #ifdef _SNMPv3
  1039.       if (version != version3) {
  1040. #endif
  1041.         my_get_community = security_name;
  1042.         if ((security_model != SecurityModel_v1) &&
  1043.             (security_model != SecurityModel_v2)) {
  1044.           debugprintf(0, "-- SNMP++, Target contains invalid security_model/version combination");
  1045.           return SNMP_CLASS_INVALID_TARGET;
  1046.         }
  1047. #ifdef _SNMPv3
  1048.       } // end if (version != version3)
  1049. #endif
  1050.     }
  1051.     else { // target is neither CTarget nor UTarget:
  1052.       debugprintf(0, "-- SNMP++, Resolve Fail");
  1053.       return SNMP_CLASS_INVALID_TARGET;
  1054.     }
  1055.   }
  1056.   //--------[ determine request id to use ]------------------------------
  1057.   pdu.set_request_id( MyMakeReqId());
  1058.   //--------[ check timestamp, if null use system time ]-----------------
  1059.   check_notify_timestamp(pdu);
  1060.   //------[ validate address to use ]-------------------------------------
  1061.   if (!address.valid()) {
  1062.     debugprintf(0, "-- SNMP++, Bad address");
  1063.     return SNMP_CLASS_INVALID_TARGET;
  1064.   }
  1065.   if ((address.get_type() != Address::type_ip) &&
  1066.       (address.get_type() != Address::type_udp) )
  1067.     {
  1068.       debugprintf(0, "-- SNMP++, Bad address type");
  1069.       return SNMP_CLASS_TL_UNSUPPORTED;
  1070.     }
  1071.   UdpAddress udp_address(address);
  1072.   if (!udp_address.valid()) {
  1073.     debugprintf(0, "-- SNMP++, copy address failed");
  1074.     return SNMP_CLASS_RESOURCE_UNAVAIL;
  1075.   }
  1076.   //----------[ choose the target address port ]-----------------------
  1077.   if ((address.get_type() == Address::type_ip) || !udp_address.get_port())
  1078.     udp_address.set_port(SNMP_TRAP_PORT);
  1079.   //----------[ based on the target type, choose v1 or v1 trap type ]-----
  1080.   if ( version == version1)
  1081.     pdu.set_type( sNMP_PDU_V1TRAP);
  1082.   else // v2 and v3 use v2TRAP
  1083.     pdu.set_type( sNMP_PDU_TRAP);
  1084.   SnmpMessage snmpmsg;
  1085. #ifdef _SNMPv3
  1086.   if ( version == version3) {
  1087.     OctetStr engine_id = v3MP::I->get_local_engine_id();
  1088.     if (!utarget) {
  1089.       debugprintf(0, "-- SNMP++, dont know how to handle SNMPv3 without UTarget!");
  1090.       return SNMP_CLASS_INVALID_TARGET;
  1091.     }
  1092.     // set context_engine_id of pdu, if it is not set
  1093.     if (pdu.get_context_engine_id().len() == 0)
  1094.     {
  1095.       debugprintf(8, "Setting contextEngineID of Pdu to (%s)",
  1096.                   engine_id.get_printable());
  1097.       pdu.set_context_engine_id(engine_id);
  1098.     }
  1099.     debugprintf(4,"Snmp::trap:");
  1100.     debugprintf(4," engineID (%s), securityName (%s)n securityModel (%i) security_level (%i)",
  1101.                 engine_id.get_printable(), security_name.get_printable(),
  1102.                 security_model, pdu.get_security_level());
  1103.     debugprintf(4," Addr/Port (%s)",udp_address.get_printable());
  1104.     status = snmpmsg.loadv3( pdu, engine_id, security_name,
  1105.                              security_model, (snmp_version)version);
  1106.   }
  1107.   else
  1108. #endif
  1109.     status = snmpmsg.load( pdu, my_get_community, (snmp_version) version);
  1110.   if ( status != SNMP_CLASS_SUCCESS) {
  1111.     debugprintf(0, "snmp message load error!");
  1112.     return status;
  1113.   }
  1114.   lock();
  1115.   //------[ send the trap ]
  1116.   if (udp_address.get_ip_version() == Address::version_ipv4)
  1117.   {
  1118.     if (iv_snmp_session != INVALID_SOCKET)
  1119.       status = send_snmp_request(iv_snmp_session,
  1120.  snmpmsg.data(), (size_t)snmpmsg.len(),
  1121.  udp_address);
  1122.     else
  1123.     {
  1124.       udp_address.map_to_ipv6();
  1125.       status = send_snmp_request(iv_snmp_session_ipv6,
  1126.  snmpmsg.data(), (size_t)snmpmsg.len(),
  1127.  udp_address);
  1128.     }
  1129.   }
  1130.   else
  1131.     status = send_snmp_request(iv_snmp_session_ipv6,
  1132.                                snmpmsg.data(), (size_t)snmpmsg.len(),
  1133.                                udp_address);
  1134.   unlock();
  1135.   if (status != 0)
  1136.     return SNMP_CLASS_TL_FAILED;
  1137.   return SNMP_CLASS_SUCCESS;
  1138. }
  1139. //----------------[ set notify_timestamp if it is null ]-------------
  1140. #if defined (CPU) && CPU == PPC603
  1141.   struct SCommTimer
  1142.   {
  1143. unsigned long NumMS;
  1144. unsigned long FractMS;
  1145.   };
  1146.   extern "C"
  1147.   {
  1148.   void GetTime (struct SCommTimer *  Time);
  1149.   }
  1150. #endif
  1151. void Snmp::check_notify_timestamp(Pdu &pdu)
  1152. {
  1153.   // As we don't know, when the application was started,
  1154.   // use a continuously increasing notify_timestamp
  1155.   TimeTicks timestamp;
  1156.   pdu.get_notify_timestamp( timestamp);
  1157.   if (timestamp <= 0)
  1158.   {
  1159. #ifdef WIN32
  1160.     struct _timeb timebuffer;
  1161.     _ftime( &timebuffer );
  1162.     timebuffer.time -= 1103760000;   // knock off 35 years worth of seconds
  1163.     timestamp = SAFE_ULONG_CAST((timebuffer.time * 100) +
  1164. (timebuffer.millitm / 10));
  1165. #elif defined (CPU) && CPU == PPC603
  1166.     SCommTimer theTime;
  1167.     GetTime(&theTime); // This function must be defined by the application
  1168.     timestamp = theTime.NumMS/10;
  1169. #else
  1170.     struct timeval tp;
  1171.     gettimeofday(&tp, NULL);
  1172.     tp.tv_sec -= 1103760000;   // knock off 35 years worth of seconds
  1173.     timestamp = (tp.tv_sec * 100) + (tp.tv_usec / 10000);
  1174. #endif
  1175.     pdu.set_notify_timestamp( timestamp);
  1176.   }
  1177. }
  1178. //-----------------------[ read the notification filters ]----------------
  1179. int Snmp::get_notify_filter( OidCollection &trapids,
  1180.                              TargetCollection &targets,
  1181.      AddressCollection &listen_addresses)
  1182. {
  1183.   CNotifyEvent *e = eventListHolder->notifyEventList()->GetEntry(this);
  1184.   if (!e)  return SNMP_CLASS_INVALID;
  1185.   e->get_filter(trapids, targets, listen_addresses);
  1186.   return SNMP_CLASS_SUCCESS;
  1187. }
  1188. // Set the port for listening to traps and informs.
  1189. void Snmp::notify_set_listen_port(const int port)
  1190. {
  1191.   eventListHolder->notifyEventList()->set_listen_port(port);
  1192. }
  1193. // Get the port that is used for listening to traps and informs.
  1194. int Snmp::notify_get_listen_port()
  1195. {
  1196.   return eventListHolder->notifyEventList()->get_listen_port();
  1197. }
  1198. //-----------------------[ register to get traps]-------------------------
  1199. int Snmp::notify_register( const OidCollection     &trapids,
  1200.                            const TargetCollection  &targets,
  1201.                            const AddressCollection &addresses,
  1202.                            const snmp_callback      callback,
  1203.                            const void              *callback_data)
  1204. {
  1205.   int status;
  1206.   // assign callback and callback data info
  1207.   notifycallback = callback;
  1208.   notifycallback_data = (void *)callback_data;
  1209.   // remove any previous filters for this session
  1210.   eventListHolder->notifyEventList()->DeleteEntry(this);
  1211.   // add to the notify queue
  1212.   status = eventListHolder->notifyEventList()->AddEntry(this, trapids,
  1213. targets, addresses);
  1214.   iv_notify_fd = eventListHolder->notifyEventList()->get_notify_fd(); // DLD
  1215.   return status;
  1216. }
  1217. // alternate form for local listen specification
  1218. //-----------------------[ register to get traps]-------------------------
  1219. int Snmp::notify_register( const OidCollection    &trapids,
  1220.                            const TargetCollection &targets,
  1221.                            const snmp_callback     callback,
  1222.                            const void             *callback_data)
  1223. {
  1224.   AddressCollection addresses;
  1225.   return notify_register(trapids, targets, addresses,
  1226.                          callback, callback_data);
  1227. }
  1228. //-----------------------[ un-register to get traps]----------------------
  1229. int Snmp::notify_unregister()
  1230. {
  1231.   /// @todo Return error if not registered before!
  1232.   // remove from the notify queue
  1233.   eventListHolder->notifyEventList()->DeleteEntry(this);
  1234.   // null out callback information
  1235.   notifycallback = 0;
  1236.   notifycallback_data = 0;
  1237.   iv_notify_fd = INVALID_SOCKET;
  1238.   return SNMP_CLASS_SUCCESS;
  1239. }
  1240. //---------[ get / set engine ]-----------------------------------------
  1241. // The main snmp engine used for all requests
  1242. // async requests return out early and don't wait in here for
  1243. // the response
  1244. int Snmp::snmp_engine( Pdu &pdu,              // pdu to use
  1245.                        long int non_reps,     // # of non repititions
  1246.                        long int max_reps,     // # of max repititions
  1247.                        const SnmpTarget &target,    // from this target
  1248.                        const snmp_callback cb,// callback for async calls
  1249.                        const void *cbd,      // callback data
  1250.        SnmpSocket fd,
  1251.        int reports_received)
  1252. {
  1253.   long req_id;                       // pdu request id
  1254.   int status;                        // send status
  1255. #ifdef _SNMPv3
  1256.   // save original PDU for later reference
  1257.   Pdu backupPdu = pdu;
  1258.   for (int maxloops=0; maxloops<3; maxloops++)
  1259.   {
  1260. #endif
  1261.     unsigned short pdu_action;        // type of pdu to build
  1262.     unsigned short action;        // type of pdu to build
  1263.     unsigned long my_timeout;        // target specific timeout
  1264.     int my_retry;                // target specific retry
  1265.     OctetStr my_get_community;
  1266.     OctetStr my_set_community;
  1267.     GenAddress address;
  1268.     unsigned char version;
  1269.     //---------[ make sure pdu is valid ]--------------------------
  1270.     if ( !pdu.valid())
  1271.       return  SNMP_CLASS_INVALID_PDU;
  1272.     //---------[ depending on user action, map the correct pdu action]
  1273.     action = pdu.get_type();
  1274.     map_action(action, pdu_action);
  1275.     //---------[ check for correct mode ]---------------------------
  1276.     // if the class was constructed as a blocked model, callback=0
  1277.     // and async calls are attempted, an error is returned
  1278.     if (( cb == 0) &&
  1279.         ((action == sNMP_PDU_GET_ASYNC) ||
  1280.          (action == sNMP_PDU_SET_ASYNC) ||
  1281.          (action == sNMP_PDU_GETNEXT_ASYNC) ||
  1282.          (action == sNMP_PDU_GETBULK_ASYNC) ||
  1283.          (action == sNMP_PDU_INFORM_ASYNC)))
  1284.       return SNMP_CLASS_INVALID_CALLBACK;
  1285.     //---------[ more mode checking ]--------------------------------
  1286.     // if the class was constructed as an async model, callback = something
  1287.     // and blocked calls are attempted, an error is returned
  1288.     if (( cb != 0) &&
  1289.         ((action == sNMP_PDU_GET) ||
  1290.          (action == sNMP_PDU_SET) ||
  1291.          (action == sNMP_PDU_GETNEXT) ||
  1292.          (action == sNMP_PDU_GETBULK) ||
  1293.          (action == sNMP_PDU_INFORM)))
  1294.       return SNMP_CLASS_INVALID_CALLBACK;
  1295.     //---------[ make sure target is valid ]-------------------------
  1296.     // make sure that the target is valid
  1297.     if ( ! target.valid())
  1298.       return SNMP_CLASS_INVALID_TARGET;
  1299.     OctetStr community_string;
  1300.     OctetStr security_name;
  1301.     int security_model;
  1302.     const CTarget* ctarget = NULL;
  1303.     const UTarget* utarget = NULL;
  1304.     switch (target.get_type())
  1305.     {
  1306.       case SnmpTarget::type_ctarget:
  1307.         ctarget = (CTarget*)(&target);
  1308.         break;
  1309.       case SnmpTarget::type_utarget:
  1310.         utarget = (UTarget*)(&target);
  1311.         break;
  1312.       case SnmpTarget::type_base:
  1313.         debugprintf(0, "-- SNMP++, do not use SnmpTarget,"
  1314.                     "use a  CTarget or UTarget");
  1315.         return SNMP_CLASS_INVALID_TARGET;
  1316.       default:
  1317.         /* target is not known */
  1318.         debugprintf(0, "-- SNMP++, type of target is unknown!");
  1319.         return SNMP_CLASS_UNSUPPORTED;
  1320.     }
  1321.     if (ctarget) /* Is is a CTarget? */
  1322.     {
  1323.       debugprintf(3, "snmp_engine called with CTarget");
  1324.       if (!ctarget->resolve_to_C( my_get_community, my_set_community,
  1325.                                   address, my_timeout, my_retry, version))
  1326.       {
  1327.         debugprintf(0, "-- SNMP++, Resolve Fail (CTarget)");
  1328.         return SNMP_CLASS_UNSUPPORTED;
  1329.       }
  1330. #ifdef _SNMPv3
  1331.       if ((version == version3) ||
  1332.           (action == sNMP_PDU_REPORT))
  1333.       {
  1334.         debugprintf(0, "-- SNMP++, use UTarget for SNMPv3");
  1335.         return SNMP_CLASS_INVALID_TARGET;
  1336.       }
  1337. #endif
  1338.       //----------[ use the appropriate community string ]-----------------
  1339.       if (( action == sNMP_PDU_GET) ||
  1340.           ( action == sNMP_PDU_GET_ASYNC) ||
  1341.           ( action == sNMP_PDU_GETNEXT) ||
  1342.           ( action == sNMP_PDU_GETNEXT_ASYNC) ||
  1343.           ( action == sNMP_PDU_GETBULK) ||
  1344.           ( action == sNMP_PDU_GETBULK_ASYNC) ||
  1345.           ( action == sNMP_PDU_INFORM) ||
  1346.           ( action == sNMP_PDU_INFORM_ASYNC) ||
  1347.           ( action == sNMP_PDU_RESPONSE))
  1348.         community_string = my_get_community;
  1349.       else /* got to be a set */
  1350.         community_string = my_set_community;
  1351.     }
  1352.     else if (utarget)  /* Is is a UTarget? */
  1353.     {
  1354.       debugprintf(3, "snmp_engine called with UTarget");
  1355.       if (!utarget->resolve_to_U( security_name, security_model,
  1356.                                   address, my_timeout,
  1357.                                   my_retry, version))
  1358.       {
  1359.         debugprintf(0, "-- SNMP++, Resolve Fail (UTarget)");
  1360.         return SNMP_CLASS_UNSUPPORTED;
  1361.       }
  1362. #ifdef _SNMPv3
  1363.       if (version != version3)
  1364.       {
  1365. #endif
  1366.         community_string = security_name;
  1367.         if ((security_model != SecurityModel_v1) &&
  1368.             (security_model != SecurityModel_v2)) {
  1369.           debugprintf(0, "-- SNMP++, Target contains invalid security_model/version combination");
  1370.           return SNMP_CLASS_INVALID_TARGET;
  1371.         }
  1372. #ifdef _SNMPv3
  1373.       } // end if (version != version3)
  1374. #endif
  1375.     }
  1376.     else
  1377.     { // target is neither CTarget nor UTarget (should not happen)
  1378.       debugprintf(0, "-- SNMP++, Resolve Fail");
  1379.       return SNMP_CLASS_INVALID_TARGET;
  1380.     }
  1381.     if (!address.valid())
  1382.     {
  1383.       debugprintf(0, "-- SNMP++, Target contains invalid address");
  1384.       return SNMP_CLASS_INVALID_TARGET;
  1385.     }
  1386.     //----------[ validate the target address ]--------------------------
  1387.     if ((address.get_type() != Address::type_ip) &&
  1388.         (address.get_type() != Address::type_udp) )
  1389.     {
  1390.       debugprintf(0, "-- SNMP++, Bad address type");
  1391.       return SNMP_CLASS_TL_UNSUPPORTED;
  1392.     }
  1393.     UdpAddress udp_address(address);
  1394.     if (!udp_address.valid())
  1395.     {
  1396.       debugprintf(0, "-- SNMP++, Bad address");
  1397.       return SNMP_CLASS_RESOURCE_UNAVAIL;
  1398.     }
  1399.     //----------[ choose the target address port ]-----------------------
  1400.     if ((address.get_type() == Address::type_ip) || !udp_address.get_port())
  1401.     {
  1402.       if (pdu_action == sNMP_PDU_INFORM)
  1403.         udp_address.set_port(SNMP_TRAP_PORT);
  1404.       else
  1405.         udp_address.set_port(SNMP_PORT);
  1406.     }
  1407.     // otherwise port was already set
  1408.     // check socket to use
  1409.     SnmpSocket iv_session_used = fd;
  1410.     if (fd == INVALID_SOCKET)
  1411.     {
  1412.       if (udp_address.get_ip_version() == Address::version_ipv4)
  1413.       {
  1414.         if (iv_snmp_session != INVALID_SOCKET)
  1415.   iv_session_used = iv_snmp_session;
  1416. else
  1417. {
  1418.   udp_address.map_to_ipv6();
  1419.   iv_session_used = iv_snmp_session_ipv6;
  1420. }
  1421.       }
  1422.       else
  1423. iv_session_used = iv_snmp_session_ipv6;
  1424.     }
  1425.     if ((pdu_action != sNMP_PDU_RESPONSE) &&
  1426.         (pdu_action != sNMP_PDU_REPORT))
  1427.     {
  1428.       // set error index to none
  1429.       pdu.set_error_index(0);
  1430.       // determine request id to use
  1431.       req_id = MyMakeReqId();
  1432.       pdu.set_request_id(req_id);
  1433.     }
  1434.     //---------[ map GetBulk over v1 to GetNext ]-------------------------
  1435.     if (( pdu_action == sNMP_PDU_GETBULK)&&( (snmp_version)version== version1))
  1436.       pdu_action = sNMP_PDU_GETNEXT;
  1437.     if ( pdu_action == sNMP_PDU_GETBULK) {
  1438.       pdu.set_error_status((int) non_reps);
  1439.       pdu.set_error_index((int) max_reps);
  1440.     }
  1441.     pdu.set_type( pdu_action);
  1442.     SnmpMessage snmpmsg;
  1443. #ifdef _SNMPv3
  1444.     if (version == version3)
  1445.     {
  1446.       if (!utarget)
  1447.       {
  1448.         debugprintf(0, "-- SNMP++, need UTarget to send SNMPv3 message!");
  1449.         return SNMP_CLASS_INVALID_TARGET;
  1450.       }
  1451.       OctetStr engine_id;
  1452.       utarget->get_engine_id(engine_id);
  1453.       if (engine_id.len() == 0)
  1454.       {
  1455.         if (v3MP::I->get_from_engine_id_table(engine_id,
  1456.     (char*)udp_address.get_printable())
  1457.             == SNMPv3_MP_OK )
  1458.         {
  1459.   // Override const here
  1460.           ((UTarget*)utarget)->set_engine_id(engine_id);
  1461.         } // else: engineID="" --> automatic engineID discovery
  1462.       }
  1463.       // set context_engine_id of pdu, if it is not set
  1464.       if (pdu.get_context_engine_id().len() == 0)
  1465.       {
  1466.         debugprintf(8, "Setting contextEngineID of Pdu to (%s)",
  1467.                     engine_id.get_printable());
  1468.         pdu.set_context_engine_id(engine_id);
  1469.         backupPdu.set_context_engine_id(engine_id);
  1470.       }
  1471.       debugprintf(4,"Snmp::snmp_engine: engineID (%s), securityName (%s)"
  1472.                   "securityModel (%i) security_level (%i)",
  1473.                   engine_id.get_printable(), security_name.get_printable(),
  1474.                   security_model, pdu.get_security_level());
  1475.       debugprintf(4," Addr/Port (%s)",udp_address.get_printable());
  1476.       status = snmpmsg.loadv3( pdu, engine_id, security_name,
  1477.                                security_model, (snmp_version)version);
  1478.     }
  1479.     else
  1480. #endif
  1481.       status = snmpmsg.load( pdu, community_string,(snmp_version) version);
  1482.     if ( status != SNMP_CLASS_SUCCESS)
  1483.     {
  1484.       debugprintf(0, "snmp message load error!");
  1485.       return status;
  1486.     }
  1487.     //------[ send the request ]
  1488.     lock();
  1489.     status = send_snmp_request(iv_session_used,
  1490.        snmpmsg.data(), (size_t) snmpmsg.len(),
  1491.        udp_address);
  1492.     unlock();
  1493.     if ( status != 0)
  1494.       return SNMP_CLASS_TL_FAILED;
  1495.     if ((pdu_action == sNMP_PDU_RESPONSE) ||
  1496.         (pdu_action == sNMP_PDU_REPORT))
  1497.       return SNMP_CLASS_SUCCESS; // don't wait for an answer
  1498. #ifdef _SNMPv3
  1499.     if ((version == version3) && ((action == sNMP_PDU_GET_ASYNC) ||
  1500.                                   (action == sNMP_PDU_SET_ASYNC) ||
  1501.                                   (action == sNMP_PDU_GETNEXT_ASYNC) ||
  1502.                                   (action == sNMP_PDU_GETBULK_ASYNC) ||
  1503.                                   (action == sNMP_PDU_INFORM_ASYNC))) {
  1504.       // add callback for v3
  1505.       struct V3CallBackData *v3CallBackData;
  1506.       v3CallBackData = new struct V3CallBackData;
  1507.       v3CallBackData->pdu = new Pdu(pdu);
  1508.       v3CallBackData->pdu->set_type(backupPdu.get_type());
  1509.       v3CallBackData->non_reps = non_reps;
  1510.       v3CallBackData->max_reps = max_reps;
  1511.       v3CallBackData->target = new UTarget(*utarget);
  1512.       v3CallBackData->oldCallback = cb;
  1513.       v3CallBackData->cbd = cbd;
  1514.       v3CallBackData->reports_received = reports_received;
  1515.       // Add the message to the message queue
  1516.       eventListHolder->snmpEventList()->AddEntry(req_id, this, iv_session_used,
  1517.  target, pdu,
  1518.  snmpmsg.data(),
  1519.  (size_t) snmpmsg.len(),
  1520.  udp_address,
  1521.  v3CallBack,
  1522.  (void *)v3CallBackData);
  1523.     }
  1524.     else
  1525. #endif
  1526.     {
  1527.       eventListHolder->snmpEventList()->AddEntry( req_id, this,
  1528.   iv_session_used,
  1529.   target, pdu,
  1530.   snmpmsg.data(),
  1531.   (size_t) snmpmsg.len(),
  1532.   udp_address,
  1533.   cb, (void *)cbd);
  1534.     }
  1535.     //----[ if an async mode request then return success ]-----
  1536.     if (( action == sNMP_PDU_GET_ASYNC) ||
  1537.         ( action == sNMP_PDU_SET_ASYNC) ||
  1538.         ( action == sNMP_PDU_GETNEXT_ASYNC) ||
  1539.         ( action == sNMP_PDU_GETBULK_ASYNC) ||
  1540.         ( action == sNMP_PDU_INFORM_ASYNC))
  1541.       return SNMP_CLASS_SUCCESS;
  1542.     // Now wait for the response (or timeout) for our message.
  1543.     // This handles any necessary retries.
  1544.     status = eventListHolder->SNMPBlockForResponse(req_id, pdu);
  1545.     if (pdu.get_type() != REPORT_MSG) {
  1546. #ifdef _SNMPv3
  1547.       if (status == SNMPv3_MP_OK)
  1548.         return SNMP_CLASS_SUCCESS;
  1549.       else
  1550. #endif
  1551.         return status;
  1552.     }
  1553. #ifdef _SNMPv3
  1554.     else
  1555.       if (status == SNMPv3_USM_DECRYPTION_ERROR)
  1556.         return status;
  1557.     // We received a REPORT-MSG, check if we should try another time
  1558.     Vb first_vb;
  1559.     Oid first_oid;
  1560.     pdu.get_vb(first_vb,0);
  1561.     first_vb.get_oid(first_oid);
  1562.     debugprintf(1,"received oid: %s with value: %s",
  1563.                 first_vb.get_printable_oid(), first_vb.get_printable_value());
  1564.     debugprintf(1, "%s", error_msg(first_oid));
  1565.     switch (maxloops)
  1566.     {
  1567.       case 0:
  1568.       {
  1569. // This was our first try, so we may receive a unknown engine id 
  1570. // report or a not in time window report
  1571.         if (first_oid == oidUsmStatsUnknownEngineIDs)
  1572.         {
  1573.   pdu = backupPdu; // restore pdu and try again
  1574.   break;
  1575.         }
  1576.         else if (first_oid == oidUsmStatsNotInTimeWindows)
  1577.         {
  1578.           ++maxloops; // increase it, as the next request must succeed
  1579.   pdu = backupPdu; // restore pdu and try again
  1580.   break;
  1581.         }
  1582.         return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
  1583.       }
  1584.       case 1:
  1585.       {
  1586. // This was the second try, engine id discovery should be ok
  1587. // so test only for not in time report
  1588.         if (first_oid == oidUsmStatsNotInTimeWindows)
  1589.         {
  1590.   pdu = backupPdu; // restore pdu and try again
  1591.   break;
  1592.         }
  1593.         return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
  1594.       }
  1595.       case 2:
  1596.       {
  1597. // We tried three times: one for engine id discovery, one for
  1598. // time sync and we still get a report --> somethings wrong!
  1599.         return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
  1600.       }
  1601.     }
  1602.   }
  1603. #endif
  1604.   return status;
  1605. }
  1606. #ifdef _SNMPv3
  1607. int Snmp::engine_id_discovery(OctetStr &engine_id,
  1608.       const int timeout_sec,
  1609.       const UdpAddress &addr)
  1610. {
  1611.   unsigned char *message;
  1612.   int message_length;
  1613.   SnmpSocket sock;
  1614.   SnmpMessage snmpmsg;
  1615.   unsigned char snmpv3_message[60] = {
  1616.     0x30, 0x3a,
  1617.           0x02, 0x01, 0x03,                   // Version: 3
  1618.           0x30, 0x0f,                         // global header length 15
  1619.                 0x02, 0x03, 0x01, 0x00, 0x00, // message id
  1620.                 0x02, 0x02, 0x10, 0x00,       // message max size
  1621.                 0x04, 0x01, 0x04,             // flags (reportable set)
  1622.                 0x02, 0x01, 0x03,             // security model USM
  1623.           0x04, 0x10,                         // security params
  1624.                 0x30, 0x0e,
  1625.                       0x04, 0x00,             // no engine id
  1626.                       0x02, 0x01, 0x00,       // boots 0
  1627.                       0x02, 0x01, 0x00,       // time 0
  1628.                       0x04, 0x00,             // no user name
  1629.                       0x04, 0x00,             // no auth par
  1630.                       0x04, 0x00,             // no priv par
  1631.           0x30, 0x12,
  1632.                 0x04, 0x00,                   // no context engine id
  1633.                 0x04, 0x00,                   // no context name
  1634.           0xa0, 0x0c,                         // GET PDU
  1635.                 0x02, 0x02, 0x34, 0x26,       // request id
  1636.                 0x02, 0x01, 0x00,             // error status no error
  1637.                 0x02, 0x01, 0x00,             // error index 0
  1638.                 0x30, 0x00                    // no data
  1639.   };
  1640.   message = (unsigned char *)snmpv3_message;
  1641.   message_length = 60;
  1642.   engine_id.clear();
  1643.   UdpAddress uaddr(addr);
  1644.   if (uaddr.get_ip_version() == Address::version_ipv4)
  1645.   {
  1646.     if (iv_snmp_session != INVALID_SOCKET)
  1647.       sock = iv_snmp_session;
  1648.     else
  1649.     {
  1650.       uaddr.map_to_ipv6();
  1651.       sock = iv_snmp_session_ipv6;
  1652.     }
  1653.   }
  1654.   else
  1655.     sock = iv_snmp_session_ipv6;
  1656.   lock();
  1657.   if (send_snmp_request(sock, message, message_length, uaddr) < 0)
  1658.   {
  1659.     debugprintf(0, "Error sending message.");
  1660.     unlock();
  1661.     return SNMP_CLASS_TL_FAILED;
  1662.   }
  1663.   // now wait for the responses
  1664.   Pdu dummy_pdu;
  1665.   fd_set readfds;
  1666.   int nfound = 0;
  1667.   struct timeval fd_timeout;
  1668.   msec end_time;
  1669.   end_time += timeout_sec * 1000;
  1670.   do
  1671.   {
  1672.     FD_ZERO(&readfds);
  1673.     FD_SET(sock, &readfds);
  1674.     end_time.GetDeltaFromNow(fd_timeout);
  1675.     nfound = select((int)(sock + 1), &readfds, NULL, NULL, &fd_timeout);
  1676.     if ((nfound > 0) && (FD_ISSET(sock, &readfds)))
  1677.     {
  1678.       // receive message
  1679.       UdpAddress from;
  1680.       int res = receive_snmp_response(sock, *this, dummy_pdu,
  1681.       from, true /* process_msg */);
  1682.       if ((res == SNMP_CLASS_SUCCESS) ||
  1683.   (res == SNMPv3_MP_UNKNOWN_PDU_HANDLERS))
  1684.       {
  1685. dummy_pdu.get_context_engine_id(engine_id);
  1686. debugprintf(3, "Response received from (%s) id %s.",
  1687.     from.get_printable(), engine_id.get_printable());
  1688. return SNMP_CLASS_SUCCESS;
  1689.       }
  1690.       else
  1691.       {
  1692. debugprintf(0, "Error receiving discovery response.");
  1693.       }
  1694.     }
  1695.   } while ((nfound > 0) ||
  1696.    (fd_timeout.tv_sec > 0) || (fd_timeout.tv_usec > 0));
  1697.   unlock();
  1698.   return SNMP_CLASS_TIMEOUT;
  1699. }
  1700. #endif
  1701. // Send a SNMP Broadcast message.
  1702. int Snmp::broadcast_discovery(UdpAddressCollection &addresses,
  1703.       const int timeout_sec,
  1704.       const UdpAddress &addr,
  1705.       const snmp_version version,
  1706.       const OctetStr *community)
  1707. {
  1708.   unsigned char *message;
  1709.   int message_length;
  1710.   SnmpSocket sock;
  1711.   SnmpMessage snmpmsg;
  1712. #ifdef _SNMPv3
  1713.   unsigned char snmpv3_broadcast_message[60] = {
  1714.     0x30, 0x3a,
  1715.           0x02, 0x01, 0x03,                   // Version: 3
  1716.           0x30, 0x0f,                         // global header length 15
  1717.                 0x02, 0x03, 0x01, 0x00, 0x00, // message id
  1718.                 0x02, 0x02, 0x10, 0x00,       // message max size
  1719.                 0x04, 0x01, 0x04,             // flags (reportable set)
  1720.                 0x02, 0x01, 0x03,             // security model USM
  1721.           0x04, 0x10,                         // security params
  1722.                 0x30, 0x0e,
  1723.                       0x04, 0x00,             // no engine id
  1724.                       0x02, 0x01, 0x00,       // boots 0
  1725.                       0x02, 0x01, 0x00,       // time 0
  1726.                       0x04, 0x00,             // no user name
  1727.                       0x04, 0x00,             // no auth par
  1728.                       0x04, 0x00,             // no priv par
  1729.           0x30, 0x12,
  1730.                 0x04, 0x00,                   // no context engine id
  1731.                 0x04, 0x00,                   // no context name
  1732.           0xa0, 0x0c,                         // GET PDU
  1733.                 0x02, 0x02, 0x34, 0x26,       // request id
  1734.                 0x02, 0x01, 0x00,             // error status no error
  1735.                 0x02, 0x01, 0x00,             // error index 0
  1736.                 0x30, 0x00                    // no data
  1737.   };
  1738.   if (version == version3)
  1739.   {
  1740.     message = (unsigned char *)snmpv3_broadcast_message;
  1741.     message_length = 60;
  1742.   }
  1743.   else
  1744. #endif
  1745.   {
  1746.     Pdu pdu;
  1747.     Vb vb;
  1748.     OctetStr get_community;
  1749.     vb.set_oid("1.3.6.1.2.1.1.1.0");
  1750.     pdu +=vb;
  1751.     pdu.set_error_index(0);            // set error index to none
  1752.     pdu.set_request_id(MyMakeReqId()); // determine request id to use
  1753.     pdu.set_type(sNMP_PDU_GET);        // set pdu type
  1754.     if (community)
  1755.       get_community = *community;
  1756.     else
  1757.       get_community = "public";
  1758.     int status = snmpmsg.load(pdu, get_community, version);
  1759.     if (status != SNMP_CLASS_SUCCESS)
  1760.     {
  1761.       debugprintf(0, "Error encoding broadcast pdu (%i).", status);
  1762.       return status;
  1763.     }
  1764.     message        = snmpmsg.data();
  1765.     message_length = snmpmsg.len();
  1766.   }
  1767.   UdpAddress uaddr(addr);
  1768.   if (uaddr.get_ip_version() == Address::version_ipv4)
  1769.   {
  1770.     if (iv_snmp_session != INVALID_SOCKET)
  1771.       sock = iv_snmp_session;
  1772.     else
  1773.     {
  1774.       uaddr.map_to_ipv6();
  1775.       sock = iv_snmp_session_ipv6;
  1776.     }
  1777.   }
  1778.   else
  1779.     sock = iv_snmp_session_ipv6;
  1780.   lock();
  1781.   if (send_snmp_request(sock, message, message_length, uaddr) < 0)
  1782.   {
  1783.     debugprintf(0, "Error sending broadast.");
  1784.     unlock();
  1785.     return SNMP_CLASS_TL_FAILED;
  1786.   }
  1787.   // now wait for the responses
  1788.   Pdu dummy_pdu;
  1789.   fd_set readfds;
  1790.   int nfound = 0;
  1791.   struct timeval fd_timeout;
  1792.   msec end_time;
  1793.   end_time += timeout_sec * 1000;
  1794.   do
  1795.   {
  1796.     FD_ZERO(&readfds);
  1797.     FD_SET(sock, &readfds);
  1798.     end_time.GetDeltaFromNow(fd_timeout);
  1799.     nfound = select((int)(sock + 1), &readfds, NULL, NULL, &fd_timeout);
  1800.     if ((nfound > 0) && (FD_ISSET(sock, &readfds)))
  1801.     {
  1802.       // receive message
  1803.       UdpAddress from;
  1804.       if (receive_snmp_response(sock, *this, dummy_pdu,
  1805. from, false /* process_msg */)
  1806.   == SNMP_CLASS_SUCCESS)
  1807.       {
  1808. addresses += from;
  1809.       }
  1810.       else
  1811.       {
  1812. debugprintf(0, "Error receiving broadcast response.");
  1813.       }
  1814.     }
  1815.   } while ((nfound > 0) ||
  1816.    (fd_timeout.tv_sec > 0) || (fd_timeout.tv_usec > 0));
  1817.   unlock();
  1818. #ifdef __DEBUG
  1819.   for (int i=0; i < addresses.size(); ++i)
  1820.   {
  1821.     debugprintf(3, "Broadcast response received from (%s).",
  1822. addresses[i].get_printable());
  1823.   }
  1824. #endif
  1825.   return 0;
  1826. }
  1827. //     Starts the working thread for the recovery of the pending events
  1828. bool Snmp::start_poll_thread(const int select_timeout)
  1829. {
  1830. #ifdef _THREADS
  1831.     // store the timeout value for later
  1832.     m_iPollTimeOut = select_timeout;
  1833.     // if we are already running return ok
  1834.     if (m_bThreadRunning == true) return true;
  1835.     // since we are here, things must be fine so far...
  1836.     m_bThreadRunning = true;
  1837.     // start the ProcessThread function....
  1838. #ifdef WIN32
  1839.     DWORD id;
  1840.     m_hThread = CreateThread(NULL, 0,
  1841.        (LPTHREAD_START_ROUTINE)&Snmp::process_thread,
  1842.        this, 0, &id);
  1843.     if (m_hThread == NULL)
  1844.     {
  1845.         debugprintf(0, "Could not create ProcessThread");
  1846. m_bThreadRunning = false;
  1847.     }
  1848. #elif defined (CPU) && CPU == PPC603
  1849. m_hThread = taskSpawn("Snmp::process_thread",  0, 0, 10000, (int (*)(...))Snmp::process_thread,  (int)this, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  1850.     if (m_hThread == ERROR)
  1851.     {
  1852. // Could not create thread.
  1853.         debugprintf(0, "Could not create ProcessThread");
  1854. m_bThreadRunning = false;
  1855.     }
  1856. #else
  1857.     int rc = pthread_create(&m_hThread, NULL, Snmp::process_thread,
  1858.     (void*) this);
  1859.     if (rc)
  1860.     {
  1861. // Could not create thread.
  1862.         debugprintf(0, "Could not create ProcessThread");
  1863. m_bThreadRunning = false;
  1864.     }
  1865. #endif
  1866. #endif
  1867.     return m_bThreadRunning;
  1868. }
  1869. ///////////////////////////////////////////////////////////////////////////////
  1870. // stop_poll_thread
  1871. //     Stops the recovery of the pending events
  1872. //
  1873. ///////////////////////////////////////////////////////////////////////////////
  1874. void Snmp::stop_poll_thread()
  1875. {
  1876.     if (m_bThreadRunning == false) return;
  1877. #ifdef _THREADS
  1878.     // stop the thread
  1879.     m_bThreadRunning = false;
  1880.     // Wait for the working thread to stop....
  1881. #ifdef WIN32
  1882.     ::WaitForSingleObject(m_hThread, INFINITE);
  1883. #elif defined (CPU) && CPU == PPC603
  1884. while (taskIdVerify(m_hThread) == OK)
  1885. taskDelay(10);
  1886. #else
  1887.     int status;
  1888.     pthread_join(m_hThread, (void**) &status); 
  1889. #endif
  1890. #endif
  1891. }
  1892. #ifdef WIN32
  1893. int Snmp::process_thread(Snmp *pSnmp)
  1894. {
  1895. #else
  1896. void* Snmp::process_thread(void *arg)
  1897. {
  1898.     Snmp* pSnmp = (Snmp*) arg;
  1899. #endif // !WIN32
  1900.     // Loop as long as we haven't stopped
  1901.     while (pSnmp->is_running())
  1902.     {
  1903. pSnmp->eventListHolder
  1904.      ->SNMPProcessEvents(pSnmp->m_iPollTimeOut);
  1905.     }
  1906. #ifdef _THREADS
  1907. #ifndef WIN32
  1908. #if defined (CPU) && CPU == PPC603
  1909. exit(0);
  1910. #else
  1911.     pthread_exit(0);
  1912. #endif
  1913. #endif
  1914. #endif
  1915.     return 0;
  1916. }
  1917. #ifdef SNMP_PP_NAMESPACE
  1918. }; // end of namespace Snmp_pp
  1919. #endif