ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-SNMP-XS/XS.xs
Revision: 1.19
Committed: Fri Apr 19 14:50:44 2019 UTC (5 years, 2 months ago) by root
Branch: MAIN
Changes since 1.18: +134 -50 lines
Log Message:
*** empty log message ***

File Contents

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