ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-SNMP-XS/XS.xs
Revision: 1.9
Committed: Sat Apr 11 04:22:49 2009 UTC (15 years, 2 months ago) by root
Branch: MAIN
CVS Tags: rel-0_02
Changes since 1.8: +3 -0 lines
Log Message:
0.02

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