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

SNMP编程

开发平台:

Visual C++

  1. /*_############################################################################
  2.   _## 
  3.   _##  notifyqueue.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.   Copyright (c) 1999
  31.   Hewlett-Packard Company
  32.   ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
  33.   Permission to use, copy, modify, distribute and/or sell this software
  34.   and/or its documentation is hereby granted without fee. User agrees
  35.   to display the above copyright notice and this license notice in all
  36.   copies of the software and any documentation of the software. User
  37.   agrees to assume all liability for the use of the software; Hewlett-Packard
  38.   makes no representations about the suitability of this software for any
  39.   purpose. It is provided "AS-IS" without warranty of any kind,either express
  40.   or implied. User hereby grants a royalty-free license to any and all
  41.   derivatives based upon this software code base.
  42.       N O T I F Y Q U E U E . C P P
  43.       CNotifyEventQueue CLASS DEFINITION
  44.       COPYRIGHT HEWLETT PACKARD COMPANY 1999
  45.       INFORMATION NETWORKS DIVISION
  46.       NETWORK MANAGEMENT SECTION
  47.       DESIGN + AUTHOR:        Tom Murray
  48.       LANGUAGE:               ANSI C++
  49.       DESCRIPTION:
  50.         Queue for holding callback associated with user defined
  51.         timeouts
  52. =====================================================================*/
  53. char notifyqueue_version[]="#(@) SNMP++ $Id: notifyqueue.cpp 284 2007-03-22 22:09:46Z katz $";
  54. //-----[ includes ]----------------------------------------------------
  55. #ifdef WIN32
  56. #include <winsock.h>
  57. #endif
  58. #include <errno.h>
  59. //----[ snmp++ includes ]----------------------------------------------
  60. #include "snmp_pp/config_snmp_pp.h"
  61. #include "snmp_pp/v3.h"
  62. #include "snmp_pp/notifyqueue.h" // queue for holding sessions waiting for async notifications
  63. #include "snmp_pp/eventlistholder.h"
  64. #include "snmp_pp/uxsnmp.h"
  65. #include "snmp_pp/snmperrs.h"
  66. #include "snmp_pp/pdu.h"
  67. #if defined (CPU) && CPU == PPC603
  68. #include <sockLib.h> 
  69. #endif
  70. #ifdef SNMP_PP_NAMESPACE
  71. namespace Snmp_pp {
  72. #endif
  73. //--------[ externs ]---------------------------------------------------
  74. extern int receive_snmp_notification(SnmpSocket sock, Snmp &snmp_session,
  75.                                      Pdu &pdu, SnmpTarget **target);
  76. //-----[ macros ]------------------------------------------------------
  77. // should be in snmp.h...
  78. #define SNMP_PORT 161       // standard port # for SNMP
  79. #define SNMP_TRAP_PORT 162    // standard port # for SNMP traps
  80. #ifdef WIN32
  81. #define close closesocket
  82. #elif defined(_AIX)
  83. #include <unistd.h>
  84. #endif
  85. //----[ CNotifyEvent class ]------------------------------------------------
  86. CNotifyEvent::CNotifyEvent(Snmp *snmp,
  87.    const OidCollection &trapids,
  88.    const TargetCollection &targets,
  89.    const AddressCollection &addresses)
  90.   : m_snmp(snmp)
  91. {
  92.   // create new collections using parms passed in
  93.   notify_ids       = new OidCollection(trapids);
  94.   notify_targets   = new TargetCollection(targets);
  95.   notify_addresses = new AddressCollection(addresses);
  96. }
  97. CNotifyEvent::~CNotifyEvent()
  98. {
  99.   // free up local collections
  100.   if (notify_ids)       { delete notify_ids;       notify_ids       = 0; }
  101.   if (notify_targets)   { delete notify_targets;   notify_targets   = 0; }
  102.   if (notify_addresses) { delete notify_addresses; notify_addresses = 0; }
  103. }
  104. int CNotifyEvent::notify_filter(const Oid &trapid, SnmpTarget &target) const
  105. {
  106.   int target_count, has_target = FALSE, target_matches = FALSE;
  107.   int trapid_count, has_trapid = FALSE, trapid_matches = FALSE;
  108.   GenAddress targetaddr, tmpaddr;
  109.   // figure out how many targets, handle empty case as all targets
  110.   if ((notify_targets) && (target_count = notify_targets->size()))
  111.   {
  112.     SnmpTarget *tmptarget = 0;
  113.     has_target = TRUE;
  114.     target.get_address(targetaddr);
  115.     if (targetaddr.valid()) {
  116.       // loop through all targets in the collection
  117.       SnmpTarget::target_type target_type = target.get_type();
  118.       SnmpTarget::target_type tmptarget_type;
  119.       for ( int x = 0; x < target_count; x++)       // for all targets
  120.       {
  121. if (notify_targets->get_element(tmptarget, x))
  122.   continue;
  123. tmptarget->get_address(tmpaddr);
  124. if ((tmpaddr.valid())) {
  125.           int addr_equal = 0;
  126.           /* check for types of Address */
  127.           if ((tmpaddr.get_type() == Address::type_ip) &&
  128.               (targetaddr.get_type() == Address::type_udp))
  129.           {
  130.             /* special case that works for UdpAddress == IpAddress */
  131.             IpAddress ip1(targetaddr);
  132.             IpAddress ip2(tmpaddr);
  133.             addr_equal = (ip1.valid() && ip2.valid() && (ip1 == ip2));
  134.           }
  135.           else
  136.           {
  137.             addr_equal = (targetaddr == tmpaddr);
  138.           }
  139.           if (addr_equal) {
  140.             tmptarget_type = tmptarget->get_type();
  141.             if (target_type == SnmpTarget::type_utarget) {
  142.               // target is a UTarget
  143.               if (tmptarget_type == SnmpTarget::type_utarget) {
  144.                 // both are UTarget
  145.                 if ((((UTarget*)(&target))->get_security_name() ==
  146.                      ((UTarget*)tmptarget)->get_security_name()) &&
  147.                     (((UTarget*)(&target))->get_security_model() ==
  148.                      ((UTarget*)tmptarget)->get_security_model())) {
  149.   target_matches = TRUE;
  150.                   break;
  151.                 }
  152.               }
  153.               else
  154.                 if (tmptarget_type == SnmpTarget::type_ctarget)
  155.                   // in case utarget is used with v1 or v2:
  156.                   if ((tmptarget->get_version() == target.get_version()) &&
  157.                       (((UTarget*)(&target))->get_security_name() ==
  158.                        OctetStr(((CTarget*)tmptarget)->
  159.                                 get_readcommunity()))) {
  160.                     target_matches = TRUE;
  161.                     break;
  162.                   }
  163.             }
  164.             else {
  165.               if (target_type == SnmpTarget::type_ctarget) {
  166.                 // target is a CTarget
  167.                 if (tmptarget_type == SnmpTarget::type_ctarget) {
  168.                   // both are CTarget
  169.                   if (!strcmp(((CTarget*)(&target))->get_readcommunity(),
  170.                               ((CTarget*)tmptarget)->get_readcommunity())) {
  171.                     target_matches = TRUE;
  172.                     break;
  173.                   }
  174.                 }
  175.                 else
  176.                   if (tmptarget_type == SnmpTarget::type_utarget) {
  177.                     if ((tmptarget->get_version() == target.get_version()) &&
  178.                         (OctetStr(((CTarget*)(&target))->get_readcommunity()) ==
  179.                          ((UTarget*)tmptarget)->get_security_name())) {
  180.                       target_matches = TRUE;
  181.                       break;
  182.                     }
  183.                   }
  184.               }
  185.             }
  186.           } // end if (add_equal)
  187.         } // end if tmpaddr.valid()...
  188.       }
  189.     }
  190.   }
  191.   // else no targets means all targets
  192.   // figure out how many trapids, handle empty case as all trapids
  193.   if ((notify_ids) && (trapid_count = notify_ids->size())) {
  194.     Oid tmpoid;
  195.     has_trapid = TRUE;
  196.     // loop through all trapids in the collection
  197.     for (int y=0; y < trapid_count; y++)       // for all trapids
  198.     {
  199.       if (notify_ids->get_element(tmpoid, y))
  200. continue;
  201.       if (trapid == tmpoid) {
  202. trapid_matches = TRUE;
  203. break;
  204.       }
  205.     }
  206.   }
  207.   // else no trapids means all traps
  208.   // Make the callback if the trap passed the filters
  209.   if ((has_target && !target_matches) || (has_trapid && !trapid_matches))
  210.     return FALSE;
  211.   return TRUE;
  212. }
  213. int CNotifyEvent::Callback(SnmpTarget &target, Pdu &pdu, SnmpSocket fd, int status)
  214. {
  215.   Oid trapid;
  216.   pdu.get_notify_id(trapid);
  217.   // Make the callback if the trap passed the filters
  218.   if ((m_snmp) && (notify_filter(trapid, target)))
  219.   {
  220.     int reason;
  221.     if (SNMP_CLASS_TL_FAILED == status)
  222.       reason = SNMP_CLASS_TL_FAILED;
  223.     else
  224.       reason = SNMP_CLASS_NOTIFICATION;
  225.     //------[ call into the callback function ]-------------------------
  226.     if (m_snmp->get_notify_callback())
  227.       (m_snmp->get_notify_callback())(
  228.   reason,
  229.   m_snmp, // snmp++ session who owns the req
  230.   pdu, // trap pdu
  231.   target, // target
  232.   m_snmp->get_notify_callback_data()); // callback data
  233.   }
  234.   return SNMP_CLASS_SUCCESS;
  235. }
  236. //----[ CNotifyEventQueueElt class ]--------------------------------------
  237. CNotifyEventQueue::CNotifyEventQueueElt::CNotifyEventQueueElt(
  238.                                            CNotifyEvent *notifyevent,
  239.    CNotifyEventQueueElt *next,
  240.    CNotifyEventQueueElt *previous)
  241.   : m_notifyevent(notifyevent), m_Next(next), m_previous(previous)
  242. {
  243.   /* Finish insertion into doubly linked list */
  244.   if (m_Next)     m_Next->m_previous = this;
  245.   if (m_previous) m_previous->m_Next = this;
  246. }
  247. CNotifyEventQueue::CNotifyEventQueueElt::~CNotifyEventQueueElt()
  248. {
  249.   /* Do deletion form doubly linked list */
  250.   if (m_Next)        m_Next->m_previous = m_previous;
  251.   if (m_previous)    m_previous->m_Next = m_Next;
  252.   if (m_notifyevent) delete m_notifyevent;
  253. }
  254. CNotifyEvent *CNotifyEventQueue::CNotifyEventQueueElt::TestId(Snmp *snmp)
  255. {
  256.   if (m_notifyevent && (m_notifyevent->GetId() == snmp))
  257.     return m_notifyevent;
  258.   return 0;
  259. }
  260. //----[ CNotifyEventQueue class ]--------------------------------------
  261. CNotifyEventQueue::CNotifyEventQueue(EventListHolder *holder, Snmp *session)
  262.   : m_head(NULL,NULL,NULL), m_msgCount(0), m_notify_fds(0),
  263.     m_notify_fd_count(0), m_listen_port(SNMP_TRAP_PORT),
  264.     my_holder(holder), m_snmpSession(session)
  265. {
  266. //TM: could do the trap registration setup here but seems better to
  267. //wait until the app actually requests trap receives by calling
  268. //notify_register().
  269. }
  270. CNotifyEventQueue::~CNotifyEventQueue()
  271. {
  272.   CNotifyEventQueueElt *leftOver;
  273.   /* walk the list deleting any elements still on the queue */
  274.   lock();
  275.   while ((leftOver = m_head.GetNext()))
  276.     delete leftOver;
  277.   unlock();
  278. }
  279. SnmpSocket CNotifyEventQueue::get_notify_fd(const UdpAddress match_addr) const
  280. {
  281.   SnmpSocket found_fd = INVALID_SOCKET;
  282.   int max_bits_matched = 0;
  283.   IpAddress ip_match = IpAddress(match_addr);
  284.   for (int i = 0; i < m_notify_fd_count; i++)
  285.   {
  286.     IpAddress ip = m_notify_addrs[i];
  287.     int bits = ip_match.get_match_bits(ip);
  288.     debugprintf(5, "Compared %s to %s, bits %d", 
  289. ip.get_printable(), ip_match.get_printable(), bits);
  290.     if (bits > max_bits_matched)
  291.     {
  292. max_bits_matched = bits;
  293. found_fd = m_notify_fds[i];
  294.     }
  295.   }
  296.   return found_fd;
  297. }
  298. SnmpSocket CNotifyEventQueue::get_notify_fd(const int i) const
  299. {
  300.   if ((i < 0) || ( i >= m_notify_fd_count))
  301.       return INVALID_SOCKET;
  302.   return m_notify_fds[i];
  303. }
  304. int CNotifyEventQueue::AddEntry(Snmp *snmp,
  305. const OidCollection &trapids,
  306. const TargetCollection &targets,
  307. const AddressCollection &addresses)
  308. {
  309.   if (snmp != m_snmpSession)
  310.   {
  311.     debugprintf(0, "WARNING: Adding notification event for other Snmp object");
  312.   }
  313.   lock();
  314.   if (!m_msgCount)
  315.   {
  316. //    m_notify_addrs = addresses;
  317.     if (m_notify_addrs.size() == 0)
  318.     {
  319.       UdpAddress tmp_addr = snmp->get_listen_address();
  320.       tmp_addr.set_port(m_listen_port);
  321.       m_notify_addrs += tmp_addr;
  322.     }
  323.     // allocate fd array
  324.     m_notify_fds = new SnmpSocket[m_notify_addrs.size()];
  325.     if (!m_notify_fds)
  326. return SNMP_CLASS_RESOURCE_UNAVAIL;
  327.     m_notify_fd_count = m_notify_addrs.size();
  328.     for (int i = 0; i < m_notify_fd_count ; i++)
  329.     {
  330.       // This is the first request to receive notifications
  331.       // Set up the socket for the snmp trap port (162) or the
  332.       // specified port through set_listen_port()
  333.       struct sockaddr_in mgr_addr;
  334.       // open a socket to be used for the session
  335.       if ((m_notify_fds[i] = socket( AF_INET, SOCK_DGRAM,0)) < 0)
  336.       {
  337.   int status;
  338. #ifdef WIN32
  339.   int werr = WSAGetLastError();
  340.   if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
  341.       status = SNMP_CLASS_RESOURCE_UNAVAIL;
  342.   else if (WSAEHOSTDOWN == werr)
  343.       status = SNMP_CLASS_TL_FAILED;
  344.   else
  345.       status = SNMP_CLASS_TL_UNSUPPORTED;
  346. #else
  347.   if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
  348.       status = SNMP_CLASS_RESOURCE_UNAVAIL;
  349.   else if (EHOSTDOWN == errno)
  350.       status = SNMP_CLASS_TL_FAILED;
  351.   else
  352.       status = SNMP_CLASS_TL_UNSUPPORTED;
  353. #endif
  354.   // Free all fds...
  355.   for (int j=0; j<i; j++)
  356.       close(m_notify_fds[j]);
  357.   delete [] m_notify_fds;
  358.   m_notify_fds = 0;
  359.   m_notify_fd_count = 0;
  360.   unlock();
  361.   return status;
  362.       }
  363.       // set up the manager socket attributes
  364.       unsigned long inaddr = inet_addr(IpAddress(m_notify_addrs[i]).get_printable());
  365.       memset(&mgr_addr, 0, sizeof(mgr_addr));
  366.       mgr_addr.sin_family = AF_INET;
  367.       mgr_addr.sin_addr.s_addr = inaddr; // was htonl( INADDR_ANY);
  368.       UdpAddress tmp_udp_addr(m_notify_addrs[i]);
  369.       mgr_addr.sin_port = htons(tmp_udp_addr.get_port());
  370. #ifdef CYGPKG_NET_OPENBSD_STACK
  371.       mgr_addr.sin_len = sizeof(mgr_addr);
  372. #endif
  373.       // bind the socket
  374.       if (bind(m_notify_fds[i], (struct sockaddr *) &mgr_addr,
  375.        sizeof(mgr_addr)) < 0)
  376.       {
  377. int status;
  378. #ifdef WIN32
  379. int werr = WSAGetLastError();
  380. if (WSAEADDRINUSE  == werr)
  381.     status = SNMP_CLASS_TL_IN_USE;
  382. else if (WSAENOBUFS == werr)
  383.     status = SNMP_CLASS_RESOURCE_UNAVAIL;
  384. else if (werr == WSAEAFNOSUPPORT)
  385.     status = SNMP_CLASS_TL_UNSUPPORTED;
  386. else if (werr == WSAENETUNREACH)
  387.     status = SNMP_CLASS_TL_FAILED;
  388. else if (werr == EACCES)
  389.     status = SNMP_CLASS_TL_ACCESS_DENIED;
  390. else
  391.     status = SNMP_CLASS_INTERNAL_ERROR;
  392. #else
  393. if (EADDRINUSE  == errno)
  394.     status = SNMP_CLASS_TL_IN_USE;
  395. else if (ENOBUFS == errno)
  396.     status = SNMP_CLASS_RESOURCE_UNAVAIL;
  397. else if (errno == EAFNOSUPPORT)
  398.     status = SNMP_CLASS_TL_UNSUPPORTED;
  399. else if (errno == ENETUNREACH)
  400.     status = SNMP_CLASS_TL_FAILED;
  401. else if (errno == EACCES)
  402.     status = SNMP_CLASS_TL_ACCESS_DENIED;
  403. else
  404. {
  405.   debugprintf(0, "Uncatched errno value %d, returning internal error.",
  406.       errno);
  407.   status = SNMP_CLASS_INTERNAL_ERROR;
  408. }
  409. #endif
  410.         debugprintf(0, "Fatal: could not bind to %s",
  411.     m_notify_addrs[i].get_printable());
  412. // Free all fds...
  413. for (int j=0; j <= i; j++)
  414.     close(m_notify_fds[j]);
  415. delete [] m_notify_fds;
  416. m_notify_fds = 0;
  417. m_notify_fd_count = 0;
  418.         unlock();
  419. return status;
  420.       }
  421.       debugprintf(3, "Bind to %s for notifications, fd %d.",
  422.   m_notify_addrs[i].get_printable(), m_notify_fds[i]);
  423.     }
  424.   }
  425.   CNotifyEvent *newEvent = new CNotifyEvent(snmp, trapids, targets,
  426.     m_notify_addrs);
  427.   /*---------------------------------------------------------*/
  428.   /* Insert entry at head of list, done automagically by the */
  429.   /* constructor function, so don't use the return value.    */
  430.   /*---------------------------------------------------------*/
  431.   (void) new CNotifyEventQueueElt(newEvent, m_head.GetNext(), &m_head);
  432.   m_msgCount++;
  433.   unlock();
  434.   return SNMP_CLASS_SUCCESS;
  435. }
  436. CNotifyEvent *CNotifyEventQueue::GetEntry(Snmp * snmp) REENTRANT ({
  437.   CNotifyEventQueueElt *msgEltPtr = m_head.GetNext();
  438.   CNotifyEvent *returnVal = NULL;
  439.   while (msgEltPtr){
  440.     if ((returnVal = msgEltPtr->TestId(snmp)))
  441.       return returnVal;
  442.     msgEltPtr = msgEltPtr->GetNext();
  443.   }
  444.   return 0;
  445. })
  446. void CNotifyEventQueue::DeleteEntry(Snmp *snmp)
  447. {
  448.   lock();
  449.   CNotifyEventQueueElt *msgEltPtr = m_head.GetNext();
  450.   while (msgEltPtr){
  451.     if (msgEltPtr->TestId(snmp)){
  452.       delete msgEltPtr;
  453.       m_msgCount--;
  454.       break;
  455.     }
  456.     msgEltPtr = msgEltPtr->GetNext();
  457.   }
  458.   if (m_msgCount <= 0)
  459.   {
  460.     for(int i=0; i < m_notify_fd_count; i++)
  461.     {
  462.       // shut down the trap socket (if valid) if not using it.
  463.       if (m_notify_fds[i] != (int)INVALID_SOCKET)
  464.       {
  465. debugprintf(3, "Closing notifications port %s, fd %d.",
  466.     m_notify_addrs[i].get_printable(), m_notify_fds[i]);
  467. close(m_notify_fds[i]);
  468. m_notify_fds[i] = INVALID_SOCKET;
  469.       }
  470.     }
  471.     if (m_notify_fds) delete [] m_notify_fds;
  472.     m_notify_fds = 0;
  473.     m_notify_fd_count = 0;
  474.   }
  475.   unlock();
  476. }
  477. void CNotifyEventQueue::GetFdSets(int &maxfds,
  478.   fd_set &readfds,
  479.   fd_set &/*writefds*/,
  480.   fd_set &/*exceptfds*/) REENTRANT ({
  481.   if (m_notify_fd_count > 0) {
  482.     for (int i = 0; i < m_notify_fd_count; i++)
  483.     {
  484.       FD_SET(m_notify_fds[i], &readfds);
  485.       if (maxfds < m_notify_fds[i] + 1)
  486. maxfds = SAFE_INT_CAST(m_notify_fds[i] + 1);
  487.     }
  488.   }
  489.   return;
  490. })
  491. int CNotifyEventQueue::HandleEvents(const int /*maxfds*/,
  492.     const fd_set &readfds,
  493.     const fd_set &/*writefds*/,
  494.     const fd_set &/*exceptfds*/) REENTRANT ({
  495.   int status = SNMP_CLASS_SUCCESS;
  496.   if (m_notify_fd_count == 0)
  497.     return status;
  498.   for (int i=0; i < m_notify_fd_count; i++)
  499.   {
  500.     Pdu pdu;
  501.     SnmpTarget *target = NULL;
  502.     CNotifyEventQueueElt *notifyEltPtr = m_head.GetNext();
  503.     // pull the notifiaction off the socket
  504.     if (FD_ISSET(m_notify_fds[i], &readfds)) {
  505.       status = receive_snmp_notification(m_notify_fds[i], *m_snmpSession,
  506.  pdu, &target);
  507.       if (SNMP_CLASS_SUCCESS == status ||
  508.   SNMP_CLASS_TL_FAILED == status) {
  509. // If we have transport layer failure, the app will want to
  510. // know about it.
  511. // Go through each snmp object and check the filters, making
  512. // callbacks as necessary
  513.         // LiorK: on failure target will be NULL
  514. if (!target)
  515.   target = new SnmpTarget();
  516. while (notifyEltPtr){
  517.   notifyEltPtr->GetNotifyEvent()->Callback(*target, pdu,
  518.    m_notify_fds[i], status);
  519.   notifyEltPtr = notifyEltPtr->GetNext();
  520. } // for each snmp object
  521.       }
  522.       if (target) // receive_snmp_notification calls new
  523. delete target;
  524.     }
  525.   }
  526.   return status;
  527. })
  528. #ifdef SNMP_PP_NAMESPACE
  529. }; // end of namespace Snmp_pp
  530. #endif