ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-SNMP-XS/XS.xs
Revision: 1.10
Committed: Sat Apr 11 06:24:18 2009 UTC (15 years, 2 months ago) by root
Branch: MAIN
Changes since 1.9: +85 -0 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.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.5 *app = '.'; app += ! ! leading_dot;
290 root 1.6 app = write_uv (app, (U8)w / 40);
291 root 1.5 *app++ = '.';
292 root 1.6 app = write_uv (app, (U8)w % 40);
293 root 1.4
294 root 1.5 // we assume an oid component is never > 64 bytes
295     while (cur < end && oid + sizeof (oid) - app > 64)
296     {
297     w = getb ();
298     *app++ = '.';
299     app = write_uv (app, w);
300     }
301 root 1.4
302 root 1.7 return newSVpvn (oid, app - oid);
303 root 1.6 }
304    
305     static AV *av_type;
306    
307     static SV *
308     process_sv (int *found)
309     {
310     int type = get8 ();
311    
312     *found = type;
313    
314     SV *res;
315    
316     switch (type)
317 root 1.4 {
318 root 1.6 case ASN_OBJECT_IDENTIFIER:
319     res = process_object_identifier_sv ();
320     break;
321    
322     case ASN_INTEGER32:
323     res = process_integer32_sv ();
324     break;
325    
326     case ASN_UNSIGNED32:
327     case ASN_COUNTER32:
328     case ASN_TIMETICKS:
329     res = process_unsigned32_sv ();
330     break;
331    
332     case ASN_SEQUENCE:
333     res = newSVuv (process_length ());
334     break;
335    
336     case ASN_OCTET_STRING:
337     case ASN_OPAQUE:
338     res = process_octet_string_sv ();
339     break;
340    
341     default:
342     {
343     if (type > AvFILLp (av_type) || !SvTYPE (AvARRAY (av_type)[type]) == SVt_PVCV)
344     {
345     error ("Unknown ASN.1 type");
346     return &PL_sv_undef;
347     }
348    
349     dSP;
350     PUSHMARK (SP);
351     EXTEND (SP, 2);
352     PUSHs (msg);
353     PUSHs (sv_2mortal (newSViv (type)));
354     PUTBACK;
355     int count = call_sv (AvARRAY (av_type)[type], G_SCALAR);
356     SPAGAIN;
357     res = count ? SvREFCNT_inc (TOPs) : &PL_sv_undef;
358     }
359 root 1.4 }
360    
361 root 1.6 return errflag ? &PL_sv_undef : res;
362 root 1.4 }
363    
364 root 1.10 /////////////////////////////////////////////////////////////////////////////
365    
366     #if HAVE_VERSIONSORT
367    
368     static int
369     oid_lex_cmp (const void *a_, const void *b_)
370     {
371     const char *a = SvPVX (*(SV **)a_);
372     const char *b = SvPVX (*(SV **)b_);
373    
374     a += *a == '.';
375     b += *b == '.';
376    
377     return strverscmp (a, b);
378     }
379    
380     #endif
381    
382 root 1.1 MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
383    
384 root 1.3 PROTOTYPES: ENABLE
385    
386     BOOT:
387     av_type = newAV ();
388    
389     void
390     set_type (int type, SV *cv)
391     CODE:
392     av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
393    
394 root 1.1 void
395     set_msg (SV *msg_, SV *buf_)
396     CODE:
397 root 1.8 {
398     if (msg)
399     croak ("recursive invocation of Net::SNMP::XS parser is not supported");
400    
401 root 1.4 errflag = 0;
402     leading_dot = -1;
403     msg = SvREFCNT_inc (msg_);
404     buf = SvPVbyte (buf_, len);
405     cur = buf;
406     rem = len;
407 root 1.2 #ifdef BENCHMARK
408 root 1.4 t1 = tstamp ();
409 root 1.2 #endif
410 root 1.8 }
411 root 1.1
412     void
413     clr_msg ()
414     CODE:
415 root 1.8 SvREFCNT_dec (msg); msg = 0;
416     buf = cur = (U8 *)"";
417 root 1.1 len = rem = 0;
418 root 1.2 #ifdef BENCHMARK
419 root 1.1 printf ("%f\n", tstamp () - t1);//D
420 root 1.2 #endif
421 root 1.1
422     MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::Message
423    
424     void
425     _buffer_get (SV *self, int count = -1)
426     PPCODE:
427     {
428     // grrr.
429     if (count < 0)
430     {
431     hv_delete ((HV *)SvRV (self), "_index" , 6, G_DISCARD);
432     hv_delete ((HV *)SvRV (self), "_length", 7, G_DISCARD);
433     SV **svp = hv_fetch ((HV *)SvRV (self), "_buffer", 7, 1);
434     XPUSHs (sv_2mortal (newSVsv (*svp)));
435     sv_setpvn (*svp, "", 0);
436     XSRETURN (1);
437     }
438    
439     char *data = getn (count, 0);
440    
441     if (data)
442     XPUSHs (sv_2mortal (newSVpvn (data, count)));
443     }
444    
445     U32
446     index (SV *self, int ndx = -1)
447     CODE:
448     {
449     if (ndx >= 0 && ndx < len)
450     {
451     cur = buf + ndx;
452     rem = len - ndx;
453     }
454    
455     RETVAL = cur - buf;
456     }
457     OUTPUT:
458     RETVAL
459    
460     U32
461     _process_length (SV *self, ...)
462     ALIAS:
463 root 1.3 _process_sequence = 0
464 root 1.1 CODE:
465     RETVAL = process_length ();
466     OUTPUT:
467     RETVAL
468    
469 root 1.4 SV *
470 root 1.1 _process_integer32 (SV *self, ...)
471 root 1.4 CODE:
472     RETVAL = process_integer32_sv ();
473     OUTPUT:
474     RETVAL
475    
476     SV *
477     _process_counter (SV *self, ...)
478 root 1.1 ALIAS:
479 root 1.4 _process_gauge = 0
480     _process_timeticks = 0
481 root 1.1 CODE:
482 root 1.4 RETVAL = process_unsigned32_sv ();
483 root 1.1 OUTPUT:
484     RETVAL
485    
486 root 1.8 #if IVSIZE >= 8
487    
488     SV *
489     _process_counter64 (SV *self, ...)
490     CODE:
491     RETVAL = process_unsigned64_sv ();
492     OUTPUT:
493     RETVAL
494    
495     #endif
496    
497 root 1.1 SV *
498     _process_object_identifier (SV *self, ...)
499     CODE:
500 root 1.4 RETVAL = process_object_identifier_sv ();
501 root 1.1 OUTPUT:
502     RETVAL
503    
504     SV *
505     _process_octet_string (SV *self, ...)
506     ALIAS:
507     _process_opaque = 0
508     CODE:
509 root 1.4 RETVAL = process_octet_string_sv ();
510 root 1.1 OUTPUT:
511     RETVAL
512    
513     SV *
514     _process_ipaddress (SV *self, ...)
515     CODE:
516     {
517     U32 length = process_length ();
518     if (length != 4)
519     {
520     error ("IP ADDRESS length not four");
521     XSRETURN_UNDEF;
522     }
523    
524     U8 *data = getn (4, "\x00\x00\x00\x00");
525     RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]);
526     }
527     OUTPUT:
528     RETVAL
529    
530 root 1.3 SV *
531 root 1.6 process (SV *self, SV *expected = &PL_sv_undef, SV *found = 0)
532     CODE:
533 root 1.3 {
534 root 1.6 int type;
535 root 1.3
536 root 1.6 RETVAL = process_sv (&type);
537 root 1.3
538     if (found)
539     sv_setiv (found, type);
540    
541 root 1.6 if (SvOK (expected) && type != SvIV (expected))
542     error ("Expected a different type than found");
543 root 1.4 }
544 root 1.6 OUTPUT:
545     RETVAL
546 root 1.4
547     MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
548    
549     SV *
550     _process_var_bind_list (SV *self)
551     CODE:
552     {
553 root 1.6 if (get8 () != ASN_SEQUENCE)
554     error ("SEQUENCE expected at beginning of VarBindList");
555     int seqlen = process_length ();
556     U8 *end = cur + seqlen;
557    
558     HV *list = newHV ();
559     AV *names = newAV ();
560     HV *types = newHV ();
561    
562     hv_store ((HV *)SvRV (self), "_var_bind_list" , sizeof ("_var_bind_list" ) - 1, newRV_noinc ((SV *)list ), 0);
563     hv_store ((HV *)SvRV (self), "_var_bind_names", sizeof ("_var_bind_names") - 1, newRV_noinc ((SV *)names), 0);
564     hv_store ((HV *)SvRV (self), "_var_bind_types", sizeof ("_var_bind_types") - 1, newRV_noinc ((SV *)types), 0);
565 root 1.4
566 root 1.6 while (cur < end && !errflag)
567     {
568     // SEQUENCE ObjectName ObjectSyntax
569     if (get8 () != ASN_SEQUENCE)
570     error ("SEQUENCE expected at beginning of VarBind");
571     process_length ();
572    
573     if (get8 () != ASN_OBJECT_IDENTIFIER)
574     error ("OBJECT IDENTIFIER expected at beginning of VarBind");
575     int type, oidlen;
576 root 1.7 SV *oid = process_object_identifier_sv ();
577 root 1.6 SV *val = process_sv (&type);
578    
579 root 1.7 hv_store_ent (types, oid, newSViv (type), 0);
580     hv_store_ent (list , oid, val, 0);
581     av_push (names, oid);
582 root 1.6 }
583 root 1.4
584 root 1.6 //return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT);
585 root 1.4
586 root 1.6 RETVAL = newRV_inc ((SV *)list);
587 root 1.4 }
588 root 1.6 OUTPUT:
589     RETVAL
590 root 1.3
591 root 1.10 MODULE = Net::SNMP::XS PACKAGE = Net::SNMP
592    
593     void
594     oid_base_match (SV *base_, SV *oid_)
595     PROTOTYPE: $$
596     ALIAS:
597     oid_context_match = 0
598     PPCODE:
599     {
600     if (!SvOK (base_) || !SvOK (oid_))
601     XSRETURN_NO;
602    
603     STRLEN blen, olen;
604     char *base = SvPV (base_, blen);
605     char *oid = SvPV (oid_ , olen);
606    
607     blen -= *base == '.'; base += *base == '.';
608     olen -= *base == '.'; oid += *oid == '.';
609    
610     if (olen < blen)
611     XSRETURN_NO;
612    
613     if (memcmp (base, oid, blen))
614     XSRETURN_NO;
615    
616     if (oid [blen] && oid [blen] != '.')
617     XSRETURN_NO;
618    
619     XSRETURN_YES;
620     }
621    
622     #if HAVE_VERSIONSORT
623    
624     void
625     oid_lex_sort (...)
626     PROTOTYPE: @
627     PPCODE:
628     {
629     // make sure SvPVX is valid
630     int i;
631     for (i = items; i--; )
632     {
633     SV *sv = ST (i);
634    
635     if (SvTYPE (sv) < SVt_PV || SvTYPE (sv) == SVt_PVAV && SvTYPE (sv) == SVt_PVHV)
636     SvPV_force_nolen (sv);
637     }
638    
639     qsort (&ST (0), items, sizeof (SV *), oid_lex_cmp);
640    
641     EXTEND (SP, items);
642     // we cheat somewhat by not returning copies here
643     for (i = 0; i < items; ++i)
644     PUSHs (sv_2mortal (SvREFCNT_inc (ST (i))));
645     }
646    
647     int
648     _index_cmp (const char *a, const char *b)
649     PROTOTYPE: $$
650     CODE:
651     RETVAL = strverscmp (a, b);
652     OUTPUT:
653     RETVAL
654    
655     #endif
656 root 1.3