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, 2 months ago) by root
Branch: MAIN
Changes since 1.19: +133 -34 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 // C99 required
6
7 //#define BENCHMARK
8
9 enum {
10 // ASN_TAG
11 ASN_BOOLEAN = 0x01,
12 ASN_INTEGER32 = 0x02,
13 ASN_BIT_STRING = 0x03,
14 ASN_OCTET_STRING = 0x04,
15 ASN_NULL = 0x05,
16 ASN_OBJECT_IDENTIFIER = 0x06,
17 ASN_SEQUENCE = 0x10,
18
19 ASN_TAG_BER = 0x1f,
20 ASN_TAG_MASK = 0x1f,
21
22 // primitive/constructed
23 ASN_CONSTRUCTED = 0x20,
24
25 // ASN_CLASS
26 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 // 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 };
50
51 #define MAX_OID_STRLEN 4096
52
53 #define HAVE_VERSIONSORT defined (_GNU_SOURCE) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
54
55 static SV *cur_bufobj;
56 static SV *msg, *bufsv;
57 static int errflag, leading_dot;
58 static U8 *buf, *cur;
59 static STRLEN len, rem;
60
61 typedef SV *BUFOBJ;
62
63 // 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 /////////////////////////////////////////////////////////////////////////////
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 clear_bufobj (void)
97 {
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 }
104
105 SvREFCNT_dec (msg);
106 msg = 0;
107 cur_bufobj = 0;
108 }
109
110 static void
111 switch_bufobj (BUFOBJ neu)
112 {
113 clear_bufobj ();
114
115 msg = newSVsv (neu);
116 cur_bufobj = SvRV (msg);
117 sv_rvweaken (msg);
118
119 errflag = 0;
120 leading_dot = -1;
121
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 }
129
130 /////////////////////////////////////////////////////////////////////////////
131
132 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 static void
146 error (const char *errmsg)
147 {
148 errflag = 1;
149
150 if (!msg)
151 croak ("Net::SNMP::XS fatal error, parser called without parsing context");
152
153 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 }
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 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 #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 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
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 static SV *
374 process_object_identifier_sv (void)
375 {
376 U32 length = process_length ();
377
378 if (length <= 0)
379 {
380 error ("OBJECT IDENTIFIER length equal to zero");
381 return &PL_sv_undef;
382 }
383
384 U8 *end = cur + length;
385 U32 w = getb ();
386
387 static char oid[MAX_OID_STRLEN]; // must be static
388 char *app = oid;
389
390 if (leading_dot < 0)
391 leading_dot = SvTRUE (*hv_fetch ((HV *)SvRV (msg), "_leading_dot", sizeof ("_leading_dot") - 1, 1));
392
393 *app = '.'; app += ! ! leading_dot;
394 app = write_uv (app, (U8)w / 40);
395 *app++ = '.';
396 app = write_uv (app, (U8)w % 40);
397
398 // 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
406 return newSVpvn (oid, app - oid);
407 }
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 {
422 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 case ASN_APPLICATION | ASN_UNSIGNED32:
431 case ASN_APPLICATION | ASN_COUNTER32:
432 case ASN_APPLICATION | ASN_TIMETICKS:
433 res = process_unsigned32_sv ();
434 break;
435
436 case ASN_SEQUENCE | ASN_CONSTRUCTED:
437 res = newSVuv (process_length ());
438 break;
439
440 case ASN_OCTET_STRING:
441 case ASN_APPLICATION | ASN_OPAQUE:
442 res = process_octet_string_sv ();
443 break;
444
445 default:
446 {
447 if (type > AvFILLp (av_type)
448 || AvARRAY (av_type)[type] == 0
449 || AvARRAY (av_type)[type] == &PL_sv_undef)
450 {
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 }
466
467 return errflag ? &PL_sv_undef : res;
468 }
469
470 static SV *
471 ber_decode ()
472 {
473 int identifier = get8 ();
474
475 SV *res;
476
477 int constructed = identifier & ASN_CONSTRUCTED;
478 int klass = identifier & ASN_CLASS_MASK;
479 int tag = identifier & ASN_TAG_MASK;
480
481 if (tag == ASN_TAG_BER)
482 tag = getb ();
483
484 #if 0
485 if (/type & ASN_TAG_MASK) == ASN_TAG_MASK)
486 /* TODO: ber tag follows */;
487 #endif
488
489 if (constructed)
490 {
491 U32 len = process_length ();
492 U32 seqend = (cur - buf) + len;
493 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
494
495 while (cur < buf + seqend)
496 av_push (av, ber_decode ());
497
498 if (cur > buf + seqend)
499 croak ("constructed type %02x overflow (%x %x)\n", identifier, cur - buf, seqend);
500
501 res = newRV_inc ((SV *)av);
502 }
503 else
504 switch (identifier)
505 {
506 case ASN_NULL:
507 res = &PL_sv_undef;
508 break;
509
510 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 case ASN_APPLICATION | ASN_UNSIGNED32:
519 case ASN_APPLICATION | ASN_COUNTER32:
520 case ASN_APPLICATION | ASN_TIMETICKS:
521 res = process_unsigned32_sv ();
522 break;
523
524 #if 0 // handled by default case
525 case ASN_OCTET_STRING:
526 case ASN_APPLICATION | ASN_IPADDRESS:
527 case ASN_APPLICATION | ASN_OPAQUE:
528 res = process_octet_string_sv ();
529 break;
530 #endif
531
532 case ASN_APPLICATION | ASN_COUNTER64:
533 res = process_integer64_sv ();
534 break;
535
536 default:
537 res = process_octet_string_sv ();
538 break;
539 }
540
541 if (errflag)
542 croak ("some error");
543
544 AV *av = newAV ();
545 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 res = newRV_noinc ((SV *)av);
551
552 return errflag ? &PL_sv_undef : res;
553 }
554
555 /////////////////////////////////////////////////////////////////////////////
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 MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
574
575 PROTOTYPES: ENABLE
576
577 BOOT:
578 {
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
608 { "BER_CLASS" , BER_CLASS },
609 { "BER_TAG" , BER_TAG },
610 { "BER_CONSTRUCTED", BER_CONSTRUCTED },
611 { "BER_DATA" , BER_DATA },
612 };
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
620 void
621 set_type (int type, SV *cv)
622 CODE:
623 cv = x_get_cv (cv);
624 assert (SvTYPE (cv) == SVt_PVCV);
625 av_store (av_type, type, SvREFCNT_inc_NN (cv));
626
627 SV *
628 ber_decode (SV *ber)
629 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 RETVAL = ber_decode ();
643 }
644 OUTPUT: RETVAL
645
646 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
729 MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::Message
730
731 void
732 _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
749 SV *len_sv = *hv_fetch ((HV *)cur_bufobj, "_length", sizeof ("_length") - 1, 1);
750 sv_setiv (len_sv, len);
751
752 // some callers test for defined'ness of the returnvalue. *sigh*
753 XPUSHs (&PL_sv_yes);
754 }
755
756 void
757 _buffer_get (BUFOBJ self, int count = -1)
758 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 XPUSHs (sv_2mortal (newSVsv (bufsv)));
766 sv_setpvn (bufsv, "", 0);
767
768 buf = "";
769 cur = buf;
770 rem = 0;
771
772 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 index (BUFOBJ self, int ndx = -1)
783 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 OUTPUT: RETVAL
794
795 U32
796 _process_length (BUFOBJ self, ...)
797 ALIAS:
798 _process_sequence = 0
799 CODE:
800 RETVAL = process_length ();
801 OUTPUT: RETVAL
802
803 SV *
804 _process_integer32 (BUFOBJ self, ...)
805 CODE:
806 RETVAL = process_integer32_sv ();
807 OUTPUT: RETVAL
808
809 SV *
810 _process_counter (BUFOBJ self, ...)
811 ALIAS:
812 _process_gauge = 0
813 _process_timeticks = 0
814 CODE:
815 RETVAL = process_unsigned32_sv ();
816 OUTPUT: RETVAL
817
818 #if IVSIZE >= 8
819
820 SV *
821 _process_counter64 (BUFOBJ self, ...)
822 CODE:
823 RETVAL = process_unsigned64_sv ();
824 OUTPUT: RETVAL
825
826 #endif
827
828 SV *
829 _process_object_identifier (BUFOBJ self, ...)
830 CODE:
831 RETVAL = process_object_identifier_sv ();
832 OUTPUT: RETVAL
833
834 SV *
835 _process_octet_string (BUFOBJ self, ...)
836 ALIAS:
837 _process_opaque = 0
838 CODE:
839 RETVAL = process_octet_string_sv ();
840 OUTPUT: RETVAL
841
842 SV *
843 _process_ipaddress (BUFOBJ self, ...)
844 CODE:
845 {
846 U32 length = process_length ();
847 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 OUTPUT: RETVAL
857
858 SV *
859 process (BUFOBJ self, SV *expected = &PL_sv_undef, SV *found = 0)
860 CODE:
861 {
862 int type;
863
864 RETVAL = process_sv (&type);
865
866 if (found)
867 sv_setiv (found, type);
868
869 if (SvOK (expected) && type != SvIV (expected))
870 error ("Expected a different type than found");
871 }
872 OUTPUT: RETVAL
873
874 MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
875
876 SV *
877 _process_var_bind_list (BUFOBJ self)
878 CODE:
879 {
880 if (get8 () != ASN_SEQUENCE | ASN_CONSTRUCTED)
881 error ("SEQUENCE expected at beginning of VarBindList");
882
883 int seqlen = process_length ();
884 U8 *end = cur + seqlen;
885
886 HV *list = newHV ();
887 AV *names = newAV ();
888 HV *types = newHV ();
889
890 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
894 while (cur < end && !errflag)
895 {
896 // SEQUENCE ObjectName ObjectSyntax
897 if (get8 () != ASN_SEQUENCE | ASN_CONSTRUCTED)
898 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 SV *oid = process_object_identifier_sv ();
905 SV *val = process_sv (&type);
906
907 hv_store_ent (types, oid, newSViv (type), 0);
908 hv_store_ent (list , oid, val, 0);
909 av_push (names, oid);
910 }
911
912 // 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
925 RETVAL = newRV_inc ((SV *)list);
926 }
927 OUTPUT: RETVAL
928
929 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 char *base = SvPVbyte (base_, blen);
943 char *oid = SvPVbyte (oid_ , olen);
944
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 OUTPUT: RETVAL
991
992 #endif
993