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 _##########################################################################*/
33 #include "snmp_pp/reentrant.h"
34 #include "snmp_pp/target.h"
35 #include "snmp_pp/oid.h"
36 #include "snmp_pp/address.h"
38 #ifdef SNMP_PP_NAMESPACE
42 #define SNMP_PP_WITH_UDPADDR // Snmp class has constructor with UdpAddress
44 //-----[ internally used defines ]----------------------------------------
45 #define MAXNAME 80 // maximum name length
46 #define MAX_ADDR_LEN 10 // maximum address len, ipx is 4+6
47 #define SNMP_SHUTDOWN_MSG 0x0400+177 // shut down msg for stoping a blocked message
48 #ifndef INVALID_SOCKET
49 #define INVALID_SOCKET ((SnmpSocket)(~0)) // value for invalid socket
52 //-----[ async defines for engine ]---------------------------------------
53 #define sNMP_PDU_GET_ASYNC 21
54 #define sNMP_PDU_GETNEXT_ASYNC 22
55 #define sNMP_PDU_SET_ASYNC 23
56 #define sNMP_PDU_GETBULK_ASYNC 24
57 #define sNMP_PDU_INFORM_ASYNC 25
59 //-----[ trap / notify macros ]-------------------------------------------
60 #define IP_NOTIFY 162 // IP notification
61 #define IPX_NOTIFY 0x2121 // IPX notification
63 //------[ forward declaration of Snmp class ]-----------------------------
65 class EventListHolder;
69 //-----------[ async methods callback ]-----------------------------------
71 * Async methods of the class Snmp require the caller to provide a
72 * callback address of a function with this typedef.
74 * @note It is not allowed to call any synchronous Snmp methods within the
75 * callback. Async methods are allowed.
77 * @param reason - Reason for callback (see snmperrs.h)
78 * @param session - Pointer to Snmp object that was used to send the request
79 * @param pdu - The received Pdu if reason indicates a received message
80 * @param target - source target
81 * @param data - Pointer passed to the async method
83 typedef void (*snmp_callback)(int reason, Snmp *session,
84 Pdu &pdu, SnmpTarget &target, void *data);
87 //------------[ SNMP Class Def ]---------------------------------------------
90 * SNMP class defintion. The Snmp class provides an object oriented
91 * approach to SNMP. The SNMP class is an encapsulation of SNMP
92 * sessions, gets, sets and get nexts. The class manages all SNMP
93 * resources and provides complete retry and timeout capability.
95 * This class is thread save.
97 * @note If you use the async methods to send requests you MUST call
98 * Snmp::eventListHolder->SNMPProcessPendingEvents() while waiting
99 * for the responses. This function triggers the resend of
100 * packets and calls your callback function if the response is
103 * @note Call srand() before creating the first Snmp object.
105 class DLLOPT Snmp: public SnmpSynchronized
108 //------------------[ constructors ]----------------------------------
110 /** @name Constructors and Destructor */
114 * Construct a new SNMP session using the given UDP port.
117 * after creation of the session this parameter will
118 * hold the creation status.
120 * an UDP port to be used for the session
122 * Set this to true if IPv6 should be used. The default is
125 Snmp(int &status, const unsigned short port = 0,
126 const bool bind_ipv6 = false);
129 * Construct a new SNMP session using the given UDP address.
130 * Thus, binds the session on a specific IPv4 or IPv6 address.
133 * after creation of the session this parameter will
134 * hold the creation status.
136 * an UDP address to be used for the session
138 Snmp(int &status, const UdpAddress &addr);
141 * Construct a new SNMP session using the given UDP addresses.
142 * Using this constructor will bind to both IPv4 and IPv6 ports.
145 * after creation of the session this parameter will
146 * hold the creation status.
148 * an IPv4 UDP address to be used for the session
150 * an IPv6 UDP address to be used for the session
152 Snmp(int &status, const UdpAddress& addr_v4, const UdpAddress& addr_v6);
154 //-------------------[ destructor ]------------------------------------
162 //--------[ Get the version of the snmp++ library ]--------------------
164 * Get the version of the snmp++ library.
166 * @return The version of the snmp++ lib at runtime.
168 static const char *get_version();
171 //-------------------[ returns error string ]--------------------------
173 * Returns a human readable error string.
175 * @param c - Error code returned by any method of this class
176 * @return Null terminated error string.
178 static const char *error_msg(const int c);
181 * Returns a human readable error string.
182 * If a report message is returned, then the contained Oid can be
183 * used to get a error string.
185 * @param v3Oid - Oid of a SNMPv3 report Pdu
186 * @return Null terminated error string.
188 static const char* error_msg(const Oid& v3Oid);
191 //------------------------[ Windows Sockets ]----------------------------
194 * Initialize the Winsock library (WSAStartup).
196 * @note on Win32 this method *must* be called before creating Snmp or
199 static void socket_startup();
203 * Shut down the Winsock library (WSACleanup).
205 static void socket_cleanup();
207 //------------------------[ send requests ]------------------------------
209 /** @name Sending SNMP Pdus
214 * Send a blocking SNMP-GET request.
216 * @param pdu - Pdu to send
217 * @param target - Target for the get
219 * @return SNMP_CLASS_SUCCES or a negative error code
221 virtual int get(Pdu &pdu, const SnmpTarget &target);
224 * Send a async SNMP-GET request.
226 * @param pdu - Pdu to send
227 * @param target - Target for the get
228 * @param callback - User callback function to use
229 * @param callback_data - User definable data pointer
231 * @return SNMP_CLASS_SUCCES or a negative error code
233 virtual int get(Pdu &pdu, const SnmpTarget &target,
234 const snmp_callback callback,
235 const void *callback_data = 0);
238 * Send a blocking SNMP-GETNEXT request.
240 * @param pdu - Pdu to send
241 * @param target - Target for the getnext
243 * @return SNMP_CLASS_SUCCES or a negative error code
245 virtual int get_next(Pdu &pdu, const SnmpTarget &target);
248 * Send a async SNMP-GETNEXT request.
250 * @param pdu - Pdu to send
251 * @param target - Target for the getnext
252 * @param callback - User callback function to use
253 * @param callback_data - User definable data pointer
255 * @return SNMP_CLASS_SUCCES or a negative error code
257 virtual int get_next(Pdu &pdu, const SnmpTarget &target,
258 const snmp_callback callback,
259 const void *callback_data = 0);
262 * Send a blocking SNMP-SET request.
264 * @param pdu - Pdu to send
265 * @param target - Target for the set
267 * @return SNMP_CLASS_SUCCES or a negative error code
269 virtual int set(Pdu &pdu, const SnmpTarget &target);
272 * Send a async SNMP-SET request.
274 * @param pdu - Pdu to send
275 * @param target - Target for the set
276 * @param callback - User callback function to use
277 * @param callback_data - User definable data pointer
279 * @return SNMP_CLASS_SUCCES or a negative error code
281 virtual int set(Pdu &pdu, const SnmpTarget &target,
282 const snmp_callback callback,
283 const void * callback_data = 0);
286 * Send a blocking SNMP-GETBULK request.
288 * @param pdu - Pdu to send
289 * @param target - Target for the getbulk
290 * @param non_repeaters - number of non repeaters
291 * @param max_reps - maximum number of repetitions
293 * @return SNMP_CLASS_SUCCES or a negative error code
295 virtual int get_bulk(Pdu &pdu, const SnmpTarget &target,
296 const int non_repeaters, const int max_reps);
299 * Send a async SNMP-GETBULK request.
301 * @param pdu - Pdu to send
302 * @param target - Target for the getbulk
303 * @param non_repeaters - number of non repeaters
304 * @param max_reps - maximum number of repetitions
305 * @param callback - User callback function to use
306 * @param callback_data - User definable data pointer
308 * @return SNMP_CLASS_SUCCES or a negative error code
310 virtual int get_bulk(Pdu &pdu, const SnmpTarget &target,
311 const int non_repeaters, const int max_reps,
312 const snmp_callback callback,
313 const void *callback_data = 0);
318 * @param pdu - Pdu to send
319 * @param target - Target for the trap
321 * @return SNMP_CLASS_SUCCES or a negative error code
323 virtual int trap(Pdu &pdu, const SnmpTarget &target);
327 * Send a SNMPv3-REPORT.
329 * @param pdu - Pdu to send
330 * @param target - Target for the report (must be a UTarget)
332 * @return SNMP_CLASS_SUCCES or a negative error code
334 virtual int report(Pdu &pdu, const SnmpTarget &target);
337 * Send a blocking INFORM-REQ.
339 * @param pdu - Pdu to send
340 * @param target - Target for the inform
342 * @return SNMP_CLASS_SUCCES or a negative error code
344 virtual int inform(Pdu &pdu, const SnmpTarget &target);
347 * Send a async INFORM-REQ.
349 * @param pdu - Pdu to send
350 * @param target - Target for the inform
351 * @param callback - User callback function to use
352 * @param callback_data - User definable data pointer
354 * @return SNMP_CLASS_SUCCES or a negative error code
356 virtual int inform(Pdu &pdu, const SnmpTarget &target,
357 const snmp_callback callback,
358 const void * callback_data = 0);
363 * @param pdu - Pdu to send
364 * @param target - Target for the response
365 * @param fd - file descriptor to use, should be the one
366 * that was passed to the callback function
368 * @return SNMP_CLASS_SUCCES or a negative error code
370 virtual int response(Pdu &pdu, const SnmpTarget &target,
371 const SnmpSocket fd = INVALID_SOCKET);
375 * Send a SNMP Broadcast message.
377 * This member function sends out a valid SNMP message to a
378 * broadcast address and waits for responses. The source addresses
379 * of the response messages are added to the collection.
381 * The message is sent only once.
383 * @note SNMP_BROADCAST has to be defined in config_snmp_pp.h.
385 * @note There is no SNMP standard that defines "SNMP Broadcast
386 * discovery". SNMP agents are not forced to answer requests
387 * that are sent to a broadcast address.
389 * @note Do not use this method while waiting for other responses,
390 * as these responses will be added to the collection and dropped
391 * by this method. Solution for this problem: Use a special
392 * Snmp object only for broadcasts.
394 * @param addresses - The addresses of the agents, that answered.
395 * @param timeout_sec - Timeout in seconds
396 * @param addr - Broadcast address
397 * @param version - SNMP version to use
398 * @param community - Only needed for SNMPv1/v2c, defaults to "public"
401 virtual int broadcast_discovery(UdpAddressCollection &addresses,
402 const int timeout_sec,
403 const UdpAddress &addr,
404 const snmp_version version,
405 const OctetStr *community = 0);
408 virtual int engine_id_discovery(OctetStr &engine_id,
409 const int timeout_sec,
410 const UdpAddress &addr);
415 * Cancel a pending request.
417 * @param rid - The request id to cancel
419 * @return SNMP_CLASS_SUCCES or SNMP_CLASS_INVALID_REQID on failure
421 virtual int cancel(const unsigned long rid);
424 /** @name Trap and Inform handling
429 * Set the port for listening to traps and informs.
431 * @note This function must be called before notify_register(),
432 * otherwise the default port is used.
434 virtual void notify_set_listen_port(const int port);
437 * Get the port that is used for listening to traps and informs.
439 virtual int notify_get_listen_port();
442 * Register to get traps and informs.
444 * @note Every call to one of the notify_register() methods overwrites
445 * the previous given values.
447 * @param trapids - ids to listen for
448 * @param targets - targets to listen for
449 * @param callback - User callback function to use
450 * @param callback_data - User definable data pointer
452 * @return SNMP_CLASS_SUCCESS, SNMP_CLASS_TL_FAILED or SNMP_CLASS_TL_IN_USE
454 virtual int notify_register(const OidCollection &trapids,
455 const TargetCollection &targets,
456 const snmp_callback callback,
457 const void *callback_data=0);
460 * Unregister to get traps and informs.
461 * Undo the call to notify_register().
463 * @return Always SNMP_CLASS_SUCCESS
465 virtual int notify_unregister();
468 * Get notify register info.
470 * @param trapids - ids listened for
471 * @param targets - targets listened for
473 * @return SNMP_CLASS_SUCCESS or SNMP_CLASS_INVALID if not registered
475 virtual int get_notify_filter(OidCollection &trapids,
476 TargetCollection &targets);
478 //-----------------------[ access the trap reception info ]---------------
480 * Get a pointer to the callback function used for trap reception.
482 * @return Pointer to the function set through notify_register()
484 snmp_callback get_notify_callback() { return notifycallback; };
487 * Get a pointer to the data that is passed to the callback function.
489 * @return Pointer to the data set through notify_register()
491 void *get_notify_callback_data() { return notifycallback_data; };
497 * This method may be used to send any data to the recepient.
499 * @param send_buf - Data buffer
500 * @param send_len - Length of the data
501 * @param address - Recepient
502 * @param fd - socket to use, if not specified, the socket of the
505 * @return 0 on success, -1 on failure
507 virtual int send_raw_data(unsigned char *send_buf,
508 size_t send_len, UdpAddress &address,
509 SnmpSocket fd = INVALID_SOCKET);
511 const IpAddress &get_listen_address() const {return listen_address; };
514 * Start one thread listening for responses and notifications.
515 * This method is used to start response and notification processing in a
516 * multi threadded setup.
518 * @note start_poll_thread() itself is not thread safe. The caller must make
519 * sure that only one thread is calling start_poll_thread() or
520 * stop_poll_thread() at any point in time.
522 * @param timeout - Timeout for each call of the select() or poll()
525 * @return true if the thread is now running and false if it failed to start.
527 bool start_poll_thread(const int timeout);
530 * Stop the thread listening for responses and notifications.
531 * This method is used to stop the thread started with start_poll_thread().
533 * @note stop_poll_thread() itself is not thread safe. The caller must make
534 * sure that only one thread is calling start_poll_thread() or
535 * stop_poll_thread() at any point in time.
537 void stop_poll_thread();
539 EventListHolder *get_eventListHolder() { return eventListHolder; };
544 * Check for the status of the worker thread.
545 * @return BOOL - TRUE - if running, FALSE - otherwise
547 bool is_running(void) const
548 { return m_bThreadRunning; };
551 * This is a working thread for the recovery of the pending events.
553 * @param pSnmp [in] pointer to the whole object
557 * 1 - in the case of error
560 static int process_thread(Snmp *pSnmp);
562 static void* process_thread(void *arg);
568 * Generate a unique (for this Snmp obect) request id.
570 * @return Unique id between PDU_MIN_RID and PDU_MAX_RID
575 * Common init function used by constructors.
577 void init(int& status, IpAddress*[2],
578 const unsigned short port_v4, const unsigned short port_v6);
581 * Set the notify timestamp of a trap pdu if the user did not set it.
583 void check_notify_timestamp(Pdu &pdu);
585 //-----------[ Snmp Engine ]----------------------------------------
587 * gets, sets and get nexts go through here....
588 * This mf does all snmp sending and reception
589 * except for traps which are sent using trap().
591 * @note that for a UTarget with an empty engine id the
592 * Utarget::set_engine_id() may be called.
594 int snmp_engine( Pdu &pdu, // pdu to use
595 long int non_reps, // get bulk only
596 long int max_reps, // get bulk only
597 const SnmpTarget &target, // destination target
598 const snmp_callback cb, // async callback function
599 const void *cbd, // callback data
600 SnmpSocket fd = INVALID_SOCKET,
601 int reports_received = 0);
603 //--------[ map action ]------------------------------------------------
604 // map the snmp++ action to a SMI pdu type
605 void map_action(unsigned short action, unsigned short &pdu_action);
609 * Internal used callback data structure for async v3 requests.
611 struct V3CallBackData
613 Pdu *pdu; ///< The Pdu that was sent
614 long int non_reps; ///< For GET-BULK requests
615 long int max_reps; ///< For GET-BULK requests
616 SnmpTarget *target; ///< Pointer to the Target object to use
617 snmp_callback oldCallback; ///< User callback function
618 const void *cbd; ///< User callback data
619 int reports_received; ///< How many reports are already received
622 friend void v3CallBack(int reason, Snmp *snmp, Pdu &pdu,
623 SnmpTarget &target, void *v3cd);
624 friend void deleteV3Callback(struct Snmp::V3CallBackData *&cbData);
627 //---[ instance variables ]
628 SnmpSocket iv_snmp_session;
630 SnmpSocket iv_snmp_session_ipv6;
633 IpAddress listen_address;
634 long current_rid; // current rid to use
636 // inform receive member variables
637 snmp_callback notifycallback;
638 void * notifycallback_data;
640 // this member var will simulate a global var
641 EventListHolder *eventListHolder;
645 bool m_bThreadRunning;
648 // Keep track of the thread.
652 HANDLE m_hThreadEndEvent;
653 #elif defined (CPU) && CPU == PPC603
661 #ifdef SNMP_PP_NAMESPACE
662 } // end of namespace Snmp_pp