Guest User

Net::SNMP::XS XS.xs file

a guest
Nov 1st, 2012
156
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.70 KB | None | 0 0
  1. #include "EXTERN.h"
  2. #include "perl.h"
  3. #include "XSUB.h"
  4.  
  5. // C99 required
  6.  
  7. //#define BENCHMARK
  8.  
  9. #define ASN_BOOLEAN           0x01
  10. #define ASN_INTEGER32         0x02
  11. #define ASN_OCTET_STRING      0x04
  12. #define ASN_NULL              0x05
  13. #define ASN_OBJECT_IDENTIFIER 0x06
  14. #define ASN_SEQUENCE          0x30
  15. #define ASN_IPADDRESS         0x40
  16. #define ASN_COUNTER32         0x41
  17. #define ASN_UNSIGNED32        0x42
  18. #define ASN_TIMETICKS         0x43
  19. #define ASN_OPAQUE            0x44
  20. #define ASN_COUNTER64         0x46
  21.  
  22. #define MAX_OID_STRLEN 4096
  23.  
  24. #define HAVE_VERSIONSORT defined (_GNU_SOURCE) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
  25.  
  26. static SV *cur_bufobj;
  27. static SV *msg, *bufsv;
  28. static int errflag, leading_dot;
  29. static U8 *buf, *cur;
  30. static STRLEN len, rem;
  31.  
  32. typedef SV *BUFOBJ;
  33.  
  34. /////////////////////////////////////////////////////////////////////////////
  35.  
  36. #if 0
  37.         if (msg)
  38.           croak ("recursive invocation of Net::SNMP::XS parser is not supported");
  39.  
  40.  
  41. void
  42. clr_msg ()
  43.     CODE:
  44.         SvREFCNT_dec (msg); msg = 0;
  45.         buf = cur = (U8 *)"";
  46.         len = rem = 0;
  47. #endif
  48.  
  49. static void
  50. clear_bufobj (void)
  51. {
  52.   // serialise our state back
  53.   if (msg && SvROK (msg))
  54.     {
  55.       SV *idx_sv = *hv_fetch ((HV *)cur_bufobj, "_index" , sizeof ("_index" ) - 1, 1);
  56.       sv_setiv (idx_sv, cur - buf);
  57.  
  58.       SvREFCNT_dec (msg);
  59.       msg        = 0;
  60.       cur_bufobj = 0;
  61.     }
  62. }
  63.  
  64. static void
  65. switch_bufobj (BUFOBJ neu)
  66. {
  67.   clear_bufobj ();
  68.  
  69.   msg = newSVsv (neu);
  70.   cur_bufobj = SvRV (msg);
  71.   sv_rvweaken (msg);
  72.  
  73.   errflag     = 0;
  74.   leading_dot = -1;
  75.  
  76.   IV index = SvIV (*hv_fetch ((HV *)cur_bufobj, "_index" , sizeof ("_index" ) - 1, 1));
  77.   bufsv    =       *hv_fetch ((HV *)cur_bufobj, "_buffer", sizeof ("_buffer") - 1, 1);
  78.  
  79.   buf = SvPVbyte (bufsv, len);
  80.   cur = buf + index;
  81.   rem = len - index;
  82. }
  83.  
  84. /////////////////////////////////////////////////////////////////////////////
  85.  
  86. static SV *
  87. x_get_cv (SV *cb_sv)
  88. {
  89.   HV *st;
  90.   GV *gvp;
  91.   CV *cv = sv_2cv (cb_sv, &st, &gvp, 0);
  92.  
  93.   if (!cv)
  94.     croak ("CODE reference expected");
  95.  
  96.   return (SV *)cv;
  97. }
  98.  
  99. static void
  100. error (const char *errmsg)
  101. {
  102.   errflag = 1;
  103.  
  104.   if (!msg)
  105.     croak ("Net::SNMP::XS fatal error, parser called without parsing context");
  106.  
  107.   dSP;
  108.   PUSHMARK (SP);
  109.   EXTEND (SP, 2);
  110.   PUSHs (msg);
  111.   PUSHs (sv_2mortal (newSVpv (errmsg, 0)));
  112.   PUTBACK;
  113.   call_method ("_error", G_VOID | G_DISCARD);
  114. }
  115.  
  116. static int
  117. need (int count)
  118. {
  119.   if (count < 0 || (int)rem < count)
  120.     {
  121.       error ("Unexpected end of message buffer");
  122.       return 0;
  123.     }
  124.  
  125.   return 1;
  126. }
  127.  
  128. static U8 *
  129. getn (int count, const U8 *errres)
  130. {
  131.   if (!need (count))
  132.     return (U8 *)errres;
  133.  
  134.   U8 *res = cur;
  135.  
  136.   cur += count;
  137.   rem -= count;
  138.  
  139.   return res;
  140. }
  141.  
  142. static U8
  143. get8 (void)
  144. {
  145.   if (rem <= 0)
  146.     {
  147.       error ("Unexpected end of message buffer");
  148.       return 0;
  149.     }
  150.  
  151.   rem--;
  152.   return *cur++;
  153. }
  154.  
  155. static U32
  156. getb (void)
  157. {
  158.   U32 res = 0;
  159.  
  160.   for (;;)
  161.     {
  162.       U8 c = get8 ();
  163.       res = (res << 7) | (c & 0x7f);
  164.  
  165.       if (!(c & 0x80))
  166.         return res;
  167.     }
  168. }
  169.  
  170. #ifdef BENCHMARK
  171. static double t1;
  172.  
  173. static double
  174. tstamp (void)
  175. {
  176.   struct timeval tv;
  177.   gettimeofday (&tv, 0);
  178.   return tv.tv_sec + tv.tv_usec * 0.000001;
  179. }
  180. #endif
  181.  
  182. static U32
  183. process_length (void)
  184. {
  185.   U32 res = get8 ();
  186.  
  187.   if (res & 0x80)
  188.     {
  189.       int cnt = res & 0x7f;
  190.       res = 0;
  191.  
  192.       switch (cnt)
  193.         {
  194.           case 0:
  195.             error ("Indefinite ASN.1 lengths not supported");
  196.             return 0;
  197.  
  198.           default:
  199.             error ("ASN.1 length too long");
  200.             return 0;
  201.  
  202.           case 4: res = (res << 8) | get8 ();
  203.           case 3: res = (res << 8) | get8 ();
  204.           case 2: res = (res << 8) | get8 ();
  205.           case 1: res = (res << 8) | get8 ();
  206.         }
  207.     }
  208.  
  209.   return res;
  210. }
  211.  
  212. static U32
  213. process_integer32 (void)
  214. {
  215.   U32 length = process_length ();
  216.  
  217.   if (length <= 0)
  218.     {
  219.       error ("INTEGER32 length equal to zero");
  220.       return 0;
  221.     }
  222.  
  223.   U8 *data = getn (length, 0);
  224.  
  225.   if (!data)
  226.     return 0;
  227.  
  228.   if (length > 5 || (length > 4 && data [0]))
  229.     {
  230.       error ("INTEGER32 length too long");
  231.       return 0;
  232.     }
  233.  
  234.   U32 res = data [0] & 0x80 ? 0xffffffff : 0;
  235.  
  236.   while (length--)
  237.     res = (res << 8) | *data++;
  238.  
  239.   return res;
  240. }
  241.  
  242. static SV *
  243. process_integer32_sv (void)
  244. {
  245.   return newSViv ((I32)process_integer32 ());
  246. }
  247.  
  248. static SV *
  249. process_unsigned32_sv (void)
  250. {
  251.   return newSVuv ((U32)process_integer32 ());
  252. }
  253.  
  254. #if IVSIZE >= 8
  255.  
  256. static U64TYPE
  257. process_integer64 (void)
  258. {
  259.   U32 length = process_length ();
  260.  
  261.   if (length <= 0)
  262.     {
  263.       error ("INTEGER64 length equal to zero");
  264.       return 0;
  265.     }
  266.  
  267.   U8 *data = getn (length, 0);
  268.  
  269.   if (!data)
  270.     return 0;
  271.  
  272.   if (length > 9 || (length > 8 && data [0]))
  273.     {
  274.       error ("INTEGER64 length too long");
  275.       return 0;
  276.     }
  277.  
  278.   U64TYPE res = data [0] & 0x80 ? 0xffffffffffffffff : 0;
  279.  
  280.   while (length--)
  281.     res = (res << 8) | *data++;
  282.  
  283.   return res;
  284. }
  285.  
  286. static SV *
  287. process_integer64_sv (void)
  288. {
  289.   return newSViv ((I64TYPE)process_integer64 ());
  290. }
  291.  
  292. static SV *
  293. process_unsigned64_sv (void)
  294. {
  295.   return newSVuv ((U64TYPE)process_integer64 ());
  296. }
  297.  
  298. #endif
  299.  
  300. static SV *
  301. process_octet_string_sv (void)
  302. {
  303.   U32 length = process_length ();
  304.  
  305.   U8 *data = getn (length, 0);
  306.   if (!data)
  307.     {
  308.       error ("OCTET STRING too long");
  309.       return &PL_sv_undef;
  310.     }
  311.  
  312.   return newSVpvn (data, length);
  313. }
  314.  
  315. static char *
  316. write_uv (char *buf, U32 u)
  317. {
  318.   // the one-digit case is absolutely predominant
  319.   if (u < 10)
  320.     *buf++ = u + '0';
  321.   else
  322.     buf += sprintf (buf, "%u", (unsigned int)u);
  323.  
  324.   return buf;
  325. }
  326.  
  327. static SV *
  328. process_object_identifier_sv (void)
  329. {
  330.   U32 length = process_length ();
  331.  
  332.   if (length <= 0)
  333.     {
  334.       error ("OBJECT IDENTIFIER length equal to zero");
  335.       return &PL_sv_undef;
  336.     }
  337.  
  338.   U8 *end = cur + length;
  339.   U32 w = getb ();
  340.  
  341.   static char oid[MAX_OID_STRLEN]; // must be static
  342.   char *app = oid;
  343.  
  344.   if (leading_dot < 0)
  345.     leading_dot = SvTRUE (*hv_fetch ((HV *)SvRV (msg), "_leading_dot", sizeof ("_leading_dot") - 1, 1));
  346.  
  347.   *app = '.'; app += ! ! leading_dot;
  348.   app = write_uv (app, (U8)w / 40);
  349.   *app++ = '.';
  350.   app = write_uv (app, (U8)w % 40);
  351.  
  352.   // we assume an oid component is never > 64 bytes
  353.   while (cur < end && oid + sizeof (oid) - app > 64)
  354.     {
  355.       w = getb ();
  356.       *app++ = '.';
  357.       app = write_uv (app, w);
  358.     }
  359.  
  360.   return newSVpvn (oid, app - oid);
  361. }
  362.  
  363. static AV *av_type;
  364.  
  365. static SV *
  366. process_sv (int *found)
  367. {
  368.   int type = get8 ();
  369.  
  370.   *found = type;
  371.  
  372.   SV *res;
  373.  
  374.   switch (type)
  375.     {
  376.       case ASN_OBJECT_IDENTIFIER:
  377.         res = process_object_identifier_sv ();
  378.         break;
  379.  
  380.       case ASN_INTEGER32:
  381.         res = process_integer32_sv ();
  382.         break;
  383.  
  384.       case ASN_UNSIGNED32:
  385.       case ASN_COUNTER32:
  386.       case ASN_TIMETICKS:
  387.         res = process_unsigned32_sv ();
  388.         break;
  389.  
  390.       case ASN_SEQUENCE:
  391.         res = newSVuv (process_length ());
  392.         break;
  393.  
  394.       case ASN_OCTET_STRING:
  395.       case ASN_OPAQUE:
  396.         res = process_octet_string_sv ();
  397.         break;
  398.  
  399.       default:
  400.         {
  401.           if (type > AvFILLp (av_type) || SvTYPE (AvARRAY (av_type)[type]) != SVt_PVCV)
  402.             {
  403.               error ("Unknown ASN.1 type");
  404.               return &PL_sv_undef;
  405.             }
  406.  
  407.           dSP;
  408.           PUSHMARK (SP);
  409.           EXTEND (SP, 2);
  410.           PUSHs (msg);
  411.           PUSHs (sv_2mortal (newSViv (type)));
  412.           PUTBACK;
  413.           int count = call_sv (AvARRAY (av_type)[type], G_SCALAR);
  414.           SPAGAIN;
  415.           res = count ? SvREFCNT_inc (TOPs) : &PL_sv_undef;
  416.         }
  417.     }
  418.  
  419.   return errflag ? &PL_sv_undef : res;
  420. }
  421.  
  422. /////////////////////////////////////////////////////////////////////////////
  423.  
  424. #if HAVE_VERSIONSORT
  425.  
  426. static int
  427. oid_lex_cmp (const void *a_, const void *b_)
  428. {
  429.   const char *a = SvPVX (*(SV **)a_);
  430.   const char *b = SvPVX (*(SV **)b_);
  431.  
  432.   a += *a == '.';
  433.   b += *b == '.';
  434.  
  435.   return strverscmp (a, b);
  436. }
  437.  
  438. #endif
  439.  
  440. MODULE = Net::SNMP::XS      PACKAGE = Net::SNMP::XS
  441.  
  442. PROTOTYPES: ENABLE
  443.  
  444. BOOT:
  445.     av_type = newAV ();
  446.  
  447. void
  448. set_type (int type, SV *cv)
  449.     CODE:
  450.         av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
  451.  
  452. MODULE = Net::SNMP::XS      PACKAGE = Net::SNMP::Message
  453.  
  454. void
  455. _buffer_append (BUFOBJ self, SV *value)
  456.     ALIAS:
  457.         _buffer_put = 1
  458.     PPCODE:
  459. {
  460.         STRLEN vlen;
  461.         const char *vstr = SvPVbyte (value, vlen);
  462.  
  463.         if (ix)
  464.           sv_insert (bufsv, 0, 0, vstr, vlen);
  465.         else
  466.           sv_catpvn (bufsv, vstr, vlen);
  467.  
  468.         buf = SvPVbyte (bufsv, len);
  469.         cur = buf;
  470.         rem = len;
  471.  
  472.     SV *len_sv = *hv_fetch ((HV *)cur_bufobj, "_length", sizeof ("_length") - 1, 1);
  473.         sv_setiv (len_sv, len);
  474.  
  475.         // some callers test for defined'ness of the returnvalue. *sigh*
  476.         XPUSHs (&PL_sv_yes);
  477. }
  478.  
  479. void
  480. _buffer_get (BUFOBJ self, int count = -1)
  481.     PPCODE:
  482. {
  483.     // grrr.
  484.     if (count < 0)
  485.           {
  486.             hv_delete ((HV *)SvRV (self), "_index" , 6, G_DISCARD);
  487.             hv_delete ((HV *)SvRV (self), "_length", 7, G_DISCARD);
  488.             XPUSHs (sv_2mortal (newSVsv (bufsv)));
  489.             sv_setpvn (bufsv, "", 0);
  490.  
  491.             buf = "";
  492.             cur = buf;
  493.             rem = 0;
  494.  
  495.             XSRETURN (1);
  496.           }
  497.  
  498.         char *data = getn (count, 0);
  499.  
  500.         if (data)
  501.           XPUSHs (sv_2mortal (newSVpvn (data, count)));
  502. }
  503.  
  504. U32
  505. index (BUFOBJ self, int ndx = -1)
  506.     CODE:
  507. {
  508.         if (ndx >= 0 && ndx < len)
  509.           {
  510.             cur = buf + ndx;
  511.             rem = len - ndx;
  512.           }
  513.  
  514.         RETVAL = cur - buf;
  515. }
  516.     OUTPUT:
  517.         RETVAL
  518.  
  519. U32
  520. _process_length (BUFOBJ self, ...)
  521.     ALIAS:
  522.         _process_sequence = 0
  523.     CODE:
  524.         RETVAL = process_length ();
  525.     OUTPUT:
  526.         RETVAL
  527.  
  528. SV *
  529. _process_integer32 (BUFOBJ self, ...)
  530.     CODE:
  531.         RETVAL = process_integer32_sv ();
  532.     OUTPUT:
  533.         RETVAL
  534.  
  535. SV *
  536. _process_counter (BUFOBJ self, ...)
  537.     ALIAS:
  538.         _process_gauge     = 0
  539.         _process_timeticks = 0
  540.     CODE:
  541.         RETVAL = process_unsigned32_sv ();
  542.     OUTPUT:
  543.         RETVAL
  544.  
  545. #if IVSIZE >= 8
  546.  
  547. SV *
  548. _process_counter64 (BUFOBJ self, ...)
  549.     CODE:
  550.         RETVAL = process_unsigned64_sv ();
  551.     OUTPUT:
  552.         RETVAL
  553.  
  554. #endif
  555.  
  556. SV *
  557. _process_object_identifier (BUFOBJ self, ...)
  558.     CODE:
  559.         RETVAL = process_object_identifier_sv ();
  560.     OUTPUT:
  561.         RETVAL
  562.  
  563. SV *
  564. _process_octet_string (BUFOBJ self, ...)
  565.     ALIAS:
  566.         _process_opaque = 0
  567.     CODE:
  568.         RETVAL = process_octet_string_sv ();
  569.     OUTPUT:
  570.         RETVAL
  571.  
  572. SV *
  573. _process_ipaddress (BUFOBJ self, ...)
  574.     CODE:
  575. {
  576.     U32 length = process_length ();
  577.         if (length != 4)
  578.           {
  579.             error ("IP ADDRESS length not four");
  580.             XSRETURN_UNDEF;
  581.           }
  582.  
  583.         U8 *data = getn (4, "\x00\x00\x00\x00");
  584.         RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]);
  585. }
  586.     OUTPUT:
  587.         RETVAL
  588.  
  589. SV *
  590. process (BUFOBJ self, SV *expected = &PL_sv_undef, SV *found = 0)
  591.     CODE:
  592. {
  593.     int type;
  594.  
  595.         RETVAL = process_sv (&type);
  596.  
  597.         if (found)
  598.           sv_setiv (found, type);
  599.  
  600.         if (SvOK (expected) && type != SvIV (expected))
  601.           error ("Expected a different type than found");
  602. }
  603.     OUTPUT:
  604.         RETVAL
  605.  
  606. MODULE = Net::SNMP::XS      PACKAGE = Net::SNMP::PDU
  607.  
  608. SV *
  609. _process_var_bind_list (BUFOBJ self)
  610.         CODE:
  611. {
  612.         if (get8 () != ASN_SEQUENCE)
  613.           error ("SEQUENCE expected at beginning of VarBindList");
  614.         int seqlen = process_length ();
  615.         U8 *end = cur + seqlen;
  616.  
  617.         HV *list  = newHV ();
  618.         AV *names = newAV ();
  619.         HV *types = newHV ();
  620.  
  621.         hv_store ((HV *)cur_bufobj, "_var_bind_list" , sizeof ("_var_bind_list" ) - 1, newRV_noinc ((SV *)list ), 0);
  622.         hv_store ((HV *)cur_bufobj, "_var_bind_names", sizeof ("_var_bind_names") - 1, newRV_noinc ((SV *)names), 0);
  623.         hv_store ((HV *)cur_bufobj, "_var_bind_types", sizeof ("_var_bind_types") - 1, newRV_noinc ((SV *)types), 0);
  624.        
  625.         while (cur < end && !errflag)
  626.           {
  627.             // SEQUENCE ObjectName ObjectSyntax
  628.             if (get8 () != ASN_SEQUENCE)
  629.               error ("SEQUENCE expected at beginning of VarBind");
  630.             process_length ();
  631.  
  632.             if (get8 () != ASN_OBJECT_IDENTIFIER)
  633.               error ("OBJECT IDENTIFIER expected at beginning of VarBind");
  634.             int type, oidlen;
  635.             SV *oid = process_object_identifier_sv ();
  636.             SV *val = process_sv (&type);
  637.        
  638.             hv_store_ent (types, oid, newSViv (type), 0);
  639.             hv_store_ent (list , oid, val, 0);
  640.             av_push (names, oid);
  641.           }
  642.        
  643.         // sigh - great design to do it here
  644.         SV *pdu_type = *hv_fetch ((HV *)cur_bufobj, "_pdu_type" , sizeof ("_pdu_type" ) - 1, 1);
  645.  
  646.         if (SvIV (pdu_type) == 0xa8) // REPORT
  647.           {
  648.             PUSHMARK (SP);
  649.             XPUSHs (msg);
  650.             PUTBACK;
  651.             call_method ("_report_pdu_error", G_VOID | G_DISCARD);
  652.             SPAGAIN;
  653.             XSRETURN_EMPTY;
  654.           }
  655.        
  656.         RETVAL = newRV_inc ((SV *)list);
  657. }
  658.     OUTPUT:
  659.         RETVAL
  660.  
  661. MODULE = Net::SNMP::XS      PACKAGE = Net::SNMP
  662.  
  663. void
  664. oid_base_match (SV *base_, SV *oid_)
  665.     PROTOTYPE: $$
  666.         ALIAS:
  667.         oid_context_match = 0
  668.         PPCODE:
  669. {
  670.         if (!SvOK (base_) || !SvOK (oid_))
  671.           XSRETURN_NO;
  672.  
  673.         STRLEN blen, olen;
  674.         char *base = SvPVbyte (base_, blen);
  675.         char *oid  = SvPVbyte (oid_ , olen);
  676.  
  677.         blen -= *base == '.'; base += *base == '.';
  678.         olen -= *base == '.'; oid  += *oid  == '.';
  679.  
  680.         if (olen < blen)
  681.           XSRETURN_NO;
  682.  
  683.         if (memcmp (base, oid, blen))
  684.           XSRETURN_NO;
  685.  
  686.         if (oid [blen] && oid [blen] != '.')
  687.           XSRETURN_NO;
  688.  
  689.         XSRETURN_YES;
  690. }
  691.  
  692. #if HAVE_VERSIONSORT
  693.  
  694. void
  695. oid_lex_sort (...)
  696.     PROTOTYPE: @
  697.         PPCODE:
  698. {
  699.         // make sure SvPVX is valid
  700.         int i;
  701.         for (i = items; i--; )
  702.           {
  703.             SV *sv = ST (i);
  704.  
  705.             if (SvTYPE (sv) < SVt_PV || SvTYPE (sv) == SVt_PVAV && SvTYPE (sv) == SVt_PVHV)
  706.               SvPV_force_nolen (sv);
  707.           }
  708.  
  709.         qsort (&ST (0), items, sizeof (SV *), oid_lex_cmp);
  710.  
  711.         EXTEND (SP, items);
  712.         // we cheat somewhat by not returning copies here
  713.         for (i = 0; i < items; ++i)
  714.           PUSHs (sv_2mortal (SvREFCNT_inc (ST (i))));
  715. }
  716.  
  717. int
  718. _index_cmp (const char *a, const char *b)
  719.     PROTOTYPE: $$
  720.         CODE:
  721.         RETVAL = strverscmp (a, b);
  722.         OUTPUT:
  723.         RETVAL
  724.  
  725. #endif
Advertisement
Add Comment
Please, Sign In to add comment