--- Net-SNMP-XS/XS.xs 2009/04/09 04:49:16 1.5 +++ Net-SNMP-XS/XS.xs 2009/04/09 05:56:36 1.6 @@ -17,7 +17,7 @@ #define ASN_OPAQUE 0x44 #define ASN_COUNTER64 0x46 -#define BENCHMARK +//#define BENCHMARK #define MAX_OID_STRLEN 4096 @@ -212,27 +212,27 @@ return buf; } -static SV * -process_object_identifier_sv (void) +static char * +process_object_identifier (int *len) { U32 length = process_length (); if (length <= 0) { error ("OBJECT IDENTIFIER length equal to zero"); - return &PL_sv_undef; + return ""; } U8 *end = cur + length; U32 w = getb (); - static char oid[MAX_OID_STRLEN]; + static char oid[MAX_OID_STRLEN]; // must be static char *app = oid; *app = '.'; app += ! ! leading_dot; - app = write_uv (app, w / 40); + app = write_uv (app, (U8)w / 40); *app++ = '.'; - app = write_uv (app, w % 40); + app = write_uv (app, (U8)w % 40); // we assume an oid component is never > 64 bytes while (cur < end && oid + sizeof (oid) - app > 64) @@ -241,21 +241,79 @@ *app++ = '.'; app = write_uv (app, w); } -#if 0 - buf += snprintf (buf, oid + sizeof (oid) - buf, "%d.%d", (int)w / 40, (int)w % 40); - while (cur < end) - { - w = getb (); - buf += snprintf (buf, oid + sizeof (oid) - buf, ".%u", (unsigned int)w); - } -#endif + *len = app - oid; + return oid; +} + +static SV * +process_object_identifier_sv (void) +{ + int len; + char *oid = process_object_identifier (&len); - return newSVpvn (oid, app - oid); + return newSVpvn (oid, len); } static AV *av_type; +static SV * +process_sv (int *found) +{ + int type = get8 (); + + *found = type; + + SV *res; + + switch (type) + { + case ASN_OBJECT_IDENTIFIER: + res = process_object_identifier_sv (); + break; + + case ASN_INTEGER32: + res = process_integer32_sv (); + break; + + case ASN_UNSIGNED32: + case ASN_COUNTER32: + case ASN_TIMETICKS: + res = process_unsigned32_sv (); + break; + + case ASN_SEQUENCE: + res = newSVuv (process_length ()); + break; + + case ASN_OCTET_STRING: + case ASN_OPAQUE: + res = process_octet_string_sv (); + break; + + default: + { + if (type > AvFILLp (av_type) || !SvTYPE (AvARRAY (av_type)[type]) == SVt_PVCV) + { + error ("Unknown ASN.1 type"); + return &PL_sv_undef; + } + + dSP; + PUSHMARK (SP); + EXTEND (SP, 2); + PUSHs (msg); + PUSHs (sv_2mortal (newSViv (type))); + PUTBACK; + int count = call_sv (AvARRAY (av_type)[type], G_SCALAR); + SPAGAIN; + res = count ? SvREFCNT_inc (TOPs) : &PL_sv_undef; + } + } + + return errflag ? &PL_sv_undef : res; +} + MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS PROTOTYPES: ENABLE @@ -389,73 +447,21 @@ RETVAL SV * -process (SV *self, SV *expected = 0, SV *found = 0) - PPCODE: +process (SV *self, SV *expected = &PL_sv_undef, SV *found = 0) + CODE: { - U8 type = get8 (); + int type; - if (expected && SvOK (expected) && type != SvIV (expected)) - { - error ("Expected a different type than found"); - XSRETURN_UNDEF; - } - - if (type > AvFILLp (av_type) || !SvTYPE (AvARRAY (av_type)[type]) == SVt_PVCV) - { - sv_dump (AvARRAY (av_type)[type]);//D - error ("Unknown ASN.1 type"); - XSRETURN_UNDEF; - } + RETVAL = process_sv (&type); if (found) sv_setiv (found, type); - //TODO: switch based on type, to avoid calling overhead - SV *res; - - switch (type) - { - case ASN_OBJECT_IDENTIFIER: - res = sv_2mortal (process_object_identifier_sv ()); - break; - - case ASN_INTEGER32: - res = sv_2mortal (process_integer32_sv ()); - break; - - case ASN_UNSIGNED32: - case ASN_COUNTER32: - case ASN_TIMETICKS: - res = sv_2mortal (process_unsigned32_sv ()); - break; - - case ASN_SEQUENCE: - res = sv_2mortal (newSVuv (process_length ())); - break; - - case ASN_OCTET_STRING: - case ASN_OPAQUE: - res = sv_2mortal (process_octet_string_sv ()); - break; - - default: - { - dSP; - PUSHMARK (SP); - EXTEND (SP, 2); - PUSHs (self); - PUSHs (expected); - PUTBACK; - int count = call_sv (AvARRAY (av_type)[type], G_SCALAR); - SPAGAIN; - res = count ? TOPs : &PL_sv_undef; - } - } - - XPUSHs (errflag ? &PL_sv_undef : res); + if (SvOK (expected) && type != SvIV (expected)) + error ("Expected a different type than found"); } - -#if 0 + OUTPUT: + RETVAL MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU @@ -463,67 +469,42 @@ _process_var_bind_list (SV *self) CODE: { - # VarBindList::=SEQUENCE - if (!defined($value = $this->process(SEQUENCE))) { - return $this->_error; - } - - # Using the length of the VarBindList SEQUENCE, - # calculate the end index. - - my $end = $this->index + $value; - - $this->{_var_bind_list} = {}; - $this->{_var_bind_names} = []; - $this->{_var_bind_types} = {}; + if (get8 () != ASN_SEQUENCE) + error ("SEQUENCE expected at beginning of VarBindList"); + int seqlen = process_length (); + U8 *end = cur + seqlen; + + HV *list = newHV (); + AV *names = newAV (); + HV *types = newHV (); + + hv_store ((HV *)SvRV (self), "_var_bind_list" , sizeof ("_var_bind_list" ) - 1, newRV_noinc ((SV *)list ), 0); + hv_store ((HV *)SvRV (self), "_var_bind_names", sizeof ("_var_bind_names") - 1, newRV_noinc ((SV *)names), 0); + hv_store ((HV *)SvRV (self), "_var_bind_types", sizeof ("_var_bind_types") - 1, newRV_noinc ((SV *)types), 0); - my ($oid, $type); - - while ($this->index < $end) { - - # VarBind::=SEQUENCE - if (!defined($this->process(SEQUENCE))) { - return $this->_error; - } - # name::=ObjectName - if (!defined($oid = $this->process(OBJECT_IDENTIFIER))) { - return $this->_error; - } - # value::=ObjectSyntax - if (!defined($value = $this->process(undef, $type))) { - return $this->_error; - } - - # Create a hash consisting of the OBJECT IDENTIFIER as a - # key and the ObjectSyntax as the value. If there is a - # duplicate OBJECT IDENTIFIER in the VarBindList, we pad - # that OBJECT IDENTIFIER with spaces to make a unique - # key in the hash. - - while (exists($this->{_var_bind_list}->{$oid})) { - $oid .= ' '; # Pad with spaces - } - - DEBUG_INFO('{ %s => %s: %s }', $oid, asn1_itoa($type), $value); - $this->{_var_bind_list}->{$oid} = $value; - $this->{_var_bind_types}->{$oid} = $type; - - # Create an array with the ObjectName OBJECT IDENTIFIERs - # so that the order in which the VarBinds where encoded - # in the PDU can be retrieved later. - - push(@{$this->{_var_bind_names}}, $oid); - - } - - # Return an error based on the contents of the VarBindList - # if we received a Report-PDU. + while (cur < end && !errflag) + { + // SEQUENCE ObjectName ObjectSyntax + if (get8 () != ASN_SEQUENCE) + error ("SEQUENCE expected at beginning of VarBind"); + process_length (); + + if (get8 () != ASN_OBJECT_IDENTIFIER) + error ("OBJECT IDENTIFIER expected at beginning of VarBind"); + int type, oidlen; + char *oid = process_object_identifier (&oidlen); + SV *val = process_sv (&type); + + hv_store (types, oid, oidlen, newSViv (type), 0); + hv_store (list , oid, oidlen, val, 0); + av_push (names, newSVpvn (oid, oidlen)); + } - return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT); + //return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT); - # Return the var_bind_list hash - $this->{_var_bind_list}; + RETVAL = newRV_inc ((SV *)list); } + OUTPUT: + RETVAL -#endif