ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-SNMP-XS/XS.xs
Revision: 1.15
Committed: Thu Sep 18 02:58:42 2014 UTC (9 years, 9 months ago) by root
Branch: MAIN
CVS Tags: rel-1_3, rel-1_31
Changes since 1.14: +4 -4 lines
Log Message:
1.3

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.13 if (type > AvFILLp (av_type) || SvTYPE (AvARRAY (av_type)[type]) != SVt_PVCV)
402 root 1.6 {
403     error ("Unknown ASN.1 type");
404     return &PL_sv_undef;
405     }
406    
407     dSP;
408     PUSHMARK (SP);
409     EXTEND (SP, 2);
410     PUSHs (msg);
411     PUSHs (sv_2mortal (newSViv (type)));
412     PUTBACK;
413     int count = call_sv (AvARRAY (av_type)[type], G_SCALAR);
414     SPAGAIN;
415     res = count ? SvREFCNT_inc (TOPs) : &PL_sv_undef;
416     }
417 root 1.4 }
418    
419 root 1.6 return errflag ? &PL_sv_undef : res;
420 root 1.4 }
421    
422 root 1.10 /////////////////////////////////////////////////////////////////////////////
423    
424     #if HAVE_VERSIONSORT
425    
426     static int
427     oid_lex_cmp (const void *a_, const void *b_)
428     {
429     const char *a = SvPVX (*(SV **)a_);
430     const char *b = SvPVX (*(SV **)b_);
431    
432     a += *a == '.';
433     b += *b == '.';
434    
435     return strverscmp (a, b);
436     }
437    
438     #endif
439    
440 root 1.1 MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
441    
442 root 1.3 PROTOTYPES: ENABLE
443    
444     BOOT:
445     av_type = newAV ();
446    
447     void
448     set_type (int type, SV *cv)
449     CODE:
450     av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
451    
452 root 1.13 MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::Message
453    
454 root 1.1 void
455 root 1.13 _buffer_append (BUFOBJ self, SV *value)
456     ALIAS:
457     _buffer_put = 1
458     PPCODE:
459     {
460     STRLEN vlen;
461     const char *vstr = SvPVbyte (value, vlen);
462    
463     if (ix)
464     sv_insert (bufsv, 0, 0, vstr, vlen);
465     else
466     sv_catpvn (bufsv, vstr, vlen);
467    
468     buf = SvPVbyte (bufsv, len);
469     cur = buf;
470     rem = len;
471 root 1.1
472 root 1.13 SV *len_sv = *hv_fetch ((HV *)cur_bufobj, "_length", sizeof ("_length") - 1, 1);
473     sv_setiv (len_sv, len);
474 root 1.1
475 root 1.13 // some callers test for defined'ness of the returnvalue. *sigh*
476     XPUSHs (&PL_sv_yes);
477     }
478 root 1.1
479     void
480 root 1.12 _buffer_get (BUFOBJ self, int count = -1)
481 root 1.1 PPCODE:
482     {
483     // grrr.
484     if (count < 0)
485     {
486     hv_delete ((HV *)SvRV (self), "_index" , 6, G_DISCARD);
487     hv_delete ((HV *)SvRV (self), "_length", 7, G_DISCARD);
488 root 1.13 XPUSHs (sv_2mortal (newSVsv (bufsv)));
489     sv_setpvn (bufsv, "", 0);
490    
491     buf = "";
492     cur = buf;
493     rem = 0;
494    
495 root 1.1 XSRETURN (1);
496     }
497    
498     char *data = getn (count, 0);
499    
500     if (data)
501     XPUSHs (sv_2mortal (newSVpvn (data, count)));
502     }
503    
504     U32
505 root 1.12 index (BUFOBJ self, int ndx = -1)
506 root 1.1 CODE:
507     {
508     if (ndx >= 0 && ndx < len)
509     {
510     cur = buf + ndx;
511     rem = len - ndx;
512     }
513    
514     RETVAL = cur - buf;
515     }
516     OUTPUT:
517     RETVAL
518    
519     U32
520 root 1.12 _process_length (BUFOBJ self, ...)
521 root 1.1 ALIAS:
522 root 1.3 _process_sequence = 0
523 root 1.1 CODE:
524     RETVAL = process_length ();
525     OUTPUT:
526     RETVAL
527    
528 root 1.4 SV *
529 root 1.12 _process_integer32 (BUFOBJ self, ...)
530 root 1.4 CODE:
531     RETVAL = process_integer32_sv ();
532     OUTPUT:
533     RETVAL
534    
535     SV *
536 root 1.12 _process_counter (BUFOBJ self, ...)
537 root 1.1 ALIAS:
538 root 1.4 _process_gauge = 0
539     _process_timeticks = 0
540 root 1.1 CODE:
541 root 1.4 RETVAL = process_unsigned32_sv ();
542 root 1.1 OUTPUT:
543     RETVAL
544    
545 root 1.8 #if IVSIZE >= 8
546    
547     SV *
548 root 1.12 _process_counter64 (BUFOBJ self, ...)
549 root 1.8 CODE:
550     RETVAL = process_unsigned64_sv ();
551     OUTPUT:
552     RETVAL
553    
554     #endif
555    
556 root 1.1 SV *
557 root 1.12 _process_object_identifier (BUFOBJ self, ...)
558 root 1.1 CODE:
559 root 1.4 RETVAL = process_object_identifier_sv ();
560 root 1.1 OUTPUT:
561     RETVAL
562    
563     SV *
564 root 1.12 _process_octet_string (BUFOBJ self, ...)
565 root 1.1 ALIAS:
566     _process_opaque = 0
567     CODE:
568 root 1.4 RETVAL = process_octet_string_sv ();
569 root 1.1 OUTPUT:
570     RETVAL
571    
572     SV *
573 root 1.12 _process_ipaddress (BUFOBJ self, ...)
574 root 1.1 CODE:
575     {
576     U32 length = process_length ();
577     if (length != 4)
578     {
579     error ("IP ADDRESS length not four");
580     XSRETURN_UNDEF;
581     }
582    
583     U8 *data = getn (4, "\x00\x00\x00\x00");
584     RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]);
585     }
586     OUTPUT:
587     RETVAL
588    
589 root 1.3 SV *
590 root 1.12 process (BUFOBJ self, SV *expected = &PL_sv_undef, SV *found = 0)
591 root 1.6 CODE:
592 root 1.3 {
593 root 1.6 int type;
594 root 1.3
595 root 1.6 RETVAL = process_sv (&type);
596 root 1.3
597     if (found)
598     sv_setiv (found, type);
599    
600 root 1.6 if (SvOK (expected) && type != SvIV (expected))
601     error ("Expected a different type than found");
602 root 1.4 }
603 root 1.6 OUTPUT:
604     RETVAL
605 root 1.4
606     MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
607    
608     SV *
609 root 1.12 _process_var_bind_list (BUFOBJ self)
610 root 1.4 CODE:
611     {
612 root 1.6 if (get8 () != ASN_SEQUENCE)
613     error ("SEQUENCE expected at beginning of VarBindList");
614     int seqlen = process_length ();
615     U8 *end = cur + seqlen;
616    
617     HV *list = newHV ();
618     AV *names = newAV ();
619     HV *types = newHV ();
620    
621 root 1.12 hv_store ((HV *)cur_bufobj, "_var_bind_list" , sizeof ("_var_bind_list" ) - 1, newRV_noinc ((SV *)list ), 0);
622     hv_store ((HV *)cur_bufobj, "_var_bind_names", sizeof ("_var_bind_names") - 1, newRV_noinc ((SV *)names), 0);
623     hv_store ((HV *)cur_bufobj, "_var_bind_types", sizeof ("_var_bind_types") - 1, newRV_noinc ((SV *)types), 0);
624 root 1.4
625 root 1.6 while (cur < end && !errflag)
626     {
627     // SEQUENCE ObjectName ObjectSyntax
628     if (get8 () != ASN_SEQUENCE)
629     error ("SEQUENCE expected at beginning of VarBind");
630     process_length ();
631    
632     if (get8 () != ASN_OBJECT_IDENTIFIER)
633     error ("OBJECT IDENTIFIER expected at beginning of VarBind");
634     int type, oidlen;
635 root 1.7 SV *oid = process_object_identifier_sv ();
636 root 1.6 SV *val = process_sv (&type);
637    
638 root 1.7 hv_store_ent (types, oid, newSViv (type), 0);
639     hv_store_ent (list , oid, val, 0);
640     av_push (names, oid);
641 root 1.6 }
642 root 1.4
643 root 1.12 // sigh - great design to do it here
644     SV *pdu_type = *hv_fetch ((HV *)cur_bufobj, "_pdu_type" , sizeof ("_pdu_type" ) - 1, 1);
645    
646     if (SvIV (pdu_type) == 0xa8) // REPORT
647     {
648     PUSHMARK (SP);
649     XPUSHs (msg);
650     PUTBACK;
651     call_method ("_report_pdu_error", G_VOID | G_DISCARD);
652     SPAGAIN;
653     XSRETURN_EMPTY;
654     }
655 root 1.4
656 root 1.6 RETVAL = newRV_inc ((SV *)list);
657 root 1.4 }
658 root 1.6 OUTPUT:
659     RETVAL
660 root 1.3
661 root 1.10 MODULE = Net::SNMP::XS PACKAGE = Net::SNMP
662    
663     void
664     oid_base_match (SV *base_, SV *oid_)
665     PROTOTYPE: $$
666     ALIAS:
667     oid_context_match = 0
668     PPCODE:
669     {
670     if (!SvOK (base_) || !SvOK (oid_))
671     XSRETURN_NO;
672    
673     STRLEN blen, olen;
674 root 1.13 char *base = SvPVbyte (base_, blen);
675     char *oid = SvPVbyte (oid_ , olen);
676 root 1.10
677     blen -= *base == '.'; base += *base == '.';
678     olen -= *base == '.'; oid += *oid == '.';
679    
680     if (olen < blen)
681     XSRETURN_NO;
682    
683     if (memcmp (base, oid, blen))
684     XSRETURN_NO;
685    
686     if (oid [blen] && oid [blen] != '.')
687     XSRETURN_NO;
688    
689     XSRETURN_YES;
690     }
691    
692     #if HAVE_VERSIONSORT
693    
694     void
695     oid_lex_sort (...)
696     PROTOTYPE: @
697     PPCODE:
698     {
699     // make sure SvPVX is valid
700     int i;
701     for (i = items; i--; )
702     {
703     SV *sv = ST (i);
704    
705     if (SvTYPE (sv) < SVt_PV || SvTYPE (sv) == SVt_PVAV && SvTYPE (sv) == SVt_PVHV)
706     SvPV_force_nolen (sv);
707     }
708    
709     qsort (&ST (0), items, sizeof (SV *), oid_lex_cmp);
710    
711     EXTEND (SP, items);
712     // we cheat somewhat by not returning copies here
713     for (i = 0; i < items; ++i)
714     PUSHs (sv_2mortal (SvREFCNT_inc (ST (i))));
715     }
716    
717     int
718     _index_cmp (const char *a, const char *b)
719     PROTOTYPE: $$
720     CODE:
721     RETVAL = strverscmp (a, b);
722     OUTPUT:
723     RETVAL
724    
725     #endif
726 root 1.3