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