ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-SNMP-XS/XS.xs
Revision: 1.11
Committed: Sun Apr 12 00:48:39 2009 UTC (15 years, 2 months ago) by root
Branch: MAIN
CVS Tags: rel-0_03
Changes since 1.10: +3 -0 lines
Log Message:
0.03

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