The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Revision history for Perl extension POE::Component::SNMP.

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. <sigh>

	- 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. <sigh> 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. <evil grin>

	- 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

        - turned off $VERBOSE in Dispatcher.pm... even when debug
          messages weren't being shown, VERBOSE added some extra
          processing that was 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.