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