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.5 by root, Thu Apr 9 04:49:16 2009 UTC vs.
Revision 1.11 by root, Sun Apr 12 00:48:39 2009 UTC

1#include "EXTERN.h" 1#include "EXTERN.h"
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
7//#define BENCHMARK
6 8
7#define ASN_BOOLEAN 0x01 9#define ASN_BOOLEAN 0x01
8#define ASN_INTEGER32 0x02 10#define ASN_INTEGER32 0x02
9#define ASN_OCTET_STRING 0x04 11#define ASN_OCTET_STRING 0x04
10#define ASN_NULL 0x05 12#define ASN_NULL 0x05
15#define ASN_UNSIGNED32 0x42 17#define ASN_UNSIGNED32 0x42
16#define ASN_TIMETICKS 0x43 18#define ASN_TIMETICKS 0x43
17#define ASN_OPAQUE 0x44 19#define ASN_OPAQUE 0x44
18#define ASN_COUNTER64 0x46 20#define ASN_COUNTER64 0x46
19 21
20#define BENCHMARK
21
22#define MAX_OID_STRLEN 4096 22#define MAX_OID_STRLEN 4096
23
24#define HAVE_VERSIONSORT defined (_GNU_SOURCE) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
23 25
24static SV *msg; 26static SV *msg;
25static int errflag, leading_dot; 27static int errflag, leading_dot;
26static U8 *buf, *cur; 28static U8 *buf, *cur;
27static STRLEN len, rem; 29static STRLEN len, rem;
38 40
39 return (SV *)cv; 41 return (SV *)cv;
40} 42}
41 43
42static void 44static void
43error (const char *msg) 45error (const char *errmsg)
44{ 46{
45 errflag = 1; 47 errflag = 1;
46 48
47 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);
48} 59}
49 60
50static int 61static int
51need (int count) 62need (int count)
52{ 63{
183process_unsigned32_sv (void) 194process_unsigned32_sv (void)
184{ 195{
185 return newSVuv ((U32)process_integer32 ()); 196 return newSVuv ((U32)process_integer32 ());
186} 197}
187 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
188static SV * 245static SV *
189process_octet_string_sv (void) 246process_octet_string_sv (void)
190{ 247{
191 U32 length = process_length (); 248 U32 length = process_length ();
192 249
224 } 281 }
225 282
226 U8 *end = cur + length; 283 U8 *end = cur + length;
227 U32 w = getb (); 284 U32 w = getb ();
228 285
229 static char oid[MAX_OID_STRLEN]; 286 static char oid[MAX_OID_STRLEN]; // must be static
230 char *app = oid; 287 char *app = oid;
231 288
289 if (leading_dot < 0)
290 leading_dot = SvTRUE (*hv_fetch ((HV *)SvRV (msg), "_leading_dot", sizeof ("_leading_dot") - 1, 1));
291
232 *app = '.'; app += ! ! leading_dot; 292 *app = '.'; app += ! ! leading_dot;
233 app = write_uv (app, w / 40); 293 app = write_uv (app, (U8)w / 40);
234 *app++ = '.'; 294 *app++ = '.';
235 app = write_uv (app, w % 40); 295 app = write_uv (app, (U8)w % 40);
236 296
237 // we assume an oid component is never > 64 bytes 297 // we assume an oid component is never > 64 bytes
238 while (cur < end && oid + sizeof (oid) - app > 64) 298 while (cur < end && oid + sizeof (oid) - app > 64)
239 { 299 {
240 w = getb (); 300 w = getb ();
241 *app++ = '.'; 301 *app++ = '.';
242 app = write_uv (app, w); 302 app = write_uv (app, w);
243 } 303 }
244#if 0
245 buf += snprintf (buf, oid + sizeof (oid) - buf, "%d.%d", (int)w / 40, (int)w % 40);
246 304
247 while (cur < end) 305 return newSVpvn (oid, app - oid);
248 { 306}
249 w = getb (); 307
250 buf += snprintf (buf, oid + sizeof (oid) - buf, ".%u", (unsigned int)w); 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)
251 } 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
252#endif 383#endif
253
254 return newSVpvn (oid, app - oid);
255}
256
257static AV *av_type;
258 384
259MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS 385MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
260 386
261PROTOTYPES: ENABLE 387PROTOTYPES: ENABLE
262 388
269 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv))); 395 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
270 396
271void 397void
272set_msg (SV *msg_, SV *buf_) 398set_msg (SV *msg_, SV *buf_)
273 CODE: 399 CODE:
400{
401 if (msg)
402 croak ("recursive invocation of Net::SNMP::XS parser is not supported");
403
274 errflag = 0; 404 errflag = 0;
275 leading_dot = -1; 405 leading_dot = -1;
276 msg = SvREFCNT_inc (msg_); 406 msg = SvREFCNT_inc (msg_);
277 buf = SvPVbyte (buf_, len); 407 buf = SvPVbyte (buf_, len);
278 cur = buf; 408 cur = buf;
279 rem = len; 409 rem = len;
280#ifdef BENCHMARK 410#ifdef BENCHMARK
281 t1 = tstamp (); 411 t1 = tstamp ();
282#endif 412#endif
413}
283 414
284void 415void
285clr_msg () 416clr_msg ()
286 CODE: 417 CODE:
287 SvREFCNT_dec (msg); 418 SvREFCNT_dec (msg); msg = 0;
288 buf = cur = ""; 419 buf = cur = (U8 *)"";
289 len = rem = 0; 420 len = rem = 0;
290#ifdef BENCHMARK 421#ifdef BENCHMARK
291 printf ("%f\n", tstamp () - t1);//D 422 printf ("%f\n", tstamp () - t1);//D
292#endif 423#endif
293 424
353 CODE: 484 CODE:
354 RETVAL = process_unsigned32_sv (); 485 RETVAL = process_unsigned32_sv ();
355 OUTPUT: 486 OUTPUT:
356 RETVAL 487 RETVAL
357 488
489#if IVSIZE >= 8
490
491SV *
492_process_counter64 (SV *self, ...)
493 CODE:
494 RETVAL = process_unsigned64_sv ();
495 OUTPUT:
496 RETVAL
497
498#endif
499
358SV * 500SV *
359_process_object_identifier (SV *self, ...) 501_process_object_identifier (SV *self, ...)
360 CODE: 502 CODE:
361 RETVAL = process_object_identifier_sv (); 503 RETVAL = process_object_identifier_sv ();
362 OUTPUT: 504 OUTPUT:
387} 529}
388 OUTPUT: 530 OUTPUT:
389 RETVAL 531 RETVAL
390 532
391SV * 533SV *
392process (SV *self, SV *expected = 0, SV *found = 0) 534process (SV *self, SV *expected = &PL_sv_undef, SV *found = 0)
393 PPCODE: 535 CODE:
394{ 536{
395 U8 type = get8 (); 537 int type;
396 538
397 if (expected && SvOK (expected) && type != SvIV (expected)) 539 RETVAL = process_sv (&type);
398 {
399 error ("Expected a different type than found");
400 XSRETURN_UNDEF;
401 }
402
403 if (type > AvFILLp (av_type) || !SvTYPE (AvARRAY (av_type)[type]) == SVt_PVCV)
404 {
405 sv_dump (AvARRAY (av_type)[type]);//D
406 error ("Unknown ASN.1 type");
407 XSRETURN_UNDEF;
408 }
409 540
410 if (found) 541 if (found)
411 sv_setiv (found, type); 542 sv_setiv (found, type);
412 543
413 //TODO: switch based on type, to avoid calling overhead 544 if (SvOK (expected) && type != SvIV (expected))
414 SV *res; 545 error ("Expected a different type than found");
415
416 switch (type)
417 {
418 case ASN_OBJECT_IDENTIFIER:
419 res = sv_2mortal (process_object_identifier_sv ());
420 break;
421
422 case ASN_INTEGER32:
423 res = sv_2mortal (process_integer32_sv ());
424 break;
425
426 case ASN_UNSIGNED32:
427 case ASN_COUNTER32:
428 case ASN_TIMETICKS:
429 res = sv_2mortal (process_unsigned32_sv ());
430 break;
431
432 case ASN_SEQUENCE:
433 res = sv_2mortal (newSVuv (process_length ()));
434 break;
435
436 case ASN_OCTET_STRING:
437 case ASN_OPAQUE:
438 res = sv_2mortal (process_octet_string_sv ());
439 break;
440
441 default:
442 {
443 dSP;
444 PUSHMARK (SP);
445 EXTEND (SP, 2);
446 PUSHs (self);
447 PUSHs (expected);
448 PUTBACK;
449 int count = call_sv (AvARRAY (av_type)[type], G_SCALAR);
450 SPAGAIN;
451 res = count ? TOPs : &PL_sv_undef;
452 }
453 }
454
455 XPUSHs (errflag ? &PL_sv_undef : res);
456} 546}
457 547 OUTPUT:
458#if 0 548 RETVAL
459 549
460MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU 550MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
461 551
462SV * 552SV *
463_process_var_bind_list (SV *self) 553_process_var_bind_list (SV *self)
464 CODE: 554 CODE:
465{ 555{
466 # VarBindList::=SEQUENCE 556 if (get8 () != ASN_SEQUENCE)
467 if (!defined($value = $this->process(SEQUENCE))) { 557 error ("SEQUENCE expected at beginning of VarBindList");
468 return $this->_error; 558 int seqlen = process_length ();
469 } 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);
470 568
471 # Using the length of the VarBindList SEQUENCE, 569 while (cur < end && !errflag)
472 # calculate the end index. 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);
473 581
474 my $end = $this->index + $value; 582 hv_store_ent (types, oid, newSViv (type), 0);
583 hv_store_ent (list , oid, val, 0);
584 av_push (names, oid);
585 }
475 586
476 $this->{_var_bind_list} = {}; 587 //return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT);
477 $this->{_var_bind_names} = [];
478 $this->{_var_bind_types} = {};
479 588
480 my ($oid, $type); 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--; )
481 635 {
482 while ($this->index < $end) { 636 SV *sv = ST (i);
483 637
484 # VarBind::=SEQUENCE 638 if (SvTYPE (sv) < SVt_PV || SvTYPE (sv) == SVt_PVAV && SvTYPE (sv) == SVt_PVHV)
485 if (!defined($this->process(SEQUENCE))) { 639 SvPV_force_nolen (sv);
486 return $this->_error;
487 } 640 }
488 # name::=ObjectName 641
489 if (!defined($oid = $this->process(OBJECT_IDENTIFIER))) { 642 qsort (&ST (0), items, sizeof (SV *), oid_lex_cmp);
490 return $this->_error; 643
491 } 644 EXTEND (SP, items);
492 # value::=ObjectSyntax 645 // we cheat somewhat by not returning copies here
493 if (!defined($value = $this->process(undef, $type))) { 646 for (i = 0; i < items; ++i)
494 return $this->_error; 647 PUSHs (sv_2mortal (SvREFCNT_inc (ST (i))));
495 } 648}
649
650int
651_index_cmp (const char *a, const char *b)
652 PROTOTYPE: $$
496 653 CODE:
497 # Create a hash consisting of the OBJECT IDENTIFIER as a 654 RETVAL = strverscmp (a, b);
498 # key and the ObjectSyntax as the value. If there is a 655 OUTPUT:
499 # duplicate OBJECT IDENTIFIER in the VarBindList, we pad 656 RETVAL
500 # that OBJECT IDENTIFIER with spaces to make a unique
501 # key in the hash.
502
503 while (exists($this->{_var_bind_list}->{$oid})) {
504 $oid .= ' '; # Pad with spaces
505 }
506
507 DEBUG_INFO('{ %s => %s: %s }', $oid, asn1_itoa($type), $value);
508 $this->{_var_bind_list}->{$oid} = $value;
509 $this->{_var_bind_types}->{$oid} = $type;
510
511 # Create an array with the ObjectName OBJECT IDENTIFIERs
512 # so that the order in which the VarBinds where encoded
513 # in the PDU can be retrieved later.
514
515 push(@{$this->{_var_bind_names}}, $oid);
516
517 }
518
519 # Return an error based on the contents of the VarBindList
520 # if we received a Report-PDU.
521
522 return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT);
523
524 # Return the var_bind_list hash
525 $this->{_var_bind_list};
526}
527 657
528#endif 658#endif
529 659

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines