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