ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-SNMP-XS/XS.xs
(Generate patch)

Comparing Net-SNMP-XS/XS.xs (file contents):
Revision 1.2 by root, Wed Apr 8 10:39:32 2009 UTC vs.
Revision 1.11 by root, Sun Apr 12 00:48:39 2009 UTC

2#include "perl.h" 2#include "perl.h"
3#include "XSUB.h" 3#include "XSUB.h"
4 4
5// C99 required 5// C99 required
6 6
7#define ASN_BOOLEAN 0x01
8#define ASN_INTEGER 0x02
9#define ASN_BIT_STR 0x03
10#define ASN_OCTET_STR 0x04
11#define ASN_NULL 0x05
12#define ASN_OBJECT_ID 0x06
13#define ASN_SEQUENCE 0x10
14#define ASN_SET 0x11
15
16#define ASN_UNIVERSAL 0x00
17#define ASN_APPLICATION 0x40
18#define ASN_CONTEXT 0x80
19#define ASN_PRIVATE 0xc0
20
21#define ASN_PRIMITIVE 0x00
22#define ASN_CONSTRUCTOR 0x20
23
24#define ASN_LONG_LEN 0x80
25#define ASN_EXTENSION_ID 0x1f
26#define ASN_BIT8 0x80
27
28//#define BENCHMARK 7//#define BENCHMARK
29 8
9#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
22#define MAX_OID_STRLEN 4096
23
24#define HAVE_VERSIONSORT defined (_GNU_SOURCE) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
25
30static SV *msg; 26static SV *msg;
31static int errflag; 27static int errflag, leading_dot;
32static U8 *buf, *cur; 28static U8 *buf, *cur;
33static STRLEN len, rem; 29static STRLEN len, rem;
34 30
31static SV *
32x_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
35static void 44static void
36error (const char *msg) 45error (const char *errmsg)
37{ 46{
38 errflag = 1; 47 errflag = 1;
39 48
40 printf ("<<<%s>>>\n", msg);//D 49 if (!msg)
50 croak ("Net::SNMP::XS fatal error, parser called without parsing context");
51
52 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);
41} 59}
42 60
43static int 61static int
44need (int count) 62need (int count)
45{ 63{
134 } 152 }
135 153
136 return res; 154 return res;
137} 155}
138 156
157static U32
158process_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
187static SV *
188process_integer32_sv (void)
189{
190 return newSViv ((I32)process_integer32 ());
191}
192
193static SV *
194process_unsigned32_sv (void)
195{
196 return newSVuv ((U32)process_integer32 ());
197}
198
199#if IVSIZE >= 8
200
201static U64TYPE
202process_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
231static SV *
232process_integer64_sv (void)
233{
234 return newSViv ((I64TYPE)process_integer64 ());
235}
236
237static SV *
238process_unsigned64_sv (void)
239{
240 return newSVuv ((U64TYPE)process_integer64 ());
241}
242
243#endif
244
245static SV *
246process_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
260static char *
261write_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
272static SV *
273process_object_identifier_sv (void)
274{
275 U32 length = process_length ();
276
277 if (length <= 0)
278 {
279 error ("OBJECT IDENTIFIER length equal to zero");
280 return &PL_sv_undef;
281 }
282
283 U8 *end = cur + length;
284 U32 w = getb ();
285
286 static char oid[MAX_OID_STRLEN]; // must be static
287 char *app = oid;
288
289 if (leading_dot < 0)
290 leading_dot = SvTRUE (*hv_fetch ((HV *)SvRV (msg), "_leading_dot", sizeof ("_leading_dot") - 1, 1));
291
292 *app = '.'; app += ! ! leading_dot;
293 app = write_uv (app, (U8)w / 40);
294 *app++ = '.';
295 app = write_uv (app, (U8)w % 40);
296
297 // 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
305 return newSVpvn (oid, app - oid);
306}
307
308static AV *av_type;
309
310static SV *
311process_sv (int *found)
312{
313 int type = get8 ();
314
315 *found = type;
316
317 SV *res;
318
319 switch (type)
320 {
321 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 }
363
364 return errflag ? &PL_sv_undef : res;
365}
366
367/////////////////////////////////////////////////////////////////////////////
368
369#if HAVE_VERSIONSORT
370
371static int
372oid_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
139MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS 385MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
386
387PROTOTYPES: ENABLE
388
389BOOT:
390 av_type = newAV ();
391
392void
393set_type (int type, SV *cv)
394 CODE:
395 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
140 396
141void 397void
142set_msg (SV *msg_, SV *buf_) 398set_msg (SV *msg_, SV *buf_)
143 CODE: 399 CODE:
400{
401 if (msg)
402 croak ("recursive invocation of Net::SNMP::XS parser is not supported");
403
144 errflag = 0; 404 errflag = 0;
405 leading_dot = -1;
145 msg = SvREFCNT_inc (msg_); 406 msg = SvREFCNT_inc (msg_);
146 buf = SvPVbyte (buf_, len); 407 buf = SvPVbyte (buf_, len);
147 cur = buf; 408 cur = buf;
148 rem = len; 409 rem = len;
149#ifdef BENCHMARK 410#ifdef BENCHMARK
150 t1 = tstamp (); 411 t1 = tstamp ();
151#endif 412#endif
413}
152 414
153void 415void
154clr_msg () 416clr_msg ()
155 CODE: 417 CODE:
156 SvREFCNT_dec (msg); 418 SvREFCNT_dec (msg); msg = 0;
157 buf = cur = ""; 419 buf = cur = (U8 *)"";
158 len = rem = 0; 420 len = rem = 0;
159#ifdef BENCHMARK 421#ifdef BENCHMARK
160 printf ("%f\n", tstamp () - t1);//D 422 printf ("%f\n", tstamp () - t1);//D
161#endif 423#endif
162 424
199 RETVAL 461 RETVAL
200 462
201U32 463U32
202_process_length (SV *self, ...) 464_process_length (SV *self, ...)
203 ALIAS: 465 ALIAS:
204 _process_sequence = 1 466 _process_sequence = 0
205 CODE: 467 CODE:
206 RETVAL = process_length (); 468 RETVAL = process_length ();
207 OUTPUT: 469 OUTPUT:
208 RETVAL 470 RETVAL
209 471
210I32 472SV *
211_process_integer32 (SV *self, ...) 473_process_integer32 (SV *self, ...)
474 CODE:
475 RETVAL = process_integer32_sv ();
476 OUTPUT:
477 RETVAL
478
479SV *
480_process_counter (SV *self, ...)
212 ALIAS: 481 ALIAS:
213 _process_counter = 0
214 _process_gauge = 0 482 _process_gauge = 0
483 _process_timeticks = 0
215 CODE: 484 CODE:
216{ 485 RETVAL = process_unsigned32_sv ();
217 U32 length = process_length (); 486 OUTPUT:
218
219 if (length <= 0)
220 {
221 error ("INTEGER32 length equal to zero");
222 XSRETURN_UNDEF;
223 }
224
225 U8 *data = getn (length, 0);
226
227 if (!data)
228 XSRETURN_UNDEF;
229
230 if (length > 5 || (length > 4 && data [0]))
231 {
232 error ("INTEGER32 length too long");
233 XSRETURN_UNDEF;
234 }
235
236 U32 res = data [0] & 0x80 ? 0xffffffff : 0;
237
238 while (length--)
239 res = (res << 8) | *data++;
240
241 RETVAL = res; 487 RETVAL
242} 488
489#if IVSIZE >= 8
490
491SV *
492_process_counter64 (SV *self, ...)
493 CODE:
494 RETVAL = process_unsigned64_sv ();
243 OUTPUT: 495 OUTPUT:
244 RETVAL 496 RETVAL
497
498#endif
245 499
246SV * 500SV *
247_process_object_identifier (SV *self, ...) 501_process_object_identifier (SV *self, ...)
248 CODE: 502 CODE:
249{ 503 RETVAL = process_object_identifier_sv ();
250 U32 length = process_length ();
251
252 if (length <= 0)
253 {
254 error ("OBJECT IDENTIFIER length equal to zero");
255 XSRETURN_UNDEF;
256 }
257
258 U8 *end = cur + length;
259 U32 w = getb ();
260
261 //TODO: leading_dots
262
263 RETVAL = newSVpvf (".%d.%d", (int)w / 40, (int)w % 40);
264
265 while (cur < end)
266 {
267 w = getb ();
268 sv_catpvf (RETVAL, ".%u", (unsigned int)w);
269 }
270}
271 OUTPUT: 504 OUTPUT:
272 RETVAL 505 RETVAL
273 506
274SV * 507SV *
275_process_octet_string (SV *self, ...) 508_process_octet_string (SV *self, ...)
276 ALIAS: 509 ALIAS:
277 _process_opaque = 0 510 _process_opaque = 0
278 CODE: 511 CODE:
279{ 512 RETVAL = process_octet_string_sv ();
280 U32 length = process_length ();
281
282 U8 *data = getn (length, 0);
283 if (!data)
284 {
285 error ("OCTET STRING too long");
286 XSRETURN_UNDEF;
287 }
288
289 RETVAL = newSVpvn (data, length);
290}
291 OUTPUT: 513 OUTPUT:
292 RETVAL 514 RETVAL
293 515
294SV * 516SV *
295_process_ipaddress (SV *self, ...) 517_process_ipaddress (SV *self, ...)
306 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]); 528 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]);
307} 529}
308 OUTPUT: 530 OUTPUT:
309 RETVAL 531 RETVAL
310 532
533SV *
534process (SV *self, SV *expected = &PL_sv_undef, SV *found = 0)
535 CODE:
536{
537 int type;
538
539 RETVAL = process_sv (&type);
540
541 if (found)
542 sv_setiv (found, type);
543
544 if (SvOK (expected) && type != SvIV (expected))
545 error ("Expected a different type than found");
546}
547 OUTPUT:
548 RETVAL
549
550MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
551
552SV *
553_process_var_bind_list (SV *self)
554 CODE:
555{
556 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
569 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 SV *oid = process_object_identifier_sv ();
580 SV *val = process_sv (&type);
581
582 hv_store_ent (types, oid, newSViv (type), 0);
583 hv_store_ent (list , oid, val, 0);
584 av_push (names, oid);
585 }
586
587 //return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT);
588
589 RETVAL = newRV_inc ((SV *)list);
590}
591 OUTPUT:
592 RETVAL
593
594MODULE = Net::SNMP::XS PACKAGE = Net::SNMP
595
596void
597oid_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
627void
628oid_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
650int
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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines