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.4 by root, Thu Apr 9 04:37:05 2009 UTC vs.
Revision 1.8 by root, Thu Apr 9 10:08:25 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 23
24static SV *msg; 24static SV *msg;
25static int errflag, leading_dot; 25static int errflag, leading_dot;
26static U8 *buf, *cur; 26static U8 *buf, *cur;
38 38
39 return (SV *)cv; 39 return (SV *)cv;
40} 40}
41 41
42static void 42static void
43error (const char *msg) 43error (const char *errmsg)
44{ 44{
45 errflag = 1; 45 errflag = 1;
46 46
47 printf ("<<<%s>>>\n", msg);//D 47 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);
48} 54}
49 55
50static int 56static int
51need (int count) 57need (int count)
52{ 58{
183process_unsigned32_sv (void) 189process_unsigned32_sv (void)
184{ 190{
185 return newSVuv ((U32)process_integer32 ()); 191 return newSVuv ((U32)process_integer32 ());
186} 192}
187 193
194#if IVSIZE >= 8
195
196static U64TYPE
197process_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
226static SV *
227process_integer64_sv (void)
228{
229 return newSViv ((I64TYPE)process_integer64 ());
230}
231
232static SV *
233process_unsigned64_sv (void)
234{
235 return newSVuv ((U64TYPE)process_integer64 ());
236}
237
238#endif
239
188static SV * 240static SV *
189process_octet_string_sv (void) 241process_octet_string_sv (void)
190{ 242{
191 U32 length = process_length (); 243 U32 length = process_length ();
192 244
197 return &PL_sv_undef; 249 return &PL_sv_undef;
198 } 250 }
199 251
200 return newSVpvn (data, length); 252 return newSVpvn (data, length);
201} 253}
254
255static char *
256write_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
202static SV * 267static SV *
203process_object_identifier_sv (void) 268process_object_identifier_sv (void)
204{ 269{
205 U32 length = process_length (); 270 U32 length = process_length ();
206 271
211 } 276 }
212 277
213 U8 *end = cur + length; 278 U8 *end = cur + length;
214 U32 w = getb (); 279 U32 w = getb ();
215 280
216 static char oid[MAX_OID_STRLEN]; 281 static char oid[MAX_OID_STRLEN]; // must be static
217 char *buf = oid; 282 char *app = oid;
218 283
219 if (leading_dot) 284 *app = '.'; app += ! ! leading_dot;
285 app = write_uv (app, (U8)w / 40);
220 *buf++ = '.'; 286 *app++ = '.';
287 app = write_uv (app, (U8)w % 40);
221 288
222 buf += snprintf (buf, oid + sizeof (oid) - buf, "%d.%d", (int)w / 40, (int)w % 40); 289 // we assume an oid component is never > 64 bytes
223 290 while (cur < end && oid + sizeof (oid) - app > 64)
224 while (cur < end)
225 { 291 {
226 w = getb (); 292 w = getb ();
227 buf += snprintf (buf, oid + sizeof (oid) - buf, ".%u", (unsigned int)w); 293 *app++ = '.';
294 app = write_uv (app, w);
228 } 295 }
229 296
230 return newSVpvn (oid, buf - oid); 297 return newSVpvn (oid, app - oid);
231} 298}
232 299
233static AV *av_type; 300static AV *av_type;
301
302static SV *
303process_sv (int *found)
304{
305 int type = get8 ();
306
307 *found = type;
308
309 SV *res;
310
311 switch (type)
312 {
313 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 }
355
356 return errflag ? &PL_sv_undef : res;
357}
234 358
235MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS 359MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
236 360
237PROTOTYPES: ENABLE 361PROTOTYPES: ENABLE
238 362
245 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv))); 369 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
246 370
247void 371void
248set_msg (SV *msg_, SV *buf_) 372set_msg (SV *msg_, SV *buf_)
249 CODE: 373 CODE:
374{
375 if (msg)
376 croak ("recursive invocation of Net::SNMP::XS parser is not supported");
377
250 errflag = 0; 378 errflag = 0;
251 leading_dot = -1; 379 leading_dot = -1;
252 msg = SvREFCNT_inc (msg_); 380 msg = SvREFCNT_inc (msg_);
253 buf = SvPVbyte (buf_, len); 381 buf = SvPVbyte (buf_, len);
254 cur = buf; 382 cur = buf;
255 rem = len; 383 rem = len;
256#ifdef BENCHMARK 384#ifdef BENCHMARK
257 t1 = tstamp (); 385 t1 = tstamp ();
258#endif 386#endif
387}
259 388
260void 389void
261clr_msg () 390clr_msg ()
262 CODE: 391 CODE:
263 SvREFCNT_dec (msg); 392 SvREFCNT_dec (msg); msg = 0;
264 buf = cur = ""; 393 buf = cur = (U8 *)"";
265 len = rem = 0; 394 len = rem = 0;
266#ifdef BENCHMARK 395#ifdef BENCHMARK
267 printf ("%f\n", tstamp () - t1);//D 396 printf ("%f\n", tstamp () - t1);//D
268#endif 397#endif
269 398
329 CODE: 458 CODE:
330 RETVAL = process_unsigned32_sv (); 459 RETVAL = process_unsigned32_sv ();
331 OUTPUT: 460 OUTPUT:
332 RETVAL 461 RETVAL
333 462
463#if IVSIZE >= 8
464
465SV *
466_process_counter64 (SV *self, ...)
467 CODE:
468 RETVAL = process_unsigned64_sv ();
469 OUTPUT:
470 RETVAL
471
472#endif
473
334SV * 474SV *
335_process_object_identifier (SV *self, ...) 475_process_object_identifier (SV *self, ...)
336 CODE: 476 CODE:
337 RETVAL = process_object_identifier_sv (); 477 RETVAL = process_object_identifier_sv ();
338 OUTPUT: 478 OUTPUT:
363} 503}
364 OUTPUT: 504 OUTPUT:
365 RETVAL 505 RETVAL
366 506
367SV * 507SV *
368process (SV *self, SV *expected = 0, SV *found = 0) 508process (SV *self, SV *expected = &PL_sv_undef, SV *found = 0)
369 PPCODE: 509 CODE:
370{ 510{
371 U8 type = get8 (); 511 int type;
372 512
373 if (expected && SvOK (expected) && type != SvIV (expected)) 513 RETVAL = process_sv (&type);
374 {
375 error ("Expected a different type than found");
376 XSRETURN_UNDEF;
377 }
378
379 if (type > AvFILLp (av_type) || !SvTYPE (AvARRAY (av_type)[type]) == SVt_PVCV)
380 {
381 sv_dump (AvARRAY (av_type)[type]);//D
382 error ("Unknown ASN.1 type");
383 XSRETURN_UNDEF;
384 }
385 514
386 if (found) 515 if (found)
387 sv_setiv (found, type); 516 sv_setiv (found, type);
388 517
389 //TODO: switch based on type, to avoid calling overhead 518 if (SvOK (expected) && type != SvIV (expected))
390 SV *res; 519 error ("Expected a different type than found");
391
392 switch (type)
393 {
394 case ASN_OBJECT_IDENTIFIER:
395 res = sv_2mortal (process_object_identifier_sv ());
396 break;
397
398 case ASN_INTEGER32:
399 res = sv_2mortal (process_integer32_sv ());
400 break;
401
402 case ASN_UNSIGNED32:
403 case ASN_COUNTER32:
404 case ASN_TIMETICKS:
405 res = sv_2mortal (process_unsigned32_sv ());
406 break;
407
408 case ASN_SEQUENCE:
409 res = sv_2mortal (newSVuv (process_length ()));
410 break;
411
412 case ASN_OCTET_STRING:
413 case ASN_OPAQUE:
414 res = sv_2mortal (process_octet_string_sv ());
415 break;
416
417 default:
418 {
419 dSP;
420 PUSHMARK (SP);
421 EXTEND (SP, 2);
422 PUSHs (self);
423 PUSHs (expected);
424 PUTBACK;
425 int count = call_sv (AvARRAY (av_type)[type], G_SCALAR);
426 SPAGAIN;
427 res = count ? TOPs : &PL_sv_undef;
428 }
429 }
430
431 XPUSHs (errflag ? &PL_sv_undef : res);
432} 520}
433 521 OUTPUT:
434#if 0 522 RETVAL
435 523
436MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU 524MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
437 525
438SV * 526SV *
439_process_var_bind_list (SV *self) 527_process_var_bind_list (SV *self)
440 CODE: 528 CODE:
441{ 529{
442 # VarBindList::=SEQUENCE 530 if (get8 () != ASN_SEQUENCE)
443 if (!defined($value = $this->process(SEQUENCE))) { 531 error ("SEQUENCE expected at beginning of VarBindList");
444 return $this->_error; 532 int seqlen = process_length ();
445 } 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);
446 542
447 # Using the length of the VarBindList SEQUENCE, 543 while (cur < end && !errflag)
448 # calculate the end index. 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 SV *oid = process_object_identifier_sv ();
554 SV *val = process_sv (&type);
449 555
450 my $end = $this->index + $value; 556 hv_store_ent (types, oid, newSViv (type), 0);
557 hv_store_ent (list , oid, val, 0);
558 av_push (names, oid);
559 }
451 560
452 $this->{_var_bind_list} = {}; 561 //return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT);
453 $this->{_var_bind_names} = [];
454 $this->{_var_bind_types} = {};
455 562
456 my ($oid, $type); 563 RETVAL = newRV_inc ((SV *)list);
457
458 while ($this->index < $end) {
459
460 # VarBind::=SEQUENCE
461 if (!defined($this->process(SEQUENCE))) {
462 return $this->_error;
463 }
464 # name::=ObjectName
465 if (!defined($oid = $this->process(OBJECT_IDENTIFIER))) {
466 return $this->_error;
467 }
468 # value::=ObjectSyntax
469 if (!defined($value = $this->process(undef, $type))) {
470 return $this->_error;
471 }
472
473 # Create a hash consisting of the OBJECT IDENTIFIER as a
474 # key and the ObjectSyntax as the value. If there is a
475 # duplicate OBJECT IDENTIFIER in the VarBindList, we pad
476 # that OBJECT IDENTIFIER with spaces to make a unique
477 # key in the hash.
478
479 while (exists($this->{_var_bind_list}->{$oid})) {
480 $oid .= ' '; # Pad with spaces
481 }
482
483 DEBUG_INFO('{ %s => %s: %s }', $oid, asn1_itoa($type), $value);
484 $this->{_var_bind_list}->{$oid} = $value;
485 $this->{_var_bind_types}->{$oid} = $type;
486
487 # Create an array with the ObjectName OBJECT IDENTIFIERs
488 # so that the order in which the VarBinds where encoded
489 # in the PDU can be retrieved later.
490
491 push(@{$this->{_var_bind_names}}, $oid);
492
493 }
494
495 # Return an error based on the contents of the VarBindList
496 # if we received a Report-PDU.
497
498 return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT);
499
500 # Return the var_bind_list hash
501 $this->{_var_bind_list};
502} 564}
565 OUTPUT:
566 RETVAL
503 567
504#endif
505 568

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines