ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-SNMP-XS/XS.xs
Revision: 1.8
Committed: Thu Apr 9 10:08:25 2009 UTC (15 years, 2 months ago) by root
Branch: MAIN
Changes since 1.7: +74 -6 lines
Log Message:
counter64

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