--- Net-SNMP-XS/XS.pm 2009/04/08 10:39:32 1.2 +++ Net-SNMP-XS/XS.pm 2014/10/23 15:58:16 1.14 @@ -15,25 +15,27 @@ It does this by overriding a few selected internal method by (almost) equivalent XS methods. -This currently reduces decode time by some 70%. +This currently reduces decode time by a factor of ten for typical bulk +responses. There are currently the following limitations when using this module: =over 4 -=item leading dots are required for iods +=item overriding internal functions might cause the module to +malfunction with future versions of Net::SNMP -=item error handling is currently broken (but parse errors will be detected) - -=item oid components are limited to unsigned 32 bit integers +=item error messages will be simpler/different =item translation will be ignored (all values will be delivered "raw") -=item a 64 bit perl is required - =item a moderately modern (>= C99) C compiler is required -=item only tested with 5.10 +=item only tested with 5.10, no intentions to port to older perls + +=item duplicate OIDs are not supported + +=item REPORT PDUs are not supported =back @@ -46,83 +48,95 @@ use Guard; +use Net::SNMP (); use Net::SNMP::PDU (); use Net::SNMP::Message (); use Net::SNMP::MessageProcessing (); our $VERSION; -our $old_prepare; BEGIN { - $VERSION = '0.01'; - - $old_prepare = \&Net::SNMP::MessageProcessing::prepare_data_elements; + $VERSION = 1.31; - # this overrides many methods inside + # this overrides many methods inside Net::SNMP and it's submodules require XSLoader; XSLoader::load Net::SNMP::XS, $VERSION; } -sub Net::SNMP::MessageProcessing::prepare_data_elements { - my ($self, $msg) = @_; +package Net::SNMP::Message; - set_msg $msg, $msg->{_buffer}; - scope_guard \&clr_msg; - &$old_prepare -} +Net::SNMP::XS::set_type INTEGER , \&_process_integer32; +Net::SNMP::XS::set_type OCTET_STRING , \&_process_octet_string; +Net::SNMP::XS::set_type NULL , \&_process_null; +Net::SNMP::XS::set_type OBJECT_IDENTIFIER, \&_process_object_identifier; +Net::SNMP::XS::set_type SEQUENCE , \&_process_sequence; +Net::SNMP::XS::set_type IPADDRESS , \&_process_ipaddress; +Net::SNMP::XS::set_type COUNTER , \&_process_counter; +Net::SNMP::XS::set_type GAUGE , \&_process_gauge; +Net::SNMP::XS::set_type TIMETICKS , \&_process_timeticks; +Net::SNMP::XS::set_type OPAQUE , \&_process_opaque; +Net::SNMP::XS::set_type COUNTER64 , \&_process_counter64; +Net::SNMP::XS::set_type NOSUCHOBJECT , \&_process_nosuchobject; +Net::SNMP::XS::set_type NOSUCHINSTANCE , \&_process_nosuchinstance; +Net::SNMP::XS::set_type ENDOFMIBVIEW , \&_process_endofmibview; +Net::SNMP::XS::set_type GET_REQUEST , \&_process_get_request; +Net::SNMP::XS::set_type GET_NEXT_REQUEST , \&_process_get_next_request; +Net::SNMP::XS::set_type GET_RESPONSE , \&_process_get_response; +Net::SNMP::XS::set_type SET_REQUEST , \&_process_set_request; +Net::SNMP::XS::set_type TRAP , \&_process_trap; +Net::SNMP::XS::set_type GET_BULK_REQUEST , \&_process_get_bulk_request; +Net::SNMP::XS::set_type INFORM_REQUEST , \&_process_inform_request; +Net::SNMP::XS::set_type SNMPV2_TRAP , \&_process_v2_trap; +Net::SNMP::XS::set_type REPORT , \&_process_report; + +package Net::SNMP::PDU; -# almost direct copy from Net::SNMP::Message, as we cannot access $process_methods +# var_bind_list hardcodes oid_lex_sort. *sigh* +# we copy it 1:1, except for using oid_lex_sort. + +sub var_bind_list { - package Net::SNMP::Message; + my ($this, $vbl, $types) = @_; - my @process_methods; + return if defined($this->{_error}); + + if (@_ > 1) { + # The VarBindList HASH is being updated from an external + # source. We need to update the VarBind names ARRAY to + # correspond to the new keys of the HASH. If the updated + # information is valid, we will use lexicographical ordering + # for the ARRAY entries since we do not have a PDU to use + # to determine the ordering. The ASN.1 types HASH is also + # updated here if a cooresponding HASH is passed. We double + # check the mapping by populating the hash with the keys of + # the VarBindList HASH. + + if (!defined($vbl) || (ref($vbl) ne 'HASH')) { + + $this->{_var_bind_list} = undef; + $this->{_var_bind_names} = []; + $this->{_var_bind_types} = undef; - $process_methods [INTEGER ] = \&_process_integer32; - $process_methods [OCTET_STRING ] = \&_process_octet_string; - $process_methods [NULL ] = \&_process_null; - $process_methods [OBJECT_IDENTIFIER] = \&_process_object_identifier; - $process_methods [SEQUENCE ] = \&_process_sequence; - $process_methods [IPADDRESS ] = \&_process_ipaddress; - $process_methods [COUNTER ] = \&_process_counter; - $process_methods [GAUGE ] = \&_process_gauge; - $process_methods [TIMETICKS ] = \&_process_timeticks; - $process_methods [OPAQUE ] = \&_process_opaque; - $process_methods [COUNTER64 ] = \&_process_counter64; - $process_methods [NOSUCHOBJECT ] = \&_process_nosuchobject; - $process_methods [NOSUCHINSTANCE ] = \&_process_nosuchinstance; - $process_methods [ENDOFMIBVIEW ] = \&_process_endofmibview; - $process_methods [GET_REQUEST ] = \&_process_get_request; - $process_methods [GET_NEXT_REQUEST ] = \&_process_get_next_request; - $process_methods [GET_RESPONSE ] = \&_process_get_response; - $process_methods [SET_REQUEST ] = \&_process_set_request; - $process_methods [TRAP ] = \&_process_trap; - $process_methods [GET_BULK_REQUEST ] = \&_process_get_bulk_request; - $process_methods [INFORM_REQUEST ] = \&_process_inform_request; - $process_methods [SNMPV2_TRAP ] = \&_process_v2_trap; - $process_methods [REPORT ] = \&_process_report; - - # should be done in XS - sub process - { -# my ($this, $expected, $found) = @_; - - return $_[0]->_error if defined($_[0]->{_error}); - return $_[0]->_error unless defined(my $type = _buffer_get($_[0], 1)); - - $type = unpack 'C', $type; - - if ($process_methods[$type]) { - if (@_ >= 2 && (defined $_[1]) && $type != $_[1]) { - return $_[0]->_error( - 'Expected %s, but found %s', asn1_itoa($_[1]), asn1_itoa($type) - ); - } - $_[2] = $type if (@_ == 3); - $process_methods[$type]->($_[0], $type); } else { - $_[0]->_error('Unknown ASN.1 type [0x%02x]', $type); + + $this->{_var_bind_list} = $vbl; + + @{$this->{_var_bind_names}} = Net::SNMP::oid_lex_sort keys %$vbl; + + if (!defined($types) || (ref($types) ne 'HASH')) { + $types = {}; + } + + map { + $this->{_var_bind_types}->{$_} = + exists($types->{$_}) ? $types->{$_} : undef; + } keys(%{$vbl}); + } + } + + $this->{_var_bind_list}; } 1;