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