Revision history for Perl extension POE::Component::SNMP. -*-text-*- 0.01 Mon Apr 21 13:28:31 2003 - original version; created by h2xs 1.22 with options -AX -n POE::Component::SNMP 0.90 Mon Jun 7 18:44:00 2004 - Module inherited by Rob Bloodgood, from the previous maintainer, Todd Caine. - added POE::Component::SNMP::Dispatcher module, to subclass Net::SNMP::Dispatcher such that all socket and scheduling operations were processed by POE's event loop. - updated the callback variables so that the hostname and session alias of the SNMP object queried are returned to the callback event. - made write tests optional during install, so that the module would install correctly even where a writeable host was unavailable. 0.92 Mon Sep 6 13:19:53 2004 - Updated to be compatible with new Net::SNMP release 5.0.0 0.93 Thu Aug 11 11:57:29 2005 - Updated POE session constructor from the deprecated new() to the new create() method. - Removed a bunch of commented, deprecated code that was still a holdover from the 0.01 0.94 Thu Mar 30 14:43:19 2006 - Reorganized the module distribution to use a lib/ dir, cuz MakeMaker was being dumb. - Updated Makefile.PL to remove the config file on 'make realclean' - Tweaked the docs. - Altered the sample script in the SYNOPSIS to actually work. - Removed remaining commented references to deprecated code. - Followed a suggestion from Curtis J. Coleman to re-order component shutdown so that finish() worked correctly. - Lots of minor cleanups in the text - At LAST: removed the duplicate methods to account for the difference between Net::SNMP 4.x and 5.x. Now this is achieved by aliasing the functions that need to be duplicated in the symbol table. 0.95 Sat Apr 8 14:46:54 PDT 2006 - Collapsed all the identical method calls into a dispatch mechanism around a single method call template. - VASTLY improved error handling. - Added the snmp method (eg get, set, walk) and request args to the request packet returned to callbacks. - Reorganized Dispatcher.pm, trimmed old commented code. Removed unneeded debugging statements. - trimmed unnecessary parameters from calls to __invoke_callback(). - added new tests for various aspects of error handling. 0.96 Mon Apr 10 01:29:40 PDT 2006 - re-ordered the hostname and community checks so that the fatal "hostname is required" is thrown BEFORE the warning "using default community". - added new tests for error conditions and parameter errors - changed the return values to always return something sane, e.g. a string or a ref, not a string or a ref or maybe an undef, THEN a string! The only reason I didn't change this before is that I mistakenly thought this weird error structure came directly from Net::SNMP, but it turns out I just inherited it. - for compatibility, continue to return the $snmp_object->error value in the second slot, since the last change alters the API. - Also, changed the original args returned to callbacks from being a listref to a simple list, in the same way they came in. - Unified style in docs. Cleaned up internal and external POD links. 0.97 Mon Apr 10 13:14:01 PDT 2006 - Fixed some formatting tweaks in the docs. - Renamed the function snmp_last_error_message to snmp_errmsg, to correspond the the component request 'errmsg', like the other method names. - DANG! Left in some debugging references to YAML and Spiffy that I meant to comment out. Which breaks systems that don't have those modules installed. Grr. Fixed. - Also pulled references to YAML from the sample script... not everybody has YAML. 0.98 Wed Apr 12 20:02:12 PDT 2006 - Improved dispatcher tracing by making all calls consistently trace their execution. Use Net::SNMP debug functions to report our activities when the debug flag to trace the Dispatcher is set in the constructor. Gives nice, consistent trace output. - Started work to remove the requirement that each host have a different -localport parameter. I chased it down. The fundemental question is, how is it possible for Net::SNMP to reuse the same socket for every remote host, without parsing the internals of the packet and matching them to a "replies expected" table? The answer is, it is not. Net::SNMP dispatches all queries in the order received, serially. The workaround we used is correct. Note to self: NOW STOP WONDERING IF THIS IS POSSIBLE! - Accidentally optimized the whole module by a factor of at least 3x by copying Net::SNMP::Dispatcher's send_pdu() into PoCo::SNMP::Dispatcher. See notes on send_pdu(). - Changed __schedule_event so that events with no delay simply invoke their callback args instead of post()ing to __invoke_callback. This saves me a POE state call. - Updated _send_pdu to return TRUE, just like the Net::SNMP version does. 0.99 - Changed send_pdu() optimization. Instead of being a copy of the N:S:D's, we simply change the function reference involved, with local(), before invoking SUPER::send_pdu(). - Changed __send_next_pdu and __pdu_sent around... the 2nd half of __send_next_pdu belonged logically in __pdu_sent. This saves me a POE state call and is cleaner. - Renamed __send_next_pdu to __dispatch_pdu. - Discovered that select_read() can take additional args to pass back to the event triggered when a handle goes live. Duuhh. What this means is, I no longer have to dig into Net::SNMP to find out where they stashed the callback, indexed by the fileno of the socket. Instead I can simply pass and invoke the supplied callback. This changed register(), __listen, and __socket_callback. - Discovered that extra args support for select_read() wasn't added until 0.32. Coded it back, only this time without mucking around with private attributes of my parent class. - Tweaked whitespace so stuff looks consistent. - Copied the sanity check from Net::SNMP that loads and verifies the dispatcher instance. Now P:C:S:Dispatcher doesn't muck around with Net::SNMP's package space, just subclasses it. Instead, P:C:S loads the Dispatcher in a BEGIN block, just like Net::SNMP. THEN it mucks with Net::SNMP's namespace. - Replaced references to $self in the constructor with $this, following Net::SNMP's convention and the rest of the module. - Removed alot of folds. I had folds around every function, now I just have them around major sections. - Started working on the edge case where somebody is dumb enough to call finish() while data is still pending. - Updated constructor to accept all forms of -alias, alias, Alias, and the same for -hostname. - Removed the check for a valid varbindlist in the error handler of the snmp_request(). Just return the error. - Changed tracking of _current_pdu from a reference to the callback args to a simple flag. All it needs to do is *exist*. - Triple-checked that the reference changing done in send_pdu() was indeed persisting for subsequent invocations of _send_pdu(). - Adusted the debug output to have a more verbose mode available. - More work on the finish() cleanup... now we delete pending requests but allow the current request to complete. - Altered socket listen/unlisten operations to use select_pause_read() and select_resume_read(), because docs say they are more lightweight. Initial tests show reduction of approx. 20% in system loadavg with loadavg_multi_snmp. - moved the socket ops to two new private methods, _watch_handle() and _unwatch_handle(). These functions maintain the reference counting of who has what handle, without any of the rest of the module having to count any part of it. that's good. :) - had to adjust _unwatch_handle() to NOT stop listening when there are replies due, in __clean_pending - put the folds back in, not quite as many before tho. it's easier to go from block to block that way, and only have the functions unfolded that I'm working on. - moved tracking of current and pending requests from the session heap to the dispatcher object, so that the info can be retrieved in POE or non-POE space. - added the private method _pending_pdu_count(), based on the last change. - renamed __pdu_sent to __dispatch_pending_pdu - use _pending_pdu_count() check to skip invoking __dispatch_pending_pdu unless there is actually anything pending. this saves me a POE state call for most situations. - added accessors for current and pending pdus, instead of getting directly into the heap hash or object. - tried to change __clear_pending from an event to an object method, but it hangs when I do that. - way, way more tests. almost rewrote 40_set from scratch... now instead of just blindly setting something, it reads it, sets something else, verifies, then puts it back and verifies. Much more robust. - turns out that a better hook for subclassing than schedule() is _event_insert(). By using it instead, we get A) the same $event reference that cancel() receives, and B) a method name that does *not* change between 4.x and 5.x. The logic for cancel() stays the same. - commented references to schedule/_schedule in the compatibility section. - changed _event_insert() so that if the time to invoke the callback is immediate, it is invoked right then, *instead* of calling __schedule. This saves me another POE state call, woo-hoo! - created a global debug flag in the config file so that I can turn on and off debug output in *all* tests with one change. - followed to the suggestion of Curtis J. Coleman to add the ability to set arbitrary callback arguments to be returned to callback events along with ordinary response data. created tests for it. actually, I put in a couple of lines of code and then wrote the tests... and then actually put in the feature. :) tests are cool. - changed a coupla stray call()'s in the tests to posts(). - added tests and logic for localport conflicts... my previous code didn't work, and I ran into this error: "Failed to bind UDP/IPv4 socket: Address already in use at ~/bin/wackastat line 38", followed by "POE::Kernel's run() method was never called." - added an _arg_scan() to flexibly fetch values from a *list* of key/value pairs. - finally tracked down and eliminated the last stray reference that was holding our sessions open when we called 'finish' with requests still in the pipe!!!! It turns out the $MESSAGE_PROCESSING subsystem was holding a cached copy of our request, including its callback. - put an error check in __dispatch_pending_pdu based on an error report from Curtis Coleman 1.00 Mon Apr 24 15:55:23 PDT 2006 - release 1.01 Mon Apr 24 17:41:08 PDT 2006 - already got an error report from Curtis Coleman.. __socket_callback ended up seeing an empty callback. Fix by deferring unless there is a current callback. 1.02 Tue Apr 25 11:38:00 PDT 2006 - CPAN automated testing indicates not being able to correctly locate TestPCS.pm. Turns out I forgot to put it into the MANIFEST, so it wasn't bundled in the distribution! - Turns out my tests were anticipating the wealth of results available from the Net-SNMP daemon, which is not delivered from, for example, an Alcatel DSLAM. With the invaluable assistance of Curtis Coleman again, as well as a few others in #PoE, got the tests straightened out. Thanks guys! 1.03 Fri Jun 2 18:51:19 PDT 2006 - small doc tweaks - micro-optimized _pending_pdu_count by skipping exists() and just using ref(). - added a check to __schedule_event to execute immediately if for some strange reason the time of execution has already arrived and yet we're still invoking __schedule. - fixed a logic error in the -localport initializer that was preventing retries if the random port chosen was already in use. Thanks to Curtis Coleman for the spot. 1.04 Tue Jun 6 14:35:30 PDT 2006 - my fix was broken. fixed for real this time. thanks to Curtis AGAIN! 1.05 Fri Jun 16 13:00:40 PDT 2006 - turned off $VERBOSE in Dispatcher.pm... even when debug messages weren't being shown, VERBOSE adds some extra processing that is unnecessary (unless, of course, you're developing PoCo::SNMP :). - my assumptions about having a singleton dispatcher session fell apart when a user tried to run the POE kernel more than once... after the first run, the session is destroyed, causing subsequent runs to fail. added destructor logic to the dispatcher's _stop event, and constructor logic to the main component's create() method. Now it functions properly if run more than once. Thanks to Nigel Bowden for the spot. 1.06 Tue Sep 12 00:43:42 PDT 2006 - finish() behavior was broken... calling finish() for one session finished (well, broke) the entire component, PERMANENTLY. oops. removed all references to the internal "_abort" flag. now the caveat is, if you finish() using POE::Kernel->call() in the same event that you've made requests, the program will hang because there will be stray events. use post(), or yield() instead. Thanks to Kenny Flegal for the spot *and* the test case. - cleaned up the -localport logic a little bit... added a do..while() where I had a while() plus the same line of code twice. - added a 'trap2c' method a version or two ago... but forgot to add it to the states list in the constructor for the PoCo::SNMP session. This meant that anybody trying to use it would silently fail. oops. same for 'callback_args'. oops twice. - did a little bit of refactoring in Dispatcher.pm to make identifiers "tell the story" a little better, cuz on a re-read of the logic it wasn't "instantly clear" what I'd been trying to do. __dispatch_pdu and __dispatch_pending_pdu read more clearly now. - made my debugging functions a little better at no-op'ing when not debugging, resulting in a small improvement in "make test" times. 1.07 Wed Sep 27 16:30:17 PDT 2006 - added 71_multi_autherror.t to test SNMP v2c authentication errors. Net::SNMP returns 'no response'. - changed the call to POE::Kernel->post() to yield() in deregister(), saving the overhead of resolving the session since it is always called within the Dispatcher session. - also changed register() and schedule() in the Dispatcher to use POE::Kernel->call() instead of post(), because they doesn't hurt concurrency there, all they do is select_read() or alarm_set() then return. - removed an extraneous localport() accessor from SNMP.pm. - re-enabled the "duplicate session" check in the constructor because POE now correctly allows the check under ASSERT_DEFAULT. - Finally added folds to SNMP.pm. - Minor changes to the documentation. - Removed an unused variable from __clear_pending(). 1.10 Fri Jul 25 01:39:08 PDT 2008 - Added a Test::Pod pod.t to increase module Kwalitee. *NOT* adding Test::Pod::Coverage stuff because my "coverage" isn't in functions, but in states. Plus, Dispatcher doesn't have or need docs. So there. - altered/renamed _get_next_pending_pdu(), returning a scalar to _get_next_pending_pdu_args, returning an array, to unify __dispatch_pdu and __dispatch_pending_pdu - merged the __dispatch_pending_pdu event completely into __dispatch_pdu, by making deregister fetch the pending args, since the only difference between them was where they got the args for the SUPER::_send_pdu() call. - added clarification to the docs WRT concurrency. - fixed a small bug in the error handling for callback_args. - POE_ASSERT_DATA still throws a fatal error when alias_resolve() fails (up until 0.95), so updated the check to match this "minimum" condition. - updated the docs to have sample usages of each of the request types. - tweaked the localport conflict detection slightly. Added a test for it. - Andrew Hoying sent in a patch adding the getentries method, along with POD *and* a test case... woo-hoo! He reports that switching some of his code from walk to getentries significantly cut down on the amount of packets sent over the network. - renamed (un)?watch_transport to (un)?watch_socket. It's closer to what I really mean, and I've started work on PoCo::SNMP::Session, which will have such a similar structure to this module that I want to unify the differences as far as possible. - attempted to alter socket watch/unwatch behavior to leave the socket "hot" in between requests. This saves 2 method calls and 2 kernel calls per request. However, it's not quite right, so it's currently disabled - fixed a bug where SNMPv3 requests that fail could let me wind up in __clear_pending without a valid socket to unwatch/clear. - fixed a bug where I checked _pending_pdu without passing a (mandatory) fileno parameter. Oops. - got the "hot" socket logic right. I kinda cheated... I just skipped right past pausing/resuming select_read on the sockets. - finally got the tests right. I hope. 1.1001 Fri Aug 1 01:58:09 PDT 2008 - nope, still didn't get it right. left a stray dependency. changed my version system because I seem to do this alot. now releasing version 1.1001. I'm hoping I don't have to release version 1.1002 tomorrow. :) 1.1002 Fri Dec 4 18:33:23 PST 2009 - Updated for Net::SNMP v6.0.0 - looking more closely at my fail reports, they have another problem: Net::SNMP uses a v-string, and it doesn't compare properly in the test suite. Tweaked Makefile.PL. - Applied cleanup patches from gcola aka acferen__yahoo.com to eliminate some harmless but annoying warnings. - Turns out that using POE::Kernel->method as a global access to the kernel is unsupported. Since I'm already importing POE::Kernel, I have $poe_kernel in my namespace already, so use that instead. 1.1003 - Cleanups 1.1004 Mon Dec 7 13:17:15 PST 2009 - more cleanups 1.1005 Mon Dec 7 13:30:08 PST 2009 - Apparently my 'eval { use Sub::Identify }' is causing hiccups with smoke testing. Rewritten to 'eval { require Sub::Identify }' 1.1006 Sun Jan 10 20:17:10 PST 2010 - well I'm now blushing because I finally found a bug that was reported to me but I was previously unable to reproduce. The author of Net::SNMP has released v6.0.0, which doesn't compare very well to a "regular" number like 5.0. This broke my 4.x support. So I have removed it.