| package NetSNMP::agent; |
| |
| use strict; |
| use warnings; |
| use Carp; |
| |
| require Exporter; |
| require DynaLoader; |
| use AutoLoader; |
| |
| use NetSNMP::default_store (':all'); |
| use NetSNMP::agent::default_store (':all'); |
| use NetSNMP::OID (':all'); |
| use NetSNMP::agent::netsnmp_request_infoPtr; |
| |
| use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK @EXPORT $VERSION $AUTOLOAD); |
| |
| @ISA = qw(Exporter AutoLoader DynaLoader); |
| |
| # Items to export into callers namespace by default. Note: do not export |
| # names by default without a very good reason. Use EXPORT_OK instead. |
| # Do not simply export all your public functions/methods/constants. |
| |
| # This allows declaration use NetSNMP::agent ':all'; |
| # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK |
| # will save memory. |
| %EXPORT_TAGS = ( 'all' => [ qw( |
| MODE_GET |
| MODE_GETBULK |
| MODE_GETNEXT |
| MODE_SET_ACTION |
| MODE_SET_BEGIN |
| MODE_SET_COMMIT |
| MODE_SET_FREE |
| MODE_SET_RESERVE1 |
| MODE_SET_RESERVE2 |
| MODE_SET_UNDO |
| SNMP_ERR_NOERROR |
| SNMP_ERR_TOOBIG |
| SNMP_ERR_NOSUCHNAME |
| SNMP_ERR_BADVALUE |
| SNMP_ERR_READONLY |
| SNMP_ERR_GENERR |
| SNMP_ERR_NOACCESS |
| SNMP_ERR_WRONGTYPE |
| SNMP_ERR_WRONGLENGTH |
| SNMP_ERR_WRONGENCODING |
| SNMP_ERR_WRONGVALUE |
| SNMP_ERR_NOCREATION |
| SNMP_ERR_INCONSISTENTVALUE |
| SNMP_ERR_RESOURCEUNAVAILABLE |
| SNMP_ERR_COMMITFAILED |
| SNMP_ERR_UNDOFAILED |
| SNMP_ERR_AUTHORIZATIONERROR |
| SNMP_ERR_NOTWRITABLE |
| ) ] ); |
| |
| @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
| |
| @EXPORT = qw( |
| MODE_GET |
| MODE_GETBULK |
| MODE_GETNEXT |
| MODE_SET_ACTION |
| MODE_SET_BEGIN |
| MODE_SET_COMMIT |
| MODE_SET_FREE |
| MODE_SET_RESERVE1 |
| MODE_SET_RESERVE2 |
| MODE_SET_UNDO |
| SNMP_ERR_NOERROR |
| SNMP_ERR_TOOBIG |
| SNMP_ERR_NOSUCHNAME |
| SNMP_ERR_BADVALUE |
| SNMP_ERR_READONLY |
| SNMP_ERR_GENERR |
| SNMP_ERR_NOACCESS |
| SNMP_ERR_WRONGTYPE |
| SNMP_ERR_WRONGLENGTH |
| SNMP_ERR_WRONGENCODING |
| SNMP_ERR_WRONGVALUE |
| SNMP_ERR_NOCREATION |
| SNMP_ERR_INCONSISTENTVALUE |
| SNMP_ERR_RESOURCEUNAVAILABLE |
| SNMP_ERR_COMMITFAILED |
| SNMP_ERR_UNDOFAILED |
| SNMP_ERR_AUTHORIZATIONERROR |
| SNMP_ERR_NOTWRITABLE |
| ); |
| $VERSION = '5.0703'; |
| |
| sub AUTOLOAD { |
| # This AUTOLOAD is used to 'autoload' constants from the constant() |
| # XS function. If a constant is not found then control is passed |
| # to the AUTOLOAD in AutoLoader. |
| |
| my $constname; |
| ($constname = $AUTOLOAD) =~ s/.*:://; |
| croak "& not defined" if $constname eq 'constant'; |
| my $val; |
| ($!, $val) = constant($constname); |
| if ($! != 0) { |
| if ($! =~ /Invalid/ || $!{EINVAL}) { |
| $AutoLoader::AUTOLOAD = $AUTOLOAD; |
| goto &AutoLoader::AUTOLOAD; |
| } |
| else { |
| croak "Your vendor has not defined NetSNMP::agent macro $constname"; |
| } |
| } |
| { |
| no strict 'refs'; |
| # Fixed between 5.005_53 and 5.005_61 |
| # if ($] >= 5.00561) { |
| # *$AUTOLOAD = sub () { $val }; |
| # } |
| # else { |
| *$AUTOLOAD = sub { $val }; |
| # } |
| } |
| goto &$AUTOLOAD; |
| } |
| |
| { |
| my $haveinit = 0; |
| |
| sub mark_init_agent_done { |
| $haveinit = 1; |
| } |
| |
| sub maybe_init_agent { |
| return if ($haveinit); |
| $haveinit = 1; |
| |
| my $flags = $_[0]; |
| if ($flags->{'AgentX'}) { |
| netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); |
| } |
| init_agent($flags->{'Name'} || "perl"); |
| if ($flags->{'Ports'}) { |
| netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS, $flags->{'Ports'}); |
| } |
| init_mib(); |
| } |
| } |
| |
| { |
| my $haveinit = 0; |
| |
| sub mark_init_lib_done { |
| $haveinit = 1; |
| } |
| |
| sub maybe_init_lib { |
| return if ($haveinit); |
| $haveinit = 1; |
| |
| my $flags = $_[0]; |
| init_snmp($flags->{'Name'} || "perl"); |
| if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) != 1) { |
| init_master_agent(); |
| } |
| } |
| } |
| |
| sub new { |
| my $type = shift; |
| my ($self); |
| %$self = @_; |
| bless($self, $type); |
| if ($self->{'dont_init_agent'}) { |
| $self->mark_init_agent_done(); |
| } else { |
| $self->maybe_init_agent(); |
| } |
| if ($self->{'dont_init_lib'}) { |
| $self->mark_init_lib_done(); |
| } |
| return $self; |
| } |
| |
| sub register($$$$) { |
| my ($self, $name, $oid, $sub) = @_; |
| my $reg = NetSNMP::agent::netsnmp_handler_registration::new($name, $oid, $sub); |
| $reg->register() if ($reg); |
| return $reg; |
| } |
| |
| sub main_loop { |
| my $self = shift; |
| while(1) { |
| $self->agent_check_and_process(1); |
| } |
| } |
| |
| sub agent_check_and_process { |
| my ($self, $blocking) = @_; |
| $self->maybe_init_lib(); |
| __agent_check_and_process($blocking || 0); |
| } |
| |
| sub uptime { |
| my $self = shift; |
| $self->maybe_init_lib(); |
| return _uptime(); |
| } |
| |
| bootstrap NetSNMP::agent $VERSION; |
| |
| # Preloaded methods go here. |
| |
| # Autoload methods go after =cut, and are processed by the autosplit program. |
| |
| 1; |
| __END__ |
| |
| =head1 NAME |
| |
| NetSNMP::agent - Perl extension for the net-snmp agent. |
| |
| =head1 SYNOPSIS |
| |
| use NetSNMP::agent; |
| |
| my $agent = new NetSNMP::agent('Name' => 'my_agent_name'); |
| |
| |
| =head1 DESCRIPTION |
| |
| This module implements an API set to make a SNMP agent act as a snmp |
| agent, a snmp subagent (using the AgentX subagent protocol) and/or |
| embedded perl-APIs directly within the traditional net-snmp agent demon. |
| |
| Also see the tutorial about the genaral Net-SNMP C API, which this |
| module implements in a perl-way, and a perl specific tutorial at: |
| |
| http://www.net-snmp.org/tutorial-5/toolkit/ |
| |
| =head1 EXAMPLES |
| |
| =head2 Sub-agent example |
| |
| use NetSNMP::agent (':all'); |
| use NetSNMP::ASN qw(ASN_OCTET_STR); |
| |
| my $value = "hello world"; |
| sub myhandler { |
| my ($handler, $registration_info, $request_info, $requests) = @_; |
| my $request; |
| |
| for($request = $requests; $request; $request = $request->next()) { |
| my $oid = $request->getOID(); |
| if ($request_info->getMode() == MODE_GET) { |
| # ... generally, you would calculate value from oid |
| if ($oid == new NetSNMP::OID(".1.3.6.1.4.1.8072.9999.9999.7375.1.0")) { |
| $request->setValue(ASN_OCTET_STR, $value); |
| } |
| } elsif ($request_info->getMode() == MODE_GETNEXT) { |
| # ... generally, you would calculate value from oid |
| if ($oid < new NetSNMP::OID(".1.3.6.1.4.1.8072.9999.9999.7375.1.0")) { |
| $request->setOID(".1.3.6.1.4.1.8072.9999.9999.7375.1.0"); |
| $request->setValue(ASN_OCTET_STR, $value); |
| } |
| } elsif ($request_info->getMode() == MODE_SET_RESERVE1) { |
| if ($oid != new NetSNMP::OID(".1.3.6.1.4.1.8072.9999.9999.7375.1.0")) { # do error checking here |
| $request->setError($request_info, SNMP_ERR_NOSUCHNAME); |
| } |
| } elsif ($request_info->getMode() == MODE_SET_ACTION) { |
| # ... (or use the value) |
| $value = $request->getValue(); |
| } |
| } |
| |
| } |
| |
| my $agent = new NetSNMP::agent( |
| # makes the agent read a my_agent_name.conf file |
| 'Name' => "my_agent_name", |
| 'AgentX' => 1 |
| ); |
| $agent->register("my_agent_name", ".1.3.6.1.4.1.8072.9999.9999.7375", |
| \&myhandler); |
| |
| my $running = 1; |
| while($running) { |
| $agent->agent_check_and_process(1); |
| } |
| |
| $agent->shutdown(); |
| |
| |
| =head2 Embedded agent example |
| |
| # place this in a .pl file, and then in your snmpd.conf file put: |
| # perl do '/path/to/file.pl'; |
| |
| use NetSNMP::agent; |
| my $agent; |
| |
| sub myhandler { |
| my ($handler, $registration_info, $request_info, $requests) = @_; |
| # ... |
| } |
| |
| $agent = new NetSNMP::agent( |
| 'Name' => 'my_agent_name' |
| ); |
| |
| $agent->register("my_agent_name", ".1.3.6.1.4.1.8072.9999.9999.7375", |
| \&myhandler); |
| |
| $agent->main_loop(); |
| |
| |
| =head1 CONSTRUCTOR |
| |
| new ( OPTIONS ) |
| This is the constructor for a new NetSNMP::agent object. |
| |
| Possible options are: |
| |
| Name - Name of the agent (optional, defaults to "perl") |
| (The snmp library will read a NAME.conf snmp |
| configuration file based on this argument.) |
| AgentX - Make us a sub-agent (0 = false, 1 = true) |
| (The Net-SNMP master agent must be running first) |
| Ports - Ports this agent will listen on (EG: "udp:161,tcp:161") |
| |
| Example: |
| |
| $agent = new NetSNMP::agent( |
| 'Name' => 'my_agent_name', |
| 'AgentX' => 1 |
| ); |
| |
| |
| =head1 METHODS |
| |
| register (NAME, OID, \&handler_routine ) |
| Registers the callback handler with given OID. |
| |
| $agent->register(); |
| |
| A return code of 0 indicates no error. |
| |
| agent_check_and_process ( BLOCKING ) |
| Run one iteration of the main loop. |
| |
| BLOCKING - Blocking or non-blocking call. 1 = true, 0 = false. |
| |
| $agent->agent_check_and_process(1); |
| |
| main_loop () |
| Runs the agent in a loop. Does not return. |
| |
| shutdown () |
| Nicely shuts down the agent or sub-agent. |
| |
| $agent->shutdown(); |
| |
| =head1 HANDLER CALLBACKS |
| |
| handler ( HANDLER, REGISTRATION_INFO, REQUEST_INFO, REQUESTS ) |
| |
| The handler is called with the following parameters: |
| |
| HANDLER - FIXME |
| REGISTRATION_INFO - what are the correct meanings of these? |
| REQUEST_INFO - |
| REQUESTS - |
| |
| Example handler: |
| |
| sub myhandler { |
| my ($handler, $reg_info, $request_info, $requests) = @_; |
| # ... |
| } |
| |
| The handler subroutine will be called when a SNMP request received by |
| the agent for anything below the registered OID. The handler is |
| passed 4 arguments: $handler, $registration_info, $request_info, |
| $requests. These match the arguments passed to the C version of the |
| same API. Note that they are not entirely complete objects but are |
| functional "enough" at this point in time. |
| |
| =head2 $request_info object functions |
| |
| getMode () |
| Returns the mode of the request. See the MODES section for |
| list of valid modes. |
| |
| $mode = $request->getMode(); |
| |
| =head2 $registration_info object functions |
| |
| getRootOID () |
| Returns a NetSNMP::OID object that describes the registration |
| point that the handler is getting called for (in case you |
| register one handler function with multiple OIDs, which should |
| be rare anyway) |
| |
| $root_oid = $request->getRootOID(); |
| |
| =head2 $request object functions |
| |
| next () |
| Returns the next request in the list or undef if there is no |
| next request. |
| |
| $request = $request->next(); |
| |
| getOID () |
| Returns the oid of the request (a NetSNMP::OID class). |
| |
| $oid = $request->getOID(); |
| |
| setOID (new NetSNMP::OID("someoid")) |
| Sets the OID of the request to a passed oid value. This |
| should generally only be done during handling of GETNEXT |
| requests. |
| |
| $request->setOID(new NetSNMP::OID("someoid")); |
| |
| getValue () |
| Returns the value of the request. Used for example when |
| setting values. |
| |
| $value = $request->getValue(); |
| |
| FIXME: how to get the type of the value? Is it even available? |
| [Wes: no, not yet.] |
| |
| setValue ( TYPE, DATA ) |
| Sets the data to be returned to the daemon. |
| |
| Returns 1 on success, 0 on error. |
| |
| TYPE - Type of the data. See NetSNMP::ASN for valid types. |
| DATA - The data to return. |
| |
| $ret = $request->setValue(ASN_OCTET_STR, "test"); |
| |
| setError ( REQUEST_INFO, ERROR_CODE ) |
| Sets the given error code for the request. See the ERROR CODES |
| section for list of valid codes. |
| |
| $request->setError($request_info, SNMP_ERR_NOTWRITABLE); |
| |
| getProcessed () |
| The processed flag indicates that a request does not need to |
| be dealt with because someone else (a higher handler) has |
| dealt with it already. |
| |
| $processed = $request->getProcessed(); |
| |
| setProcessed ( PROCESSED ) |
| Sets the processed flag flag in the request. You generally |
| should not have to set this yourself. |
| |
| PROCESSED - 0 = false, 1 = true |
| |
| $request->setProcessed(1); |
| |
| getDelegated () |
| If you can handle a request in the background or at a future |
| time (EG, you're waiting on a file handle, or network traffic, |
| or ...), the delegated flag can be set in the request. When |
| the request is processed in the future the flag should be set |
| back to 0 so the agent will know that it can wrap up the |
| original request and send it back to the manager. This has |
| not been tested within perl, but it hopefully should work. |
| |
| $delegated = $request->getDelegated(); |
| |
| setDelegated ( DELEGATED ) |
| Sets the delegated flag. |
| |
| DELEGATED - 0 = false, 1 = true |
| |
| $request->setDelegated(1); |
| |
| getRepeat () |
| The repeat flag indicates that a getbulk operation is being |
| handled and this indicates how many answers need to be |
| returned. Generally, if you didn't register to directly |
| handle getbulk support yourself, you won't need to deal with |
| this value. |
| |
| $repeat = $request->getRepeat(); |
| |
| setRepeat ( REPEAT ) |
| Sets the repeat count (decrement after answering requests if |
| you handle getbulk requests yourself) |
| |
| REPEAT - repeat count FIXME |
| |
| $request->setRepeat(5); |
| |
| getSourceIp () |
| |
| Gets the IPv4 address of the device making the request to the handler. |
| |
| use Socket; |
| print "Source: ", inet_ntoa($request->getSourceIp()), "\n"; |
| |
| getDestIp () |
| |
| Gets the IPv4 address of the destination that the request was sent to. |
| |
| use Socket; |
| print "Destination: ", inet_ntoa($request->getDestIp()), "\n"; |
| |
| =head1 MODES |
| |
| MODE_GET |
| MODE_GETBULK |
| MODE_GETNEXT |
| MODE_SET_ACTION |
| MODE_SET_BEGIN |
| MODE_SET_COMMIT |
| MODE_SET_FREE |
| MODE_SET_RESERVE1 |
| MODE_SET_RESERVE2 |
| MODE_SET_UNDO |
| |
| =head1 ERROR CODES |
| |
| SNMP_ERR_NOERROR |
| SNMP_ERR_TOOBIG |
| SNMP_ERR_NOSUCHNAME |
| SNMP_ERR_BADVALUE |
| SNMP_ERR_READONLY |
| SNMP_ERR_GENERR |
| SNMP_ERR_NOACCESS |
| SNMP_ERR_WRONGTYPE |
| SNMP_ERR_WRONGLENGTH |
| SNMP_ERR_WRONGENCODING |
| SNMP_ERR_WRONGVALUE |
| SNMP_ERR_NOCREATION |
| SNMP_ERR_INCONSISTENTVALUE |
| SNMP_ERR_RESOURCEUNAVAILABLE |
| SNMP_ERR_COMMITFAILED |
| SNMP_ERR_UNDOFAILED |
| SNMP_ERR_AUTHORIZATIONERROR |
| SNMP_ERR_NOTWRITABLE |
| |
| =head1 AUTHOR |
| |
| Please mail the net-snmp-users@lists.sourceforge.net mailing list for |
| help, questions or comments about this module. |
| |
| Module written by: |
| Wes Hardaker <hardaker@users.sourceforge.net> |
| |
| Documentation written by: |
| Toni Willberg <toniw@iki.fi> |
| Wes Hardaker <hardaker@users.sourceforge.net> |
| |
| =head1 SEE ALSO |
| |
| NetSNMP::OID(3), NetSNMP::ASN(3), perl(1). |
| |
| =cut |