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