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.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
224 } 276 }
225 277
226 U8 *end = cur + length; 278 U8 *end = cur + length;
227 U32 w = getb (); 279 U32 w = getb ();
228 280
229 static char oid[MAX_OID_STRLEN]; 281 static char oid[MAX_OID_STRLEN]; // must be static
230 char *app = oid; 282 char *app = oid;
231 283
232 *app = '.'; app += ! ! leading_dot; 284 *app = '.'; app += ! ! leading_dot;
233 app = write_uv (app, w / 40); 285 app = write_uv (app, (U8)w / 40);
234 *app++ = '.'; 286 *app++ = '.';
235 app = write_uv (app, w % 40); 287 app = write_uv (app, (U8)w % 40);
236 288
237 // we assume an oid component is never > 64 bytes 289 // we assume an oid component is never > 64 bytes
238 while (cur < end && oid + sizeof (oid) - app > 64) 290 while (cur < end && oid + sizeof (oid) - app > 64)
239 { 291 {
240 w = getb (); 292 w = getb ();
241 *app++ = '.'; 293 *app++ = '.';
242 app = write_uv (app, w); 294 app = write_uv (app, w);
243 } 295 }
244#if 0
245 buf += snprintf (buf, oid + sizeof (oid) - buf, "%d.%d", (int)w / 40, (int)w % 40);
246
247 while (cur < end)
248 {
249 w = getb ();
250 buf += snprintf (buf, oid + sizeof (oid) - buf, ".%u", (unsigned int)w);
251 }
252#endif
253 296
254 return newSVpvn (oid, app - oid); 297 return newSVpvn (oid, app - oid);
255} 298}
256 299
257static 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}
258 358
259MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS 359MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
260 360
261PROTOTYPES: ENABLE 361PROTOTYPES: ENABLE
262 362
269 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv))); 369 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
270 370
271void 371void
272set_msg (SV *msg_, SV *buf_) 372set_msg (SV *msg_, SV *buf_)
273 CODE: 373 CODE:
374{
375 if (msg)
376 croak ("recursive invocation of Net::SNMP::XS parser is not supported");
377
274 errflag = 0; 378 errflag = 0;
275 leading_dot = -1; 379 leading_dot = -1;
276 msg = SvREFCNT_inc (msg_); 380 msg = SvREFCNT_inc (msg_);
277 buf = SvPVbyte (buf_, len); 381 buf = SvPVbyte (buf_, len);
278 cur = buf; 382 cur = buf;
279 rem = len; 383 rem = len;
280#ifdef BENCHMARK 384#ifdef BENCHMARK
281 t1 = tstamp (); 385 t1 = tstamp ();
282#endif 386#endif
387}
283 388
284void 389void
285clr_msg () 390clr_msg ()
286 CODE: 391 CODE:
287 SvREFCNT_dec (msg); 392 SvREFCNT_dec (msg); msg = 0;
288 buf = cur = ""; 393 buf = cur = (U8 *)"";
289 len = rem = 0; 394 len = rem = 0;
290#ifdef BENCHMARK 395#ifdef BENCHMARK
291 printf ("%f\n", tstamp () - t1);//D 396 printf ("%f\n", tstamp () - t1);//D
292#endif 397#endif
293 398
353 CODE: 458 CODE:
354 RETVAL = process_unsigned32_sv (); 459 RETVAL = process_unsigned32_sv ();
355 OUTPUT: 460 OUTPUT:
356 RETVAL 461 RETVAL
357 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
358SV * 474SV *
359_process_object_identifier (SV *self, ...) 475_process_object_identifier (SV *self, ...)
360 CODE: 476 CODE:
361 RETVAL = process_object_identifier_sv (); 477 RETVAL = process_object_identifier_sv ();
362 OUTPUT: 478 OUTPUT:
387} 503}
388 OUTPUT: 504 OUTPUT:
389 RETVAL 505 RETVAL
390 506
391SV * 507SV *
392process (SV *self, SV *expected = 0, SV *found = 0) 508process (SV *self, SV *expected = &PL_sv_undef, SV *found = 0)
393 PPCODE: 509 CODE:
394{ 510{
395 U8 type = get8 (); 511 int type;
396 512
397 if (expected && SvOK (expected) && type != SvIV (expected)) 513 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 514
410 if (found) 515 if (found)
411 sv_setiv (found, type); 516 sv_setiv (found, type);
412 517
413 //TODO: switch based on type, to avoid calling overhead 518 if (SvOK (expected) && type != SvIV (expected))
414 SV *res; 519 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} 520}
457 521 OUTPUT:
458#if 0 522 RETVAL
459 523
460MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU 524MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
461 525
462SV * 526SV *
463_process_var_bind_list (SV *self) 527_process_var_bind_list (SV *self)
464 CODE: 528 CODE:
465{ 529{
466 # VarBindList::=SEQUENCE 530 if (get8 () != ASN_SEQUENCE)
467 if (!defined($value = $this->process(SEQUENCE))) { 531 error ("SEQUENCE expected at beginning of VarBindList");
468 return $this->_error; 532 int seqlen = process_length ();
469 } 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);
470 542
471 # Using the length of the VarBindList SEQUENCE, 543 while (cur < end && !errflag)
472 # 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);
473 555
474 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 }
475 560
476 $this->{_var_bind_list} = {}; 561 //return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT);
477 $this->{_var_bind_names} = [];
478 $this->{_var_bind_types} = {};
479 562
480 my ($oid, $type); 563 RETVAL = newRV_inc ((SV *)list);
481
482 while ($this->index < $end) {
483
484 # VarBind::=SEQUENCE
485 if (!defined($this->process(SEQUENCE))) {
486 return $this->_error;
487 }
488 # name::=ObjectName
489 if (!defined($oid = $this->process(OBJECT_IDENTIFIER))) {
490 return $this->_error;
491 }
492 # value::=ObjectSyntax
493 if (!defined($value = $this->process(undef, $type))) {
494 return $this->_error;
495 }
496
497 # Create a hash consisting of the OBJECT IDENTIFIER as a
498 # key and the ObjectSyntax as the value. If there is a
499 # duplicate OBJECT IDENTIFIER in the VarBindList, we pad
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} 564}
565 OUTPUT:
566 RETVAL
527 567
528#endif
529 568

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines