uxsnmp.cpp
上传用户:ets1996
上传日期:2014-09-30
资源大小:353k
文件大小:66k
源码类别:

SNMP编程

开发平台:

Visual C++

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