1 /*_############################################################################
6 _## -----------------------------------------------
7 _## Copyright (c) 2001-2010 Jochen Katz, Frank Fock
9 _## This software is based on SNMP++2.6 from Hewlett Packard:
11 _## Copyright (c) 1996
12 _## Hewlett-Packard Company
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.
26 _## Stuttgart, Germany, Thu Sep 2 00:07:47 CEST 2010
28 _##########################################################################*/
29 /*===================================================================
32 UXSNMP CLASS DECLARATION
34 Description: Snmp class
36 Author: Peter E Mellquist
37 =====================================================================*/
38 char snmp_cpp_version[]="#(@) SNMP++ $Id: uxsnmp.cpp 1798 2010-08-14 20:10:48Z katz $";
40 /* CK Ng added support for WIN32 in the whole file */
42 //-----[ includes ]----------------------------------------------------
44 #include <sys/types.h> // system types
45 #include <sys/timeb.h> // _timeb and _ftime
47 #include <unistd.h> // unix
48 #include <sys/socket.h> // bsd socket stuff
49 #include <netinet/in.h> // network types
50 #include <arpa/inet.h> // arpa types
51 #include <sys/types.h> // system types
52 #if !(defined CPU && CPU == PPC603)
53 #include <sys/time.h> // time stuff
57 #define ss_family __ss_family
60 #include <stdlib.h> // need for malloc
61 #include <errno.h> // ux errs
63 #define _INCLUDE_SNMP_ERR_STRINGS
65 //----[ snmp++ includes ]----------------------------------------------
66 #include "snmp_pp/config_snmp_pp.h"
67 #include "snmp_pp/uxsnmp.h" // class def for this module
68 #include "snmp_pp/oid_def.h" // class def for well known trap oids
69 #include "snmp_pp/v3.h"
70 #include "snmp_pp/msgqueue.h" // message queue
71 #include "snmp_pp/notifyqueue.h" // notification queue
72 #include "snmp_pp/snmpmsg.h" // asn serialization class
73 #include "snmp_pp/eventlistholder.h"
74 #include "snmp_pp/usm_v3.h"
75 #include "snmp_pp/vb.h"
76 #include "snmp_pp/log.h"
77 #include "snmp_pp/IPv6Utility.h"
79 #if defined (CPU) && CPU == PPC603
84 #ifdef SNMP_PP_NAMESPACE
88 //-----[ special includes ]-------------------------------------------
91 //------------[ if using Wind-U, then bring in the ms-windows header ]
98 //-----[ macros ]------------------------------------------------------
99 #define DEFAULT_TIMEOUT 1000 // one second default timeout
100 #define DEFAULT_RETRIES 1 // no retry default
101 #define SNMP_PORT 161 // port # for SNMP
102 #define SNMP_TRAP_PORT 162 // port # for SNMP traps
105 #ifdef __BCPLUSPLUS__
109 #define close closesocket
112 //--------[ globals ]---------------------------------------------------
114 //--------------[ well known trap ids ]-----------------------------------
115 const coldStartOid coldStart;
116 const warmStartOid warmStart;
117 const linkDownOid linkDown;
118 const linkUpOid linkUp;
119 const authenticationFailureOid authenticationFailure;
120 const egpNeighborLossOid egpNeighborLoss;
121 const snmpTrapEnterpriseOid snmpTrapEnterprise;
126 void deleteV3Callback(struct Snmp::V3CallBackData *&cbData)
132 if (cbData->target) {
133 delete cbData->target;
140 void v3CallBack(int reason, Snmp *snmp, Pdu &pdu, SnmpTarget &target, void *v3cd)
142 struct Snmp::V3CallBackData *cbData = (struct Snmp::V3CallBackData*)v3cd;
147 debugprintf(5, "v3CallBack: received oid: %s with value: %s",
148 tmpvb.get_printable_oid(), tmpvb.get_printable_value());
149 debugprintf(5, "v3CallBack: error_msg (%s), pdu_type (%i)",
150 snmp->error_msg(tmpvb.get_oid()), pdu.get_type());
152 if ((pdu.get_type() == REPORT_MSG) &&
153 (((tmpvb.get_oid() == oidUsmStatsUnknownEngineIDs) &&
154 (cbData->reports_received == 0)) ||
155 ((tmpvb.get_oid() == oidUsmStatsNotInTimeWindows) &&
156 (cbData->reports_received <= 1)))) {
157 // hide those reports from user
159 if ((cbData->pdu) && (cbData->target)) {
160 rc = snmp->snmp_engine(*(cbData->pdu), cbData->non_reps,
161 cbData->max_reps, *(cbData->target),
162 (snmp_callback)(cbData->oldCallback),
163 (void *)cbData->cbd, INVALID_SOCKET,
164 cbData->reports_received + 1);
165 debugprintf(3,"v3CallBack: snmp_engine called, rc (%i)", rc);
168 rc = SNMP_CLASS_ERROR;
170 if (rc != SNMP_CLASS_SUCCESS) {
171 // call callback if snmp_engine failed or pdu or target was 0
172 debugprintf(3,"v3CallBack: calling user callback");
173 snmp_callback tmp_callBack;
174 tmp_callBack = (snmp_callback)(cbData->oldCallback);
175 tmp_callBack(rc, snmp, pdu, target, (void *)cbData->cbd);
179 debugprintf(3,"v3CallBack: calling user callback");
180 snmp_callback tmp_callBack;
181 tmp_callBack = (snmp_callback)(cbData->oldCallback);
182 tmp_callBack(reason, snmp, pdu, target, (void *)cbData->cbd);
184 // save to delete it here, because either snmp_engine created a new
185 // callback entry or the user specified callback has been called
186 deleteV3Callback(cbData);
191 //--------[ make the pdu request id ]-----------------------------------
192 // return a unique rid, clock can be too slow , so use current_rid
193 long Snmp::MyMakeReqId()
196 eventListHolder->snmpEventList()->lock();
201 debugprintf(-10, "\nWARNING: Using constand RequestID!\n");
205 if ( current_rid > PDU_MAX_RID)
207 current_rid = rid = PDU_MIN_RID;
208 // let other tasks proceed
209 eventListHolder->snmpEventList()->unlock();
213 select(0, 0, 0, 0, &tv);
214 eventListHolder->snmpEventList()->lock();
216 } while (eventListHolder->snmpEventList()->GetEntry(rid));
217 eventListHolder->snmpEventList()->unlock();
222 //---------[ Send SNMP Request ]---------------------------------------
223 // Send out a snmp request
224 DLLOPT int send_snmp_request(SnmpSocket sock, unsigned char *send_buf,
225 size_t send_len, Address & address)
227 // UX only supports UDP type addresses (addr and port) right now
228 if (address.get_type() != Address::type_udp)
229 return -1;// unsupported address type
231 debugprintf(1, "++ SNMP++: sending to %s:",
232 ((UdpAddress &)address).UdpAddress::get_printable());
233 debughexprintf(5, send_buf, SAFE_UINT_CAST(send_len));
237 if (((UdpAddress &)address).get_ip_version() == Address::version_ipv4)
239 // prepare the destination address
240 struct sockaddr_in agent_addr; // send socket struct
241 memset(&agent_addr, 0, sizeof(agent_addr));
242 agent_addr.sin_family = AF_INET;
243 agent_addr.sin_addr.s_addr
244 = inet_addr(((IpAddress &)address).IpAddress::get_printable());
245 agent_addr.sin_port = htons(((UdpAddress &)address).get_port());
247 send_result = sendto(sock, (char*) send_buf, SAFE_INT_CAST(send_len), 0,
248 (struct sockaddr*) &agent_addr, sizeof(agent_addr));
253 struct sockaddr_in6 agent_addr;
254 memset(&agent_addr, 0, sizeof(agent_addr));
255 unsigned int scope = 0;
257 OctetStr addrstr = ((IpAddress &)address).IpAddress::get_printable();
259 if (((IpAddress &)address).has_ipv6_scope())
261 scope = ((IpAddress &)address).get_scope();
263 int i = addrstr.len() - 1;
264 while ((i>0) && (addrstr[i] != '%'))
266 addrstr.set_len(addrstr.len() - 1);
269 if (addrstr[i] == '%')
270 addrstr.set_len(addrstr.len() - 1);
273 if (inet_pton(AF_INET6, addrstr.get_printable(),
274 &agent_addr.sin6_addr) < 0)
276 LOG_BEGIN(ERROR_LOG | 1);
277 LOG("Snmp transport: inet_pton returns (errno) (str)");
279 LOG(strerror(errno));
283 agent_addr.sin6_family = AF_INET6;
284 agent_addr.sin6_port = htons(((UdpAddress &)address).get_port());
285 agent_addr.sin6_scope_id = scope;
286 send_result = sendto( sock, (char*) send_buf, send_len, 0,
287 (struct sockaddr*) &agent_addr, sizeof(agent_addr));
289 debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
296 debugprintf(0, "Error sending packet: %s", strerror(errno));
297 return -1; // send error!
303 //---------[ receive a snmp response ]---------------------------------
304 // Receive a response from the specified socket.
305 // This function does not set the request id in the pdu if
306 // any error occur in receiving or parsing. This is important
307 // because the caller initializes this to zero and checks it to
308 // see whether it has been changed to a valid value. The
309 // return value is the normal PDU status or SNMP_CLASS_SUCCESS.
310 // when we are successful in receiving a pdu. Otherwise it
311 // is an error status.
313 int receive_snmp_response(SnmpSocket sock, Snmp &snmp_session,
314 Pdu &pdu, UdpAddress &fromaddress,
315 OctetStr &engine_id, bool process_msg = true)
317 unsigned char receive_buffer[MAX_SNMP_PACKET + 1];
318 long receive_buffer_len; // len of received data
320 struct sockaddr_storage from_addr;
322 struct sockaddr_in from_addr;
324 #if !(defined (CPU) && CPU == PPC603) && (defined __GNUC__ || defined __FreeBSD__ || defined _AIX) && ! defined __MINGW32__
329 fromlen = sizeof(from_addr);
331 memset(&from_addr, 0, sizeof(from_addr));
335 receive_buffer_len = (long) recvfrom(sock, (char *) receive_buffer,
336 MAX_SNMP_PACKET + 1, 0,
337 (struct sockaddr*) &from_addr,
339 debugprintf(2, "++ SNMP++: something received...");
340 } while ((receive_buffer_len < 0) && (EINTR == errno));
342 if (receive_buffer_len < 0 ) // error or no data pending
343 return SNMP_CLASS_TL_FAILED;
344 debugprintf(6, "Length received %i from socket %i; fromlen %i",
345 receive_buffer_len, sock, fromlen);
347 if (receive_buffer_len == MAX_SNMP_PACKET + 1)
349 // Message is too long...
350 debugprintf(1, "Received message is ignored (packet too long)");
351 return SNMP_CLASS_ERROR;
354 if (((sockaddr_in&)from_addr).sin_family == AF_INET)
357 fromaddress = inet_ntoa(((sockaddr_in&)from_addr).sin_addr);
358 fromaddress.set_port(ntohs(((sockaddr_in&)from_addr).sin_port));
361 else if (from_addr.ss_family == AF_INET6)
364 char tmp_buffer[INET6_ADDRSTRLEN+1];
366 inet_ntop(AF_INET6, &(((sockaddr_in6&)from_addr).sin6_addr),
367 tmp_buffer, INET6_ADDRSTRLEN);
369 fromaddress = tmp_buffer;
370 fromaddress.set_port(ntohs(((sockaddr_in6&)from_addr).sin6_port));
371 if (((sockaddr_in6&)from_addr).sin6_scope_id != 0)
372 fromaddress.set_scope(((sockaddr_in6&)from_addr).sin6_scope_id);
374 #endif // SNMP_PP_IPv6
377 debugprintf(0, "Unknown socket address family (%i).",
378 ((sockaddr_in&)from_addr).sin_family);
379 return SNMP_CLASS_ERROR;
382 debugprintf(1, "++ SNMP++: data received from %s.",
383 fromaddress.get_printable());
384 debughexprintf(5, receive_buffer, receive_buffer_len);
386 if (process_msg == false)
387 return SNMP_CLASS_SUCCESS; // return success
390 if ( snmpmsg.load( receive_buffer, receive_buffer_len) != SNMP_CLASS_SUCCESS)
391 return SNMP_CLASS_ERROR;
393 OctetStr community_name;
394 snmp_version version;
395 OctetStr security_name;
398 long int security_model;
399 if (snmpmsg.is_v3_message() == TRUE)
401 int returncode = snmpmsg.unloadv3(pdu, version, engine_id,
402 security_name, security_model,
403 fromaddress, snmp_session);
404 if (returncode != SNMP_CLASS_SUCCESS)
410 int returncode = snmpmsg.unload( pdu, community_name, version);
411 if (returncode != SNMP_CLASS_SUCCESS)
412 return SNMP_CLASS_ERROR;
415 if (version == version3)
417 debugprintf(4,"receive_snmp_response: engine_id (%s), security_name (%s), "
418 "security_model (%i), security_level (%i)",
419 engine_id.get_printable(), security_name.get_printable(),
420 security_model, pdu.get_security_level());
421 debugprintf(5," addtoengineidtable: (%s)",
422 (unsigned char*)fromaddress.get_printable());
426 //-----[ check for error status stuff..]
427 // an error status is a valid pdu,
428 // the caller needs to know about it
429 if ( pdu.get_error_status() != 0)
430 return pdu.get_error_status();
432 debugprintf(5,"receive_snmp_response requestID = %li, "
433 "returning SUCCESS.", pdu.get_request_id());
435 return SNMP_CLASS_SUCCESS; // Success! return
439 //---------[ receive a snmp trap ]---------------------------------
440 // Receive a trap from the specified socket
441 // note: caller has to delete target!
442 int receive_snmp_notification(SnmpSocket sock, Snmp &snmp_session,
443 Pdu &pdu, SnmpTarget **target)
445 unsigned char receive_buffer[MAX_SNMP_PACKET + 1];
446 long receive_buffer_len; // len of received data
449 struct sockaddr_storage from_addr;
451 struct sockaddr_in from_addr;
452 #endif // SNMP_PP_IPv6
454 #if !(defined (CPU) && CPU == PPC603) && (defined __GNUC__ || defined __FreeBSD__ || defined _AIX) && ! defined __MINGW32__
459 fromlen = sizeof(from_addr);
461 memset(&from_addr, 0, sizeof(from_addr));
465 receive_buffer_len = (long) recvfrom(sock, (char *) receive_buffer,
466 MAX_SNMP_PACKET + 1, 0,
467 (struct sockaddr*)&from_addr,
469 } while (receive_buffer_len < 0 && EINTR == errno);
471 if (receive_buffer_len < 0 ) // error or no data pending
472 return SNMP_CLASS_TL_FAILED;
474 if (receive_buffer_len == MAX_SNMP_PACKET + 1)
476 // Message is too long...
477 debugprintf(1, "Received message is ignored (packet too long)");
478 return SNMP_CLASS_ERROR;
481 // copy fromaddress and remote port
482 UdpAddress fromaddress;
484 if (((sockaddr_in&)from_addr).sin_family == AF_INET)
487 fromaddress = inet_ntoa(((sockaddr_in&)from_addr).sin_addr);
488 fromaddress.set_port(ntohs(((sockaddr_in&)from_addr).sin_port));
491 else if (from_addr.ss_family == AF_INET6)
494 char tmp_buffer[INET6_ADDRSTRLEN+1];
496 inet_ntop(AF_INET6, &(((sockaddr_in6&)from_addr).sin6_addr),
497 tmp_buffer, INET6_ADDRSTRLEN);
499 fromaddress = tmp_buffer;
500 fromaddress.set_port(ntohs(((sockaddr_in6&)from_addr).sin6_port));
501 if (((sockaddr_in6&)from_addr).sin6_scope_id != 0)
502 fromaddress.set_scope(((sockaddr_in6&)from_addr).sin6_scope_id);
504 #endif // SNMP_PP_IPv6
507 debugprintf(0, "Unknown socket address family (%i).",
508 ((sockaddr_in&)from_addr).sin_family);
509 return SNMP_CLASS_TL_FAILED;
512 debugprintf(1, "++ SNMP++: data received from %s.",
513 fromaddress.get_printable());
514 debughexprintf(5, receive_buffer, receive_buffer_len);
517 if ( snmpmsg.load( receive_buffer, receive_buffer_len) != SNMP_CLASS_SUCCESS)
518 return SNMP_CLASS_ERROR;
520 OctetStr community_name;
521 snmp_version version;
523 OctetStr security_name;
526 long int security_model;
527 if (snmpmsg.is_v3_message() == TRUE)
529 int returncode = snmpmsg.unloadv3(pdu, version, engine_id,
530 security_name, security_model,
531 fromaddress, snmp_session);
532 if (returncode != SNMP_CLASS_SUCCESS)
538 int returncode = snmpmsg.unload( pdu, community_name, version);
539 if (returncode != SNMP_CLASS_SUCCESS)
540 return SNMP_CLASS_ERROR;
544 if (version == version3) {
545 *target = new UTarget();
546 (*target)->set_address(fromaddress);
547 (*target)->set_version(version);
548 ((UTarget*)*target)->set_engine_id(engine_id);
549 ((UTarget*)*target)->set_security_name(security_name);
550 ((UTarget*)*target)->set_security_model(security_model);
552 v3MP::I->add_to_engine_id_table(engine_id,
553 (char*)(fromaddress.IpAddress::get_printable()),
554 fromaddress.get_port());
556 debugprintf(4,"receive_snmp_notification: engine_id (%s), security_name "
557 "(%s), security_model (%i), security_level (%i)",
558 engine_id.get_printable(), security_name.get_printable(),
559 security_model, pdu.get_security_level());
564 *target = new CTarget();
565 (*target)->set_version(version);
566 (*target)->set_address(fromaddress);
567 ((CTarget*)*target)->set_readcommunity( community_name);
568 ((CTarget*)*target)->set_writecommunity( community_name);
572 return SNMP_CLASS_SUCCESS; // Success! return
576 //--------[ map action ]------------------------------------------------
577 // map the snmp++ action to a SMI pdu type
578 void Snmp::map_action( unsigned short action, unsigned short & pdu_action)
583 case sNMP_PDU_GET_ASYNC:
584 pdu_action = sNMP_PDU_GET;
588 case sNMP_PDU_SET_ASYNC:
589 pdu_action = sNMP_PDU_SET;
592 case sNMP_PDU_GETNEXT:
593 case sNMP_PDU_GETNEXT_ASYNC:
594 pdu_action = sNMP_PDU_GETNEXT;
597 case sNMP_PDU_GETBULK:
598 case sNMP_PDU_GETBULK_ASYNC:
599 pdu_action = sNMP_PDU_GETBULK;
602 case sNMP_PDU_RESPONSE:
603 pdu_action = sNMP_PDU_RESPONSE;
606 case sNMP_PDU_INFORM:
607 case sNMP_PDU_INFORM_ASYNC:
608 pdu_action = sNMP_PDU_INFORM;
611 case sNMP_PDU_REPORT:
612 pdu_action = sNMP_PDU_REPORT;
616 pdu_action = sNMP_PDU_GET; // TM ?? error ??
622 //------[ Snmp Class Constructor ]--------------------------------------
624 Snmp::Snmp(int &status, const unsigned short port, const bool bind_ipv6)
625 : SnmpSynchronized(),
626 m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
628 IpAddress *addresses[2];
632 listen_address = "::";
635 addresses[1] = &listen_address;
637 init(status, addresses, 0, port);
641 listen_address = "0.0.0.0";
643 addresses[0] = &listen_address;
646 init(status, addresses, port, 0);
651 Snmp::Snmp( int &status, const UdpAddress& addr)
652 : SnmpSynchronized(),
653 m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
655 IpAddress *addresses[2];
657 listen_address = addr;
659 if (listen_address.get_ip_version() == Address::version_ipv4)
661 addresses[0] = &listen_address;
663 init(status, addresses, addr.get_port(), 0);
668 addresses[1] = &listen_address;
669 init(status, addresses, 0, addr.get_port());
673 Snmp::Snmp( int &status, const UdpAddress& addr_v4,
674 const UdpAddress& addr_v6)
675 : SnmpSynchronized(),
676 m_bThreadRunning(false), m_iPollTimeOut(DEFAULT_TIMEOUT)
678 IpAddress *addresses[2];
680 listen_address = addr_v4;
681 IpAddress address_v6((IpAddress)addr_v6);
682 addresses[0] = &listen_address;
683 addresses[1] = &address_v6;
685 init(status, addresses, addr_v4.get_port(), addr_v6.get_port());
688 void Snmp::socket_startup()
692 (void)WSAStartup(0x0101, &WSAData);
696 void Snmp::socket_cleanup()
699 int iRetValue = WSACleanup();
700 debugprintf(4, "WSACleanup: ReturnValue (%i)", iRetValue);
704 void Snmp::init(int& status, IpAddress *addresses[2],
705 const unsigned short port_v4,
706 const unsigned short port_v6)
710 m_hThread = INVALID_HANDLE_VALUE;
711 m_hThreadEndEvent = ::CreateEvent(NULL, true, false, NULL);
715 eventListHolder = new EventListHolder(this);
716 // initialize the request_id
717 eventListHolder->snmpEventList()->lock();
718 // srand(time(0)); // better than nothing
719 current_rid = (rand() % (PDU_MAX_RID - PDU_MIN_RID +1)) + PDU_MIN_RID;
720 debugprintf(4, "Initialized request_id to %i.", current_rid);
721 eventListHolder->snmpEventList()->unlock();
723 // intialize all the trap receiving member variables
725 notifycallback_data = 0;
730 status = SNMP_CLASS_ERROR;
731 iv_snmp_session = INVALID_SOCKET;
733 iv_snmp_session_ipv6 = INVALID_SOCKET;
736 /* Open IPv4 socket */
739 // open a socket to be used for the session
740 if (( iv_snmp_session = socket( AF_INET, SOCK_DGRAM,0)) == INVALID_SOCKET)
743 int werr = WSAGetLastError();
744 debugprintf(1, "Call to socket throws error %d", werr);
745 if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
746 status = SNMP_CLASS_RESOURCE_UNAVAIL;
747 else if (WSAEHOSTDOWN == werr)
748 status = SNMP_CLASS_TL_FAILED;
750 status = SNMP_CLASS_TL_UNSUPPORTED;
752 if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
753 status = SNMP_CLASS_RESOURCE_UNAVAIL;
754 else if (EHOSTDOWN == errno)
755 status = SNMP_CLASS_TL_FAILED;
757 status = SNMP_CLASS_TL_UNSUPPORTED;
762 // set up the manager socket attributes
763 unsigned long inaddr = inet_addr(addresses[0]->get_printable());
764 struct sockaddr_in mgr_addr;
765 memset(&mgr_addr, 0, sizeof(mgr_addr));
766 mgr_addr.sin_family = AF_INET;
767 mgr_addr.sin_addr.s_addr = inaddr;
768 mgr_addr.sin_port = htons( port_v4);
769 #ifdef CYGPKG_NET_OPENBSD_STACK
770 mgr_addr.sin_len = sizeof(mgr_addr);
774 if (bind(iv_snmp_session, (struct sockaddr*)&mgr_addr,
775 sizeof(mgr_addr)) < 0)
778 int werr = WSAGetLastError();
779 debugprintf(1, "Call to bind throws error %d", werr);
780 if (WSAEADDRINUSE == werr)
781 status = SNMP_CLASS_TL_IN_USE;
782 else if (WSAENOBUFS == werr)
783 status = SNMP_CLASS_RESOURCE_UNAVAIL;
784 else if (werr == WSAEAFNOSUPPORT)
785 status = SNMP_CLASS_TL_UNSUPPORTED;
786 else if (werr == WSAENETUNREACH)
787 status = SNMP_CLASS_TL_FAILED;
788 else if (werr == EACCES)
789 status = SNMP_CLASS_TL_ACCESS_DENIED;
791 status = SNMP_CLASS_INTERNAL_ERROR;
793 if (EADDRINUSE == errno)
794 status = SNMP_CLASS_TL_IN_USE;
795 else if (ENOBUFS == errno)
796 status = SNMP_CLASS_RESOURCE_UNAVAIL;
797 else if (errno == EAFNOSUPPORT)
798 status = SNMP_CLASS_TL_UNSUPPORTED;
799 else if (errno == ENETUNREACH)
800 status = SNMP_CLASS_TL_FAILED;
801 else if (errno == EACCES)
802 status = SNMP_CLASS_TL_ACCESS_DENIED;
805 debugprintf(0, "Uncatched errno value %d, returning internal error.",
807 status = SNMP_CLASS_INTERNAL_ERROR;
810 close(iv_snmp_session); // close the dynamic socket
811 iv_snmp_session = INVALID_SOCKET;
815 status = SNMP_CLASS_SUCCESS;
816 #ifdef SNMP_BROADCAST
817 int enable_broadcast = 1;
818 setsockopt(iv_snmp_session, SOL_SOCKET, SO_BROADCAST,
819 (char*)&enable_broadcast, sizeof(enable_broadcast));
823 if (status != SNMP_CLASS_SUCCESS)
827 /* Open IPv6 socket */
831 // open a socket to be used for the session
832 if (( iv_snmp_session_ipv6 = socket( AF_INET6, SOCK_DGRAM,0))
836 int werr = WSAGetLastError();
837 if (EMFILE == werr ||WSAENOBUFS == werr || ENFILE == werr)
838 status = SNMP_CLASS_RESOURCE_UNAVAIL;
839 else if (WSAEHOSTDOWN == werr)
840 status = SNMP_CLASS_TL_FAILED;
842 status = SNMP_CLASS_TL_UNSUPPORTED;
844 if (EMFILE == errno || ENOBUFS == errno || ENFILE == errno)
845 status = SNMP_CLASS_RESOURCE_UNAVAIL;
846 else if (EHOSTDOWN == errno)
847 status = SNMP_CLASS_TL_FAILED;
849 status = SNMP_CLASS_TL_UNSUPPORTED;
854 // set up the manager socket attributes
855 struct sockaddr_in6 mgr_addr;
856 memset(&mgr_addr, 0, sizeof(mgr_addr));
857 unsigned int scope = 0;
859 OctetStr addrstr = addresses[1]->get_printable();
861 if (addresses[1]->has_ipv6_scope())
863 scope = addresses[1]->get_scope();
865 int i = addrstr.len() - 1;
866 while ((i>0) && (addrstr[i] != '%'))
868 addrstr.set_len(addrstr.len() - 1);
871 if (addrstr[i] == '%')
872 addrstr.set_len(addrstr.len() - 1);
874 if (inet_pton(AF_INET6, addrstr.get_printable(),
875 &mgr_addr.sin6_addr) < 0)
877 LOG_BEGIN(ERROR_LOG | 1);
878 LOG("Snmp transport: inet_pton returns (errno) (str)");
880 LOG(strerror(errno));
882 status = SNMP_CLASS_INVALID_ADDRESS;
886 mgr_addr.sin6_family = AF_INET6;
887 mgr_addr.sin6_port = htons( port_v6);
888 mgr_addr.sin6_scope_id = scope;
890 if (bind(iv_snmp_session_ipv6, (struct sockaddr*) &mgr_addr,
891 sizeof(mgr_addr)) < 0)
894 int werr = WSAGetLastError();
895 if (WSAEADDRINUSE == werr)
896 status = SNMP_CLASS_TL_IN_USE;
897 else if (WSAENOBUFS == werr)
898 status = SNMP_CLASS_RESOURCE_UNAVAIL;
899 else if (werr == WSAEAFNOSUPPORT)
900 status = SNMP_CLASS_TL_UNSUPPORTED;
901 else if (werr == WSAENETUNREACH)
902 status = SNMP_CLASS_TL_FAILED;
903 else if (werr == EACCES)
904 status = SNMP_CLASS_TL_ACCESS_DENIED;
906 status = SNMP_CLASS_INTERNAL_ERROR;
908 if (EADDRINUSE == errno)
909 status = SNMP_CLASS_TL_IN_USE;
910 else if (ENOBUFS == errno)
911 status = SNMP_CLASS_RESOURCE_UNAVAIL;
912 else if (errno == EAFNOSUPPORT)
913 status = SNMP_CLASS_TL_UNSUPPORTED;
914 else if (errno == ENETUNREACH)
915 status = SNMP_CLASS_TL_FAILED;
916 else if (errno == EACCES)
917 status = SNMP_CLASS_TL_ACCESS_DENIED;
919 status = SNMP_CLASS_INTERNAL_ERROR;
921 close(iv_snmp_session_ipv6); // close the dynamic socket
922 iv_snmp_session_ipv6 = INVALID_SOCKET;
926 status = SNMP_CLASS_SUCCESS;
927 #ifdef SNMP_BROADCAST
928 int enable_broadcast = 1;
929 setsockopt(iv_snmp_session_ipv6, SOL_SOCKET, SO_BROADCAST,
930 (char*)&enable_broadcast, sizeof(enable_broadcast));
935 debugprintf(0, "User error: Enable IPv6 and recompile snmp++.");
936 #endif // SNMP_PP_IPv6
942 //---------[ Snmp Class Destructor ]----------------------------------
949 ::CloseHandle(m_hThreadEndEvent);
953 // if we failed during construction then don't try
954 // to free stuff up that was not allocated
955 if (iv_snmp_session != INVALID_SOCKET)
957 // go through the snmpEventList and delete any outstanding
958 // events on this socket
959 eventListHolder->snmpEventList()->DeleteSocketEntry(iv_snmp_session);
961 close(iv_snmp_session); // close the dynamic socket
963 // if we failed during construction then don't try
964 // to free stuff up that was not allocated
967 if (iv_snmp_session_ipv6 != INVALID_SOCKET)
969 // go through the snmpEventList and delete any outstanding
970 // events on this socket
971 eventListHolder->snmpEventList()->DeleteSocketEntry(iv_snmp_session_ipv6);
973 close(iv_snmp_session_ipv6); // close the dynamic socket
977 // shut down trap reception if used
980 delete eventListHolder;
983 // Get the version of the snmp++ library at runtime
984 // This function MUST stay in the cpp file!
985 const char *Snmp::get_version()
987 return SNMP_PP_VERSION_STRING;
990 //-------------------[ returns error string ]--------------------------
991 const char *Snmp::error_msg(const int c)
994 if (c>=SNMPv3_USM_MIN_ERROR)
995 return ((c>SNMPv3_USM_MAX_ERROR)?pv3Errs[SNMPv3_USM_ERRORCOUNT]:pv3Errs[c-SNMPv3_USM_MIN_ERROR]);
996 if (c<=SNMPv3_MP_MAX_ERROR)
997 return ((c<SNMPv3_MP_MIN_ERROR)?nv3Errs[SNMPv3_MP_ERRORCOUNT]:nv3Errs[SNMPv3_MP_MAX_ERROR - c]);
1000 ((c<MAX_NEG_ERROR)?nErrs[-(MAX_NEG_ERROR)+1]:nErrs[-c]):
1001 ((c>MAX_POS_ERROR)?pErrs[MAX_POS_ERROR+1]:pErrs[c]));
1005 const char* Snmp::error_msg(const Oid& v3Oid)
1008 if (v3Oid == oidUsmStatsUnsupportedSecLevels)
1009 return error_msg(SNMPv3_USM_UNSUPPORTED_SECURITY_LEVEL);
1011 if (v3Oid == oidUsmStatsNotInTimeWindows)
1012 return error_msg(SNMPv3_USM_NOT_IN_TIME_WINDOW);
1014 if (v3Oid == oidUsmStatsUnknownUserNames )
1015 return error_msg(SNMPv3_USM_UNKNOWN_SECURITY_NAME);
1017 if (v3Oid == oidUsmStatsUnknownEngineIDs)
1018 return error_msg(SNMPv3_USM_UNKNOWN_ENGINEID);
1020 if (v3Oid == oidUsmStatsWrongDigests)
1021 return error_msg(SNMPv3_USM_AUTHENTICATION_FAILURE);
1023 if (v3Oid == oidUsmStatsDecryptionErrors)
1024 return error_msg(SNMPv3_USM_DECRYPTION_ERROR);
1027 if (v3Oid == oidSnmpUnknownSecurityModels)
1028 return error_msg(SNMPv3_MP_UNSUPPORTED_SECURITY_MODEL);
1030 if (v3Oid == oidSnmpInvalidMsgs)
1031 return error_msg(SNMPv3_MP_INVALID_MESSAGE);
1033 if (v3Oid == oidSnmpUnknownPDUHandlers)
1034 return error_msg(SNMPv3_MP_UNKNOWN_PDU_HANDLERS);
1036 if (v3Oid == oidSnmpUnavailableContexts)
1037 return error_msg(SNMPv3_MP_UNAVAILABLE_CONTEXT);
1039 if (v3Oid == oidSnmpUnknownContexts)
1040 return error_msg(SNMPv3_MP_UNKNOWN_CONTEXT);
1042 return error_msg(MAX_POS_ERROR + 1);
1046 //------------------------[ get ]---------------------------------------
1047 int Snmp::get(Pdu &pdu, const SnmpTarget &target)
1049 pdu.set_type( sNMP_PDU_GET);
1050 return snmp_engine( pdu, 0, 0, target, NULL, 0);
1053 //------------------------[ get async ]----------------------------------
1054 int Snmp::get(Pdu &pdu, const SnmpTarget &target,
1055 const snmp_callback callback,
1056 const void * callback_data)
1058 pdu.set_type( sNMP_PDU_GET_ASYNC);
1059 return snmp_engine( pdu, 0, 0, target, callback, callback_data);
1062 //------------------------[ get next ]-----------------------------------
1063 int Snmp::get_next(Pdu &pdu, const SnmpTarget &target)
1065 pdu.set_type( sNMP_PDU_GETNEXT);
1066 return snmp_engine( pdu, 0, 0, target, NULL, 0);
1069 //------------------------[ get next async ]-----------------------------
1070 int Snmp::get_next(Pdu &pdu, const SnmpTarget &target,
1071 const snmp_callback callback,
1072 const void * callback_data)
1074 pdu.set_type( sNMP_PDU_GETNEXT_ASYNC);
1075 return snmp_engine( pdu, 0, 0, target, callback, callback_data);
1078 //-------------------------[ set ]---------------------------------------
1079 int Snmp::set(Pdu &pdu, const SnmpTarget &target)
1081 pdu.set_type( sNMP_PDU_SET);
1082 return snmp_engine( pdu, 0, 0, target, NULL, 0);
1085 //------------------------[ set async ]----------------------------------
1086 int Snmp::set(Pdu &pdu, const SnmpTarget &target,
1087 const snmp_callback callback,
1088 const void * callback_data)
1090 pdu.set_type( sNMP_PDU_SET_ASYNC);
1091 return snmp_engine( pdu, 0, 0, target, callback, callback_data);
1094 //-----------------------[ get bulk ]------------------------------------
1095 int Snmp::get_bulk(Pdu &pdu, // pdu to use
1096 const SnmpTarget &target,// destination target
1097 const int non_repeaters, // number of non repeaters
1098 const int max_reps) // maximum number of repetitions
1100 pdu.set_type( sNMP_PDU_GETBULK);
1101 return snmp_engine( pdu, non_repeaters, max_reps, target, NULL, 0);
1104 //-----------------------[ get bulk async ]------------------------------
1105 int Snmp::get_bulk(Pdu &pdu, // pdu to use
1106 const SnmpTarget &target, // destination target
1107 const int non_repeaters, // number of non repeaters
1108 const int max_reps, // maximum number of repetitions
1109 const snmp_callback callback,// callback to use
1110 const void * callback_data) // callback data
1112 pdu.set_type( sNMP_PDU_GETBULK_ASYNC);
1113 return snmp_engine( pdu, non_repeaters, max_reps, target,
1114 callback, callback_data);
1117 //------------------------[ inform_response ]----------------------------
1118 int Snmp::response(Pdu &pdu, // pdu to use
1119 const SnmpTarget &target, // response target
1120 const SnmpSocket fd)
1122 pdu.set_type( sNMP_PDU_RESPONSE);
1123 return snmp_engine(pdu, 0, 0, target, NULL, 0, fd);
1126 int Snmp::send_raw_data(unsigned char *send_buf,
1127 size_t send_len, UdpAddress &address, SnmpSocket fd)
1129 // REENTRANT() removed because of #ifdef
1130 SnmpSynchronize _synchronize(*this);
1132 if (fd != INVALID_SOCKET)
1133 return send_snmp_request(fd, send_buf, send_len, address);
1137 if (address.get_ip_version() == Address::version_ipv4)
1139 if (iv_snmp_session != INVALID_SOCKET)
1140 return send_snmp_request(iv_snmp_session, send_buf,
1143 address.map_to_ipv6();
1145 return send_snmp_request(iv_snmp_session_ipv6, send_buf,
1148 return send_snmp_request(iv_snmp_session, send_buf,
1155 //-----------------------[ cancel ]--------------------------------------
1156 int Snmp::cancel(const unsigned long request_id)
1158 eventListHolder->snmpEventList()->lock();
1159 int status = eventListHolder->snmpEventList()->DeleteEntry(request_id);
1160 eventListHolder->snmpEventList()->unlock();
1166 //----------------------[ sending report, V3 only]-----------------------
1167 int Snmp::report(Pdu &pdu, // pdu to send
1168 const SnmpTarget &target)// destination target
1170 pdu.set_type( sNMP_PDU_REPORT);
1171 return snmp_engine( pdu, 0, 0, target, NULL, 0);
1174 //----------------------[ blocking inform, V2 only]------------------------
1175 int Snmp::inform(Pdu &pdu, // pdu to send
1176 const SnmpTarget &target)// destination target
1178 if (target.get_version() == version1)
1180 LOG_BEGIN(ERROR_LOG | 1);
1181 LOG("Snmp: Invalid Operation: Inform not defined for SNMPv1");
1184 return SNMP_CLASS_INVALID_OPERATION;
1187 pdu.set_type( sNMP_PDU_INFORM);
1188 check_notify_timestamp(pdu);
1189 return snmp_engine( pdu, 0, 0, target, NULL, 0);
1192 //----------------------[ asynch inform, V2 only]------------------------
1193 int Snmp::inform(Pdu &pdu, // pdu to send
1194 const SnmpTarget &target, // destination target
1195 const snmp_callback callback, // callback function
1196 const void * callback_data) // callback data
1198 if (target.get_version() == version1)
1200 LOG_BEGIN(ERROR_LOG | 1);
1201 LOG("Snmp: Invalid Operation: Inform not defined for SNMPv1");
1204 return SNMP_CLASS_INVALID_OPERATION;
1207 pdu.set_type(sNMP_PDU_INFORM_ASYNC);
1208 check_notify_timestamp(pdu);
1209 return snmp_engine( pdu, 0, 0, target, callback, callback_data);
1213 //---------------------[ send a trap ]-----------------------------------
1214 int Snmp::trap(Pdu &pdu, // pdu to send
1215 const SnmpTarget &target) // destination target
1217 OctetStr my_get_community;
1218 OctetStr my_set_community;
1220 unsigned long my_timeout;
1222 unsigned char version;
1225 debugprintf(1, "++ SNMP++, Send a Trap");
1226 //---------[ make sure pdu is valid ]---------------------------------
1229 debugprintf(0, "-- SNMP++, PDU Object Invalid");
1230 return SNMP_CLASS_INVALID_PDU;
1233 //---------[ make sure target is valid ]------------------------------
1234 if (!target.valid())
1236 debugprintf(0, "-- SNMP++, Target Object Invalid");
1237 return SNMP_CLASS_INVALID_TARGET;
1240 CTarget* ctarget = NULL;
1241 UTarget* utarget = NULL;
1242 OctetStr security_name;
1245 switch (target.get_type()) {
1246 case SnmpTarget::type_ctarget:
1247 ctarget = (CTarget*)(&target);
1249 case SnmpTarget::type_utarget:
1250 utarget = (UTarget*)(&target);
1252 case SnmpTarget::type_base:
1253 debugprintf(0, "-- SNMP++, do not use SnmpTarget, use a CTarget or UTarget");
1254 return SNMP_CLASS_INVALID_TARGET;
1256 // target is not known
1257 debugprintf(0, "-- SNMP++, type of target is unknown!");
1258 return SNMP_CLASS_UNSUPPORTED;
1262 debugprintf(3, "snmp::trap called with CTarget");
1263 if (!ctarget->resolve_to_C( my_get_community, my_set_community, address,
1264 my_timeout, my_retry, version))
1266 debugprintf(0, "-- SNMP++, Resolve Fail (CTarget)");
1267 return SNMP_CLASS_UNSUPPORTED;
1270 if (version == version3)
1272 debugprintf(0, "-- SNMP++, use UTarget for SNMPv3");
1273 return SNMP_CLASS_INVALID_TARGET;
1277 else { // target is not a CTarget:
1279 debugprintf(3, "trap called with UTarget");
1280 if (!utarget->resolve_to_U( security_name, security_model, address,
1281 my_timeout, my_retry, version))
1283 debugprintf(0, "-- SNMP++, Resolve Fail (UTarget)");
1284 return SNMP_CLASS_UNSUPPORTED;
1287 if (version != version3) {
1289 my_get_community = security_name;
1290 if ((security_model != SNMP_SECURITY_MODEL_V1) &&
1291 (security_model != SNMP_SECURITY_MODEL_V2)) {
1292 debugprintf(0, "-- SNMP++, Target contains invalid security_model/version combination");
1293 return SNMP_CLASS_INVALID_TARGET;
1296 } // end if (version != version3)
1299 else { // target is neither CTarget nor UTarget:
1300 debugprintf(0, "-- SNMP++, Resolve Fail");
1301 return SNMP_CLASS_INVALID_TARGET;
1305 //--------[ determine request id to use ]------------------------------
1306 pdu.set_request_id( MyMakeReqId());
1308 //--------[ check timestamp, if null use system time ]-----------------
1309 check_notify_timestamp(pdu);
1311 //------[ validate address to use ]-------------------------------------
1312 if (!address.valid()) {
1313 debugprintf(0, "-- SNMP++, Bad address");
1314 return SNMP_CLASS_INVALID_TARGET;
1317 if ((address.get_type() != Address::type_ip) &&
1318 (address.get_type() != Address::type_udp) )
1320 debugprintf(0, "-- SNMP++, Bad address type");
1321 return SNMP_CLASS_TL_UNSUPPORTED;
1324 UdpAddress udp_address(address);
1325 if (!udp_address.valid()) {
1326 debugprintf(0, "-- SNMP++, copy address failed");
1327 return SNMP_CLASS_RESOURCE_UNAVAIL;
1330 //----------[ choose the target address port ]-----------------------
1331 if ((address.get_type() == Address::type_ip) || !udp_address.get_port())
1332 udp_address.set_port(SNMP_TRAP_PORT);
1334 //----------[ based on the target type, choose v1 or v1 trap type ]-----
1335 if ( version == version1)
1336 pdu.set_type( sNMP_PDU_V1TRAP);
1337 else // v2 and v3 use v2TRAP
1338 pdu.set_type( sNMP_PDU_TRAP);
1340 SnmpMessage snmpmsg;
1343 if ( version == version3) {
1345 OctetStr engine_id = v3MP::I->get_local_engine_id();
1347 debugprintf(0, "-- SNMP++, dont know how to handle SNMPv3 without UTarget!");
1348 return SNMP_CLASS_INVALID_TARGET;
1351 // set context_engine_id of pdu, if it is not set
1352 if (pdu.get_context_engine_id().len() == 0)
1354 debugprintf(8, "Setting contextEngineID of Pdu to (%s)",
1355 engine_id.get_printable());
1356 pdu.set_context_engine_id(engine_id);
1359 debugprintf(4,"Snmp::trap:");
1360 debugprintf(4," engineID (%s), securityName (%s)\n securityModel (%i) security_level (%i)",
1361 engine_id.get_printable(), security_name.get_printable(),
1362 security_model, pdu.get_security_level());
1363 debugprintf(4," Addr/Port (%s)",udp_address.get_printable());
1365 status = snmpmsg.loadv3( pdu, engine_id, security_name,
1366 security_model, (snmp_version)version);
1370 status = snmpmsg.load( pdu, my_get_community, (snmp_version) version);
1372 if ( status != SNMP_CLASS_SUCCESS) {
1373 debugprintf(0, "snmp message load error!");
1378 //------[ send the trap ]
1380 if (udp_address.get_ip_version() == Address::version_ipv4)
1382 if (iv_snmp_session != INVALID_SOCKET)
1383 status = send_snmp_request(iv_snmp_session,
1384 snmpmsg.data(), (size_t)snmpmsg.len(),
1388 udp_address.map_to_ipv6();
1389 status = send_snmp_request(iv_snmp_session_ipv6,
1390 snmpmsg.data(), (size_t)snmpmsg.len(),
1395 status = send_snmp_request(iv_snmp_session_ipv6,
1396 snmpmsg.data(), (size_t)snmpmsg.len(),
1399 status = send_snmp_request(iv_snmp_session, snmpmsg.data(),
1400 (size_t)snmpmsg.len(), udp_address);
1405 return SNMP_CLASS_TL_FAILED;
1407 return SNMP_CLASS_SUCCESS;
1410 //----------------[ set notify_timestamp if it is null ]-------------
1411 #if defined (CPU) && CPU == PPC603
1415 unsigned long NumMS;
1416 unsigned long FractMS;
1421 void GetTime (struct SCommTimer * Time);
1425 void Snmp::check_notify_timestamp(Pdu &pdu)
1427 // As we don't know, when the application was started,
1428 // use a continuously increasing notify_timestamp
1429 TimeTicks timestamp;
1430 pdu.get_notify_timestamp( timestamp);
1434 struct _timeb timebuffer;
1435 _ftime( &timebuffer );
1436 timebuffer.time -= 1103760000; // knock off 35 years worth of seconds
1437 timestamp = SAFE_ULONG_CAST((timebuffer.time * 100) +
1438 (timebuffer.millitm / 10));
1439 #elif defined (CPU) && CPU == PPC603
1442 GetTime(&theTime); // This function must be defined by the application
1444 timestamp = theTime.NumMS/10;
1447 gettimeofday(&tp, NULL);
1448 tp.tv_sec -= 1103760000; // knock off 35 years worth of seconds
1449 timestamp = (tp.tv_sec * 100) + (tp.tv_usec / 10000);
1452 pdu.set_notify_timestamp( timestamp);
1456 //-----------------------[ read the notification filters ]----------------
1457 int Snmp::get_notify_filter(OidCollection &trapids,
1458 TargetCollection &targets)
1460 CNotifyEvent *e = eventListHolder->notifyEventList()->GetEntry(this);
1462 if (!e) return SNMP_CLASS_INVALID;
1464 e->get_filter(trapids, targets);
1466 return SNMP_CLASS_SUCCESS;
1469 // Set the port for listening to traps and informs.
1470 void Snmp::notify_set_listen_port(const int port)
1472 eventListHolder->notifyEventList()->set_listen_port(port);
1475 // Get the port that is used for listening to traps and informs.
1476 int Snmp::notify_get_listen_port()
1478 return eventListHolder->notifyEventList()->get_listen_port();
1481 //-----------------------[ register to get traps]-------------------------
1482 int Snmp::notify_register(const OidCollection &trapids,
1483 const TargetCollection &targets,
1484 const snmp_callback callback,
1485 const void *callback_data)
1487 // remove any previous filters for this session
1488 notify_unregister();
1490 // assign callback and callback data info
1491 notifycallback = callback;
1492 notifycallback_data = (void *)callback_data;
1494 // add to the notify queue
1495 return eventListHolder->notifyEventList()->AddEntry(this, trapids, targets);
1498 //-----------------------[ un-register to get traps]----------------------
1499 int Snmp::notify_unregister()
1501 // remove from the notify queue
1502 eventListHolder->notifyEventList()->DeleteEntry(this);
1504 // null out callback information
1506 notifycallback_data = 0;
1508 return SNMP_CLASS_SUCCESS;
1511 //---------[ get / set engine ]-----------------------------------------
1512 // The main snmp engine used for all requests
1513 // async requests return out early and don't wait in here for
1515 int Snmp::snmp_engine( Pdu &pdu, // pdu to use
1516 long int non_reps, // # of non repititions
1517 long int max_reps, // # of max repititions
1518 const SnmpTarget &target, // from this target
1519 const snmp_callback cb,// callback for async calls
1520 const void *cbd, // callback data
1522 int reports_received)
1525 long req_id = 0; // pdu request id
1526 int status; // send status
1529 // save original PDU for later reference
1530 Pdu backupPdu = pdu;
1532 for (int maxloops=0; maxloops<3; maxloops++)
1536 unsigned short pdu_action; // type of pdu to build
1537 unsigned short action; // type of pdu to build
1538 unsigned long my_timeout; // target specific timeout
1539 int my_retry; // target specific retry
1541 OctetStr my_get_community;
1542 OctetStr my_set_community;
1544 unsigned char version;
1546 //---------[ make sure pdu is valid ]--------------------------
1548 return SNMP_CLASS_INVALID_PDU;
1550 //---------[ depending on user action, map the correct pdu action]
1551 action = pdu.get_type();
1552 map_action(action, pdu_action);
1554 //---------[ check for correct mode ]---------------------------
1555 // if the class was constructed as a blocked model, callback=0
1556 // and async calls are attempted, an error is returned
1558 ((action == sNMP_PDU_GET_ASYNC) ||
1559 (action == sNMP_PDU_SET_ASYNC) ||
1560 (action == sNMP_PDU_GETNEXT_ASYNC) ||
1561 (action == sNMP_PDU_GETBULK_ASYNC) ||
1562 (action == sNMP_PDU_INFORM_ASYNC)))
1563 return SNMP_CLASS_INVALID_CALLBACK;
1565 //---------[ more mode checking ]--------------------------------
1566 // if the class was constructed as an async model, callback = something
1567 // and blocked calls are attempted, an error is returned
1569 ((action == sNMP_PDU_GET) ||
1570 (action == sNMP_PDU_SET) ||
1571 (action == sNMP_PDU_GETNEXT) ||
1572 (action == sNMP_PDU_GETBULK) ||
1573 (action == sNMP_PDU_INFORM)))
1574 return SNMP_CLASS_INVALID_CALLBACK;
1576 //---------[ make sure target is valid ]-------------------------
1577 // make sure that the target is valid
1578 if ( ! target.valid())
1579 return SNMP_CLASS_INVALID_TARGET;
1581 OctetStr community_string;
1582 OctetStr security_name;
1584 const CTarget* ctarget = NULL;
1585 const UTarget* utarget = NULL;
1587 switch (target.get_type())
1589 case SnmpTarget::type_ctarget:
1590 ctarget = (CTarget*)(&target);
1592 case SnmpTarget::type_utarget:
1593 utarget = (UTarget*)(&target);
1595 case SnmpTarget::type_base:
1596 debugprintf(0, "-- SNMP++, do not use SnmpTarget,"
1597 "use a CTarget or UTarget");
1598 return SNMP_CLASS_INVALID_TARGET;
1600 /* target is not known */
1601 debugprintf(0, "-- SNMP++, type of target is unknown!");
1602 return SNMP_CLASS_UNSUPPORTED;
1605 if (ctarget) /* Is is a CTarget? */
1607 debugprintf(3, "snmp_engine called with CTarget");
1608 if (!ctarget->resolve_to_C( my_get_community, my_set_community,
1609 address, my_timeout, my_retry, version))
1611 debugprintf(0, "-- SNMP++, Resolve Fail (CTarget)");
1612 return SNMP_CLASS_UNSUPPORTED;
1615 if ((version == version3) ||
1616 (action == sNMP_PDU_REPORT))
1618 debugprintf(0, "-- SNMP++, use UTarget for SNMPv3");
1619 return SNMP_CLASS_INVALID_TARGET;
1622 //----------[ use the appropriate community string ]-----------------
1623 if (( action == sNMP_PDU_GET) ||
1624 ( action == sNMP_PDU_GET_ASYNC) ||
1625 ( action == sNMP_PDU_GETNEXT) ||
1626 ( action == sNMP_PDU_GETNEXT_ASYNC) ||
1627 ( action == sNMP_PDU_GETBULK) ||
1628 ( action == sNMP_PDU_GETBULK_ASYNC) ||
1629 ( action == sNMP_PDU_INFORM) ||
1630 ( action == sNMP_PDU_INFORM_ASYNC) ||
1631 ( action == sNMP_PDU_RESPONSE))
1632 community_string = my_get_community;
1633 else /* got to be a set */
1634 community_string = my_set_community;
1636 else if (utarget) /* Is is a UTarget? */
1638 debugprintf(3, "snmp_engine called with UTarget");
1639 if (!utarget->resolve_to_U( security_name, security_model,
1640 address, my_timeout,
1643 debugprintf(0, "-- SNMP++, Resolve Fail (UTarget)");
1644 return SNMP_CLASS_UNSUPPORTED;
1647 if (version != version3)
1650 community_string = security_name;
1651 if (((version == version1) && (security_model != SNMP_SECURITY_MODEL_V1)) ||
1652 ((version == version2c) && (security_model != SNMP_SECURITY_MODEL_V2)))
1654 LOG_BEGIN(ERROR_LOG | 1);
1655 LOG("Snmp: Target does not match SNMP version: (security model) (version)");
1656 LOG(security_model);
1660 return SNMP_CLASS_INVALID_TARGET;
1663 } // end if (version != version3)
1667 { // target is neither CTarget nor UTarget (should not happen)
1668 debugprintf(0, "-- SNMP++, Resolve Fail");
1669 return SNMP_CLASS_INVALID_TARGET;
1672 if (!address.valid())
1674 debugprintf(0, "-- SNMP++, Target contains invalid address");
1675 return SNMP_CLASS_INVALID_TARGET;
1678 //----------[ validate the target address ]--------------------------
1679 if ((address.get_type() != Address::type_ip) &&
1680 (address.get_type() != Address::type_udp) )
1682 debugprintf(0, "-- SNMP++, Bad address type");
1683 return SNMP_CLASS_TL_UNSUPPORTED;
1686 UdpAddress udp_address(address);
1687 if (!udp_address.valid())
1689 debugprintf(0, "-- SNMP++, Bad address");
1690 return SNMP_CLASS_RESOURCE_UNAVAIL;
1693 //----------[ choose the target address port ]-----------------------
1694 if ((address.get_type() == Address::type_ip) || !udp_address.get_port())
1696 if (pdu_action == sNMP_PDU_INFORM)
1697 udp_address.set_port(SNMP_TRAP_PORT);
1699 udp_address.set_port(SNMP_PORT);
1701 // otherwise port was already set
1703 // check socket to use
1704 SnmpSocket iv_session_used = fd;
1706 if (fd == INVALID_SOCKET)
1709 if (udp_address.get_ip_version() == Address::version_ipv4)
1711 if (iv_snmp_session != INVALID_SOCKET)
1712 iv_session_used = iv_snmp_session;
1715 udp_address.map_to_ipv6();
1716 iv_session_used = iv_snmp_session_ipv6;
1720 iv_session_used = iv_snmp_session_ipv6;
1722 iv_session_used = iv_snmp_session;
1726 if ((pdu_action != sNMP_PDU_RESPONSE) &&
1727 (pdu_action != sNMP_PDU_REPORT))
1729 // set error index to none
1730 pdu.set_error_index(0);
1732 // determine request id to use
1733 req_id = MyMakeReqId();
1734 pdu.set_request_id(req_id);
1737 //---------[ map GetBulk over v1 to GetNext ]-------------------------
1738 if (( pdu_action == sNMP_PDU_GETBULK)&&( (snmp_version)version== version1))
1739 pdu_action = sNMP_PDU_GETNEXT;
1740 if ( pdu_action == sNMP_PDU_GETBULK) {
1741 pdu.set_error_status((int) non_reps);
1742 pdu.set_error_index((int) max_reps);
1745 pdu.set_type( pdu_action);
1746 SnmpMessage snmpmsg;
1749 struct V3CallBackData *v3CallBackData = 0;
1751 if (version == version3)
1755 debugprintf(0, "-- SNMP++, need UTarget to send SNMPv3 message!");
1756 return SNMP_CLASS_INVALID_TARGET;
1759 utarget->get_engine_id(engine_id);
1760 if (engine_id.len() == 0)
1762 if (v3MP::I->get_from_engine_id_table(engine_id,
1763 (char*)udp_address.get_printable())
1766 // Override const here
1767 ((UTarget*)utarget)->set_engine_id(engine_id);
1771 // check if engine id discovery is enabled
1772 if ((!v3MP::I->get_usm()->is_discovery_enabled()) &&
1773 ((pdu_action == sNMP_PDU_GET) ||
1774 (pdu_action == sNMP_PDU_SET) ||
1775 (pdu_action == sNMP_PDU_GETNEXT) ||
1776 (pdu_action == sNMP_PDU_GETBULK) ||
1777 (pdu_action == sNMP_PDU_INFORM)))
1779 // no engine id, discovery disabled and not authoritytive
1780 LOG_BEGIN(ERROR_LOG | 1);
1781 LOG("Not authoritative and discovery disabled. Target without engine id is invalid");
1783 return SNMP_CLASS_INVALID_TARGET;
1787 // set context_engine_id of pdu, if it is not set
1788 if (pdu.get_context_engine_id().len() == 0)
1790 debugprintf(8, "Setting contextEngineID of Pdu to (%s)",
1791 engine_id.get_printable());
1792 pdu.set_context_engine_id(engine_id);
1793 backupPdu.set_context_engine_id(engine_id);
1796 debugprintf(4,"Snmp::snmp_engine: engineID (%s), securityName (%s)"
1797 "securityModel (%i) security_level (%i)",
1798 engine_id.get_printable(), security_name.get_printable(),
1799 security_model, pdu.get_security_level());
1800 debugprintf(4," Addr/Port (%s)",udp_address.get_printable());
1802 status = snmpmsg.loadv3( pdu, engine_id, security_name,
1803 security_model, (snmp_version)version);
1807 status = snmpmsg.load( pdu, community_string,(snmp_version) version);
1809 if ( status != SNMP_CLASS_SUCCESS)
1811 debugprintf(0, "snmp message load error!");
1815 // first add the message to the queue
1816 if ((pdu_action != sNMP_PDU_RESPONSE) &&
1817 (pdu_action != sNMP_PDU_REPORT))
1820 if ((version == version3) && ((action == sNMP_PDU_GET_ASYNC) ||
1821 (action == sNMP_PDU_SET_ASYNC) ||
1822 (action == sNMP_PDU_GETNEXT_ASYNC) ||
1823 (action == sNMP_PDU_GETBULK_ASYNC) ||
1824 (action == sNMP_PDU_INFORM_ASYNC))) {
1825 // add callback for v3
1826 v3CallBackData = new struct V3CallBackData;
1828 v3CallBackData->pdu = new Pdu(pdu);
1829 v3CallBackData->pdu->set_type(backupPdu.get_type());
1830 v3CallBackData->non_reps = non_reps;
1831 v3CallBackData->max_reps = max_reps;
1833 v3CallBackData->target = new UTarget(*utarget);
1834 v3CallBackData->oldCallback = cb;
1835 v3CallBackData->cbd = cbd;
1836 v3CallBackData->reports_received = reports_received;
1838 // Add the message to the message queue
1839 eventListHolder->snmpEventList()->AddEntry(req_id, this, iv_session_used,
1840 target, pdu, snmpmsg.data(), (size_t) snmpmsg.len(),
1841 udp_address, v3CallBack, (void *)v3CallBackData);
1846 eventListHolder->snmpEventList()->AddEntry(req_id, this, iv_session_used,
1847 target, pdu, snmpmsg.data(), (size_t) snmpmsg.len(),
1848 udp_address, cb, (void *)cbd);
1852 //------[ send the request ]
1854 status = send_snmp_request(iv_session_used,
1855 snmpmsg.data(), (size_t) snmpmsg.len(),
1861 if ((pdu_action != sNMP_PDU_RESPONSE) &&
1862 (pdu_action != sNMP_PDU_REPORT))
1864 // remove the id from message queue
1865 eventListHolder->snmpEventList()->lock();
1866 eventListHolder->snmpEventList()->DeleteEntry(req_id);
1867 eventListHolder->snmpEventList()->unlock();
1870 // dont forget to delete this
1871 if (v3CallBackData) deleteV3Callback(v3CallBackData);
1874 return SNMP_CLASS_TL_FAILED;
1877 if ((pdu_action == sNMP_PDU_RESPONSE) ||
1878 (pdu_action == sNMP_PDU_REPORT))
1879 return SNMP_CLASS_SUCCESS; // don't wait for an answer
1881 //----[ if an async mode request then return success ]-----
1882 if (( action == sNMP_PDU_GET_ASYNC) ||
1883 ( action == sNMP_PDU_SET_ASYNC) ||
1884 ( action == sNMP_PDU_GETNEXT_ASYNC) ||
1885 ( action == sNMP_PDU_GETBULK_ASYNC) ||
1886 ( action == sNMP_PDU_INFORM_ASYNC))
1887 return SNMP_CLASS_SUCCESS;
1889 // Now wait for the response (or timeout) for our message.
1890 // This handles any necessary retries.
1891 status = eventListHolder->SNMPBlockForResponse(req_id, pdu);
1893 if (pdu.get_type() != REPORT_MSG) {
1895 if (status == SNMPv3_MP_OK)
1896 return SNMP_CLASS_SUCCESS;
1903 if (status == SNMPv3_USM_DECRYPTION_ERROR)
1906 // We received a REPORT-MSG, check if we should try another time
1909 pdu.get_vb(first_vb,0);
1910 first_vb.get_oid(first_oid);
1912 debugprintf(1,"received oid: %s with value: %s",
1913 first_vb.get_printable_oid(), first_vb.get_printable_value());
1914 debugprintf(1, "%s", error_msg(first_oid));
1920 // This was our first try, so we may receive a unknown engine id
1921 // report or a not in time window report
1922 if (first_oid == oidUsmStatsUnknownEngineIDs)
1924 pdu = backupPdu; // restore pdu and try again
1927 else if (first_oid == oidUsmStatsNotInTimeWindows)
1929 ++maxloops; // increase it, as the next request must succeed
1930 pdu = backupPdu; // restore pdu and try again
1933 return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
1937 // This was the second try, engine id discovery should be ok
1938 // so test only for not in time report
1939 if (first_oid == oidUsmStatsNotInTimeWindows)
1941 pdu = backupPdu; // restore pdu and try again
1944 return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
1948 // We tried three times: one for engine id discovery, one for
1949 // time sync and we still get a report --> somethings wrong!
1950 return (status == SNMPv3_MP_OK) ? SNMP_CLASS_SUCCESS : status;
1959 int Snmp::engine_id_discovery(OctetStr &engine_id,
1960 const int timeout_sec,
1961 const UdpAddress &addr)
1963 unsigned char *message;
1966 SnmpMessage snmpmsg;
1968 unsigned char snmpv3_message[60] = {
1970 0x02, 0x01, 0x03, // Version: 3
1971 0x30, 0x0f, // global header length 15
1972 0x02, 0x03, 0x01, 0x00, 0x00, // message id
1973 0x02, 0x02, 0x10, 0x00, // message max size
1974 0x04, 0x01, 0x04, // flags (reportable set)
1975 0x02, 0x01, 0x03, // security model USM
1976 0x04, 0x10, // security params
1978 0x04, 0x00, // no engine id
1979 0x02, 0x01, 0x00, // boots 0
1980 0x02, 0x01, 0x00, // time 0
1981 0x04, 0x00, // no user name
1982 0x04, 0x00, // no auth par
1983 0x04, 0x00, // no priv par
1985 0x04, 0x00, // no context engine id
1986 0x04, 0x00, // no context name
1987 0xa0, 0x0c, // GET PDU
1988 0x02, 0x02, 0x34, 0x26, // request id
1989 0x02, 0x01, 0x00, // error status no error
1990 0x02, 0x01, 0x00, // error index 0
1991 0x30, 0x00 // no data
1994 message = (unsigned char *)snmpv3_message;
1995 message_length = 60;
1999 UdpAddress uaddr(addr);
2002 if (uaddr.get_ip_version() == Address::version_ipv4)
2004 if (iv_snmp_session != INVALID_SOCKET)
2005 sock = iv_snmp_session;
2008 uaddr.map_to_ipv6();
2009 sock = iv_snmp_session_ipv6;
2013 sock = iv_snmp_session_ipv6;
2015 sock = iv_snmp_session;
2019 if (send_snmp_request(sock, message, message_length, uaddr) < 0)
2021 debugprintf(0, "Error sending message.");
2023 return SNMP_CLASS_TL_FAILED;
2026 // now wait for the responses
2030 struct timeval fd_timeout;
2032 end_time += timeout_sec * 1000;
2034 #ifdef HAVE_POLL_SYSCALL
2035 struct pollfd readfds;
2043 bool something_to_receive = false;
2044 end_time.GetDeltaFromNow(fd_timeout);
2046 #ifdef HAVE_POLL_SYSCALL
2047 memset(&readfds, 0, sizeof(struct pollfd));
2049 readfds.events = POLLIN;
2050 timeout = fd_timeout.tv_sec * 1000 + fd_timeout.tv_usec / 1000;
2051 nfound = poll(&readfds, 1, timeout);
2052 if ((nfound > 0) && (readfds.revents & POLLIN))
2053 something_to_receive = true;
2056 FD_SET(sock, &readfds);
2058 nfound = select((int)(sock + 1), &readfds, NULL, NULL, &fd_timeout);
2059 if ((nfound > 0) && (FD_ISSET(sock, &readfds)))
2060 something_to_receive = true;
2063 if (something_to_receive)
2067 int res = receive_snmp_response(sock, *this, dummy_pdu,
2068 from, engine_id, true /* process_msg */);
2069 if ((res == SNMP_CLASS_SUCCESS) ||
2070 (res == SNMPv3_MP_UNKNOWN_PDU_HANDLERS))
2072 //dummy_pdu.get_context_engine_id(engine_id);
2073 debugprintf(3, "Response received from (%s) id %s.",
2074 from.get_printable(), engine_id.get_printable());
2076 return SNMP_CLASS_SUCCESS;
2080 debugprintf(0, "Error receiving discovery response.");
2083 } while ((nfound > 0) ||
2084 (fd_timeout.tv_sec > 0) || (fd_timeout.tv_usec > 0));
2087 return SNMP_CLASS_TIMEOUT;
2091 // Send a SNMP Broadcast message.
2092 int Snmp::broadcast_discovery(UdpAddressCollection &addresses,
2093 const int timeout_sec,
2094 const UdpAddress &addr,
2095 const snmp_version version,
2096 const OctetStr *community)
2098 unsigned char *message;
2101 SnmpMessage snmpmsg;
2104 unsigned char snmpv3_broadcast_message[60] = {
2106 0x02, 0x01, 0x03, // Version: 3
2107 0x30, 0x0f, // global header length 15
2108 0x02, 0x03, 0x01, 0x00, 0x00, // message id
2109 0x02, 0x02, 0x10, 0x00, // message max size
2110 0x04, 0x01, 0x04, // flags (reportable set)
2111 0x02, 0x01, 0x03, // security model USM
2112 0x04, 0x10, // security params
2114 0x04, 0x00, // no engine id
2115 0x02, 0x01, 0x00, // boots 0
2116 0x02, 0x01, 0x00, // time 0
2117 0x04, 0x00, // no user name
2118 0x04, 0x00, // no auth par
2119 0x04, 0x00, // no priv par
2121 0x04, 0x00, // no context engine id
2122 0x04, 0x00, // no context name
2123 0xa0, 0x0c, // GET PDU
2124 0x02, 0x02, 0x34, 0x26, // request id
2125 0x02, 0x01, 0x00, // error status no error
2126 0x02, 0x01, 0x00, // error index 0
2127 0x30, 0x00 // no data
2130 if (version == version3)
2132 message = (unsigned char *)snmpv3_broadcast_message;
2133 message_length = 60;
2140 OctetStr get_community;
2142 vb.set_oid("1.3.6.1.2.1.1.1.0");
2144 pdu.set_error_index(0); // set error index to none
2145 pdu.set_request_id(MyMakeReqId()); // determine request id to use
2146 pdu.set_type(sNMP_PDU_GET); // set pdu type
2149 get_community = *community;
2151 get_community = "public";
2153 int status = snmpmsg.load(pdu, get_community, version);
2154 if (status != SNMP_CLASS_SUCCESS)
2156 debugprintf(0, "Error encoding broadcast pdu (%i).", status);
2159 message = snmpmsg.data();
2160 message_length = snmpmsg.len();
2163 UdpAddress uaddr(addr);
2166 if (uaddr.get_ip_version() == Address::version_ipv4)
2168 if (iv_snmp_session != INVALID_SOCKET)
2169 sock = iv_snmp_session;
2172 uaddr.map_to_ipv6();
2173 sock = iv_snmp_session_ipv6;
2177 sock = iv_snmp_session_ipv6;
2179 sock = iv_snmp_session;
2183 if (send_snmp_request(sock, message, message_length, uaddr) < 0)
2185 debugprintf(0, "Error sending broadast.");
2187 return SNMP_CLASS_TL_FAILED;
2190 // now wait for the responses
2195 struct timeval fd_timeout;
2197 end_time += timeout_sec * 1000;
2199 #ifdef HAVE_POLL_SYSCALL
2200 struct pollfd readfds;
2208 bool something_to_receive = false;
2209 end_time.GetDeltaFromNow(fd_timeout);
2211 #ifdef HAVE_POLL_SYSCALL
2212 memset(&readfds, 0, sizeof(struct pollfd));
2214 readfds.events = POLLIN;
2215 timeout = fd_timeout.tv_sec * 1000 + fd_timeout.tv_usec / 1000;
2216 nfound = poll(&readfds, 1, timeout);
2217 if ((nfound > 0) && (readfds.revents & POLLIN))
2218 something_to_receive = true;
2221 FD_SET(sock, &readfds);
2223 nfound = select((int)(sock + 1), &readfds, NULL, NULL, &fd_timeout);
2224 if ((nfound > 0) && (FD_ISSET(sock, &readfds)))
2225 something_to_receive = true;
2228 if (something_to_receive)
2232 if (receive_snmp_response(sock, *this, dummy_pdu,
2233 from, engine_id, false /* process_msg */)
2234 == SNMP_CLASS_SUCCESS)
2240 debugprintf(0, "Error receiving broadcast response.");
2243 } while ((nfound > 0) ||
2244 (fd_timeout.tv_sec > 0) || (fd_timeout.tv_usec > 0));
2248 for (int i=0; i < addresses.size(); ++i)
2250 debugprintf(3, "Broadcast response received from (%s).",
2251 addresses[i].get_printable());
2257 // Starts the working thread for the recovery of the pending events
2258 bool Snmp::start_poll_thread(const int timeout)
2261 // store the timeout value for later
2262 m_iPollTimeOut = timeout;
2264 // if we are already running return ok
2265 if (m_bThreadRunning == true) return true;
2267 // since we are here, things must be fine so far...
2268 m_bThreadRunning = true;
2270 // start the ProcessThread function....
2273 m_hThread = CreateThread(NULL, 0,
2274 (LPTHREAD_START_ROUTINE)&Snmp::process_thread,
2276 if (m_hThread == NULL)
2278 debugprintf(0, "Could not create ProcessThread");
2279 m_bThreadRunning = false;
2281 #elif defined (CPU) && CPU == PPC603
2282 m_hThread = taskSpawn("Snmp::process_thread", 0, 0, 10000, (int (*)(...))Snmp::process_thread, (int)this, 0, 0, 0, 0, 0, 0, 0, 0, 0);
2283 if (m_hThread == ERROR)
2285 // Could not create thread.
2286 debugprintf(0, "Could not create ProcessThread");
2287 m_bThreadRunning = false;
2290 int rc = pthread_create(&m_hThread, NULL, Snmp::process_thread,
2294 // Could not create thread.
2295 debugprintf(0, "Could not create ProcessThread");
2296 m_bThreadRunning = false;
2300 return m_bThreadRunning;
2303 ///////////////////////////////////////////////////////////////////////////////
2305 // Stops the recovery of the pending events
2307 ///////////////////////////////////////////////////////////////////////////////
2308 void Snmp::stop_poll_thread()
2310 if (m_bThreadRunning == false) return;
2314 m_bThreadRunning = false;
2316 // Wait for the working thread to stop....
2318 ::WaitForSingleObject(m_hThreadEndEvent, INFINITE);
2319 CloseHandle(m_hThread);
2320 #elif defined (CPU) && CPU == PPC603
2321 while (taskIdVerify(m_hThread) == OK)
2324 //int *status; // not used
2325 pthread_join(m_hThread, NULL /*(void**) &status */);
2331 int Snmp::process_thread(Snmp *pSnmp)
2334 void* Snmp::process_thread(void *arg)
2336 Snmp* pSnmp = (Snmp*) arg;
2339 // Loop as long as we haven't stopped
2340 while (pSnmp->is_running())
2342 pSnmp->eventListHolder
2343 ->SNMPProcessEvents(pSnmp->m_iPollTimeOut);
2348 ::SetEvent(pSnmp->m_hThreadEndEvent);
2350 #if defined (CPU) && CPU == PPC603
2360 #ifdef SNMP_PP_NAMESPACE
2361 }; // end of namespace Snmp_pp