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.13 by root, Thu Jul 29 02:52:07 2010 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
26static SV *cur_bufobj;
30static SV *msg; 27static SV *msg, *bufsv;
31static int errflag; 28static int errflag, leading_dot;
32static U8 *buf, *cur; 29static U8 *buf, *cur;
33static STRLEN len, rem; 30static STRLEN len, rem;
34 31
32typedef SV *BUFOBJ;
33
34/////////////////////////////////////////////////////////////////////////////
35
36#if 0
37 if (msg)
38 croak ("recursive invocation of Net::SNMP::XS parser is not supported");
39
40
41void
42clr_msg ()
43 CODE:
44 SvREFCNT_dec (msg); msg = 0;
45 buf = cur = (U8 *)"";
46 len = rem = 0;
47#endif
48
35static void 49static void
50clear_bufobj (void)
51{
52 // serialise our state back
53 if (msg && SvROK (msg))
54 {
55 SV *idx_sv = *hv_fetch ((HV *)cur_bufobj, "_index" , sizeof ("_index" ) - 1, 1);
56 sv_setiv (idx_sv, cur - buf);
57
58 SvREFCNT_dec (msg);
59 msg = 0;
60 cur_bufobj = 0;
61 }
62}
63
64static void
65switch_bufobj (BUFOBJ neu)
66{
67 clear_bufobj ();
68
69 msg = newSVsv (neu);
70 cur_bufobj = SvRV (msg);
71 sv_rvweaken (msg);
72
73 errflag = 0;
74 leading_dot = -1;
75
76 IV index = SvIV (*hv_fetch ((HV *)cur_bufobj, "_index" , sizeof ("_index" ) - 1, 1));
77 bufsv = *hv_fetch ((HV *)cur_bufobj, "_buffer", sizeof ("_buffer") - 1, 1);
78
79 buf = SvPVbyte (bufsv, len);
80 cur = buf + index;
81 rem = len - index;
82}
83
84/////////////////////////////////////////////////////////////////////////////
85
86static SV *
87x_get_cv (SV *cb_sv)
88{
89 HV *st;
90 GV *gvp;
91 CV *cv = sv_2cv (cb_sv, &st, &gvp, 0);
92
93 if (!cv)
94 croak ("CODE reference expected");
95
96 return (SV *)cv;
97}
98
99static void
36error (const char *msg) 100error (const char *errmsg)
37{ 101{
38 errflag = 1; 102 errflag = 1;
39 103
40 printf ("<<<%s>>>\n", msg);//D 104 if (!msg)
105 croak ("Net::SNMP::XS fatal error, parser called without parsing context");
106
107 dSP;
108 PUSHMARK (SP);
109 EXTEND (SP, 2);
110 PUSHs (msg);
111 PUSHs (sv_2mortal (newSVpv (errmsg, 0)));
112 PUTBACK;
113 call_method ("_error", G_VOID | G_DISCARD);
41} 114}
42 115
43static int 116static int
44need (int count) 117need (int count)
45{ 118{
134 } 207 }
135 208
136 return res; 209 return res;
137} 210}
138 211
212static U32
213process_integer32 (void)
214{
215 U32 length = process_length ();
216
217 if (length <= 0)
218 {
219 error ("INTEGER32 length equal to zero");
220 return 0;
221 }
222
223 U8 *data = getn (length, 0);
224
225 if (!data)
226 return 0;
227
228 if (length > 5 || (length > 4 && data [0]))
229 {
230 error ("INTEGER32 length too long");
231 return 0;
232 }
233
234 U32 res = data [0] & 0x80 ? 0xffffffff : 0;
235
236 while (length--)
237 res = (res << 8) | *data++;
238
239 return res;
240}
241
242static SV *
243process_integer32_sv (void)
244{
245 return newSViv ((I32)process_integer32 ());
246}
247
248static SV *
249process_unsigned32_sv (void)
250{
251 return newSVuv ((U32)process_integer32 ());
252}
253
254#if IVSIZE >= 8
255
256static U64TYPE
257process_integer64 (void)
258{
259 U32 length = process_length ();
260
261 if (length <= 0)
262 {
263 error ("INTEGER64 length equal to zero");
264 return 0;
265 }
266
267 U8 *data = getn (length, 0);
268
269 if (!data)
270 return 0;
271
272 if (length > 9 || (length > 8 && data [0]))
273 {
274 error ("INTEGER64 length too long");
275 return 0;
276 }
277
278 U64TYPE res = data [0] & 0x80 ? 0xffffffffffffffff : 0;
279
280 while (length--)
281 res = (res << 8) | *data++;
282
283 return res;
284}
285
286static SV *
287process_integer64_sv (void)
288{
289 return newSViv ((I64TYPE)process_integer64 ());
290}
291
292static SV *
293process_unsigned64_sv (void)
294{
295 return newSVuv ((U64TYPE)process_integer64 ());
296}
297
298#endif
299
300static SV *
301process_octet_string_sv (void)
302{
303 U32 length = process_length ();
304
305 U8 *data = getn (length, 0);
306 if (!data)
307 {
308 error ("OCTET STRING too long");
309 return &PL_sv_undef;
310 }
311
312 return newSVpvn (data, length);
313}
314
315static char *
316write_uv (char *buf, U32 u)
317{
318 // the one-digit case is absolutely predominant
319 if (u < 10)
320 *buf++ = u + '0';
321 else
322 buf += sprintf (buf, "%u", (unsigned int)u);
323
324 return buf;
325}
326
327static SV *
328process_object_identifier_sv (void)
329{
330 U32 length = process_length ();
331
332 if (length <= 0)
333 {
334 error ("OBJECT IDENTIFIER length equal to zero");
335 return &PL_sv_undef;
336 }
337
338 U8 *end = cur + length;
339 U32 w = getb ();
340
341 static char oid[MAX_OID_STRLEN]; // must be static
342 char *app = oid;
343
344 if (leading_dot < 0)
345 leading_dot = SvTRUE (*hv_fetch ((HV *)SvRV (msg), "_leading_dot", sizeof ("_leading_dot") - 1, 1));
346
347 *app = '.'; app += ! ! leading_dot;
348 app = write_uv (app, (U8)w / 40);
349 *app++ = '.';
350 app = write_uv (app, (U8)w % 40);
351
352 // we assume an oid component is never > 64 bytes
353 while (cur < end && oid + sizeof (oid) - app > 64)
354 {
355 w = getb ();
356 *app++ = '.';
357 app = write_uv (app, w);
358 }
359
360 return newSVpvn (oid, app - oid);
361}
362
363static AV *av_type;
364
365static SV *
366process_sv (int *found)
367{
368 int type = get8 ();
369
370 *found = type;
371
372 SV *res;
373
374 switch (type)
375 {
376 case ASN_OBJECT_IDENTIFIER:
377 res = process_object_identifier_sv ();
378 break;
379
380 case ASN_INTEGER32:
381 res = process_integer32_sv ();
382 break;
383
384 case ASN_UNSIGNED32:
385 case ASN_COUNTER32:
386 case ASN_TIMETICKS:
387 res = process_unsigned32_sv ();
388 break;
389
390 case ASN_SEQUENCE:
391 res = newSVuv (process_length ());
392 break;
393
394 case ASN_OCTET_STRING:
395 case ASN_OPAQUE:
396 res = process_octet_string_sv ();
397 break;
398
399 default:
400 {
401 if (type > AvFILLp (av_type) || SvTYPE (AvARRAY (av_type)[type]) != SVt_PVCV)
402 {
403 error ("Unknown ASN.1 type");
404 return &PL_sv_undef;
405 }
406
407 dSP;
408 PUSHMARK (SP);
409 EXTEND (SP, 2);
410 PUSHs (msg);
411 PUSHs (sv_2mortal (newSViv (type)));
412 PUTBACK;
413 int count = call_sv (AvARRAY (av_type)[type], G_SCALAR);
414 SPAGAIN;
415 res = count ? SvREFCNT_inc (TOPs) : &PL_sv_undef;
416 }
417 }
418
419 return errflag ? &PL_sv_undef : res;
420}
421
422/////////////////////////////////////////////////////////////////////////////
423
424#if HAVE_VERSIONSORT
425
426static int
427oid_lex_cmp (const void *a_, const void *b_)
428{
429 const char *a = SvPVX (*(SV **)a_);
430 const char *b = SvPVX (*(SV **)b_);
431
432 a += *a == '.';
433 b += *b == '.';
434
435 return strverscmp (a, b);
436}
437
438#endif
439
139MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS 440MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
140 441
442PROTOTYPES: ENABLE
443
444BOOT:
445 av_type = newAV ();
446
141void 447void
142set_msg (SV *msg_, SV *buf_) 448set_type (int type, SV *cv)
143 CODE: 449 CODE:
144 errflag = 0; 450 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
145 msg = SvREFCNT_inc (msg_); 451
146 buf = SvPVbyte (buf_, len); 452void xxx(...)
147 cur = buf; 453 CODE:
148 rem = len; 454 clear_bufobj ();
149#ifdef BENCHMARK 455
150 t1 = tstamp (); 456MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::Message
151#endif
152 457
153void 458void
154clr_msg () 459_buffer_append (BUFOBJ self, SV *value)
460 ALIAS:
461 _buffer_put = 1
155 CODE: 462 PPCODE:
156 SvREFCNT_dec (msg); 463{
157 buf = cur = ""; 464 STRLEN vlen;
158 len = rem = 0; 465 const char *vstr = SvPVbyte (value, vlen);
159#ifdef BENCHMARK
160 printf ("%f\n", tstamp () - t1);//D
161#endif
162 466
163MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::Message 467 if (ix)
468 sv_insert (bufsv, 0, 0, vstr, vlen);
469 else
470 sv_catpvn (bufsv, vstr, vlen);
471
472 buf = SvPVbyte (bufsv, len);
473 cur = buf;
474 rem = len;
475
476 SV *len_sv = *hv_fetch ((HV *)cur_bufobj, "_length", sizeof ("_length") - 1, 1);
477 sv_setiv (len_sv, len);
478
479 // some callers test for defined'ness of the returnvalue. *sigh*
480 XPUSHs (&PL_sv_yes);
481}
164 482
165void 483void
166_buffer_get (SV *self, int count = -1) 484_buffer_get (BUFOBJ self, int count = -1)
167 PPCODE: 485 PPCODE:
168{ 486{
169 // grrr. 487 // grrr.
170 if (count < 0) 488 if (count < 0)
171 { 489 {
172 hv_delete ((HV *)SvRV (self), "_index" , 6, G_DISCARD); 490 hv_delete ((HV *)SvRV (self), "_index" , 6, G_DISCARD);
173 hv_delete ((HV *)SvRV (self), "_length", 7, G_DISCARD); 491 hv_delete ((HV *)SvRV (self), "_length", 7, G_DISCARD);
174 SV **svp = hv_fetch ((HV *)SvRV (self), "_buffer", 7, 1);
175 XPUSHs (sv_2mortal (newSVsv (*svp))); 492 XPUSHs (sv_2mortal (newSVsv (bufsv)));
176 sv_setpvn (*svp, "", 0); 493 sv_setpvn (bufsv, "", 0);
494
495 buf = "";
496 cur = buf;
497 rem = 0;
498
177 XSRETURN (1); 499 XSRETURN (1);
178 } 500 }
179 501
180 char *data = getn (count, 0); 502 char *data = getn (count, 0);
181 503
182 if (data) 504 if (data)
183 XPUSHs (sv_2mortal (newSVpvn (data, count))); 505 XPUSHs (sv_2mortal (newSVpvn (data, count)));
184} 506}
185 507
186U32 508U32
187index (SV *self, int ndx = -1) 509index (BUFOBJ self, int ndx = -1)
188 CODE: 510 CODE:
189{ 511{
190 if (ndx >= 0 && ndx < len) 512 if (ndx >= 0 && ndx < len)
191 { 513 {
192 cur = buf + ndx; 514 cur = buf + ndx;
197} 519}
198 OUTPUT: 520 OUTPUT:
199 RETVAL 521 RETVAL
200 522
201U32 523U32
202_process_length (SV *self, ...) 524_process_length (BUFOBJ self, ...)
203 ALIAS: 525 ALIAS:
204 _process_sequence = 1 526 _process_sequence = 0
205 CODE: 527 CODE:
206 RETVAL = process_length (); 528 RETVAL = process_length ();
207 OUTPUT: 529 OUTPUT:
208 RETVAL 530 RETVAL
209 531
210I32 532SV *
211_process_integer32 (SV *self, ...) 533_process_integer32 (BUFOBJ self, ...)
534 CODE:
535 RETVAL = process_integer32_sv ();
536 OUTPUT:
537 RETVAL
538
539SV *
540_process_counter (BUFOBJ self, ...)
212 ALIAS: 541 ALIAS:
213 _process_counter = 0
214 _process_gauge = 0 542 _process_gauge = 0
543 _process_timeticks = 0
215 CODE: 544 CODE:
216{ 545 RETVAL = process_unsigned32_sv ();
217 U32 length = process_length (); 546 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; 547 RETVAL
242} 548
243 OUTPUT: 549#if IVSIZE >= 8
244 RETVAL
245 550
246SV * 551SV *
247_process_object_identifier (SV *self, ...) 552_process_counter64 (BUFOBJ self, ...)
248 CODE: 553 CODE:
249{ 554 RETVAL = process_unsigned64_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: 555 OUTPUT:
272 RETVAL 556 RETVAL
557
558#endif
273 559
274SV * 560SV *
561_process_object_identifier (BUFOBJ self, ...)
562 CODE:
563 RETVAL = process_object_identifier_sv ();
564 OUTPUT:
565 RETVAL
566
567SV *
275_process_octet_string (SV *self, ...) 568_process_octet_string (BUFOBJ self, ...)
276 ALIAS: 569 ALIAS:
277 _process_opaque = 0 570 _process_opaque = 0
278 CODE: 571 CODE:
279{ 572 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: 573 OUTPUT:
292 RETVAL 574 RETVAL
293 575
294SV * 576SV *
295_process_ipaddress (SV *self, ...) 577_process_ipaddress (BUFOBJ self, ...)
296 CODE: 578 CODE:
297{ 579{
298 U32 length = process_length (); 580 U32 length = process_length ();
299 if (length != 4) 581 if (length != 4)
300 { 582 {
306 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]); 588 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]);
307} 589}
308 OUTPUT: 590 OUTPUT:
309 RETVAL 591 RETVAL
310 592
593SV *
594process (BUFOBJ self, SV *expected = &PL_sv_undef, SV *found = 0)
595 CODE:
596{
597 int type;
598
599 RETVAL = process_sv (&type);
600
601 if (found)
602 sv_setiv (found, type);
603
604 if (SvOK (expected) && type != SvIV (expected))
605 error ("Expected a different type than found");
606}
607 OUTPUT:
608 RETVAL
609
610MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
611
612SV *
613_process_var_bind_list (BUFOBJ self)
614 CODE:
615{
616 if (get8 () != ASN_SEQUENCE)
617 error ("SEQUENCE expected at beginning of VarBindList");
618 int seqlen = process_length ();
619 U8 *end = cur + seqlen;
620
621 HV *list = newHV ();
622 AV *names = newAV ();
623 HV *types = newHV ();
624
625 hv_store ((HV *)cur_bufobj, "_var_bind_list" , sizeof ("_var_bind_list" ) - 1, newRV_noinc ((SV *)list ), 0);
626 hv_store ((HV *)cur_bufobj, "_var_bind_names", sizeof ("_var_bind_names") - 1, newRV_noinc ((SV *)names), 0);
627 hv_store ((HV *)cur_bufobj, "_var_bind_types", sizeof ("_var_bind_types") - 1, newRV_noinc ((SV *)types), 0);
628
629 while (cur < end && !errflag)
630 {
631 // SEQUENCE ObjectName ObjectSyntax
632 if (get8 () != ASN_SEQUENCE)
633 error ("SEQUENCE expected at beginning of VarBind");
634 process_length ();
635
636 if (get8 () != ASN_OBJECT_IDENTIFIER)
637 error ("OBJECT IDENTIFIER expected at beginning of VarBind");
638 int type, oidlen;
639 SV *oid = process_object_identifier_sv ();
640 SV *val = process_sv (&type);
641
642 hv_store_ent (types, oid, newSViv (type), 0);
643 hv_store_ent (list , oid, val, 0);
644 av_push (names, oid);
645 }
646
647 // sigh - great design to do it here
648 SV *pdu_type = *hv_fetch ((HV *)cur_bufobj, "_pdu_type" , sizeof ("_pdu_type" ) - 1, 1);
649
650 if (SvIV (pdu_type) == 0xa8) // REPORT
651 {
652 PUSHMARK (SP);
653 XPUSHs (msg);
654 PUTBACK;
655 call_method ("_report_pdu_error", G_VOID | G_DISCARD);
656 SPAGAIN;
657 XSRETURN_EMPTY;
658 }
659
660 RETVAL = newRV_inc ((SV *)list);
661}
662 OUTPUT:
663 RETVAL
664
665MODULE = Net::SNMP::XS PACKAGE = Net::SNMP
666
667void
668oid_base_match (SV *base_, SV *oid_)
669 PROTOTYPE: $$
670 ALIAS:
671 oid_context_match = 0
672 PPCODE:
673{
674 if (!SvOK (base_) || !SvOK (oid_))
675 XSRETURN_NO;
676
677 STRLEN blen, olen;
678 char *base = SvPVbyte (base_, blen);
679 char *oid = SvPVbyte (oid_ , olen);
680
681 blen -= *base == '.'; base += *base == '.';
682 olen -= *base == '.'; oid += *oid == '.';
683
684 if (olen < blen)
685 XSRETURN_NO;
686
687 if (memcmp (base, oid, blen))
688 XSRETURN_NO;
689
690 if (oid [blen] && oid [blen] != '.')
691 XSRETURN_NO;
692
693 XSRETURN_YES;
694}
695
696#if HAVE_VERSIONSORT
697
698void
699oid_lex_sort (...)
700 PROTOTYPE: @
701 PPCODE:
702{
703 // make sure SvPVX is valid
704 int i;
705 for (i = items; i--; )
706 {
707 SV *sv = ST (i);
708
709 if (SvTYPE (sv) < SVt_PV || SvTYPE (sv) == SVt_PVAV && SvTYPE (sv) == SVt_PVHV)
710 SvPV_force_nolen (sv);
711 }
712
713 qsort (&ST (0), items, sizeof (SV *), oid_lex_cmp);
714
715 EXTEND (SP, items);
716 // we cheat somewhat by not returning copies here
717 for (i = 0; i < items; ++i)
718 PUSHs (sv_2mortal (SvREFCNT_inc (ST (i))));
719}
720
721int
722_index_cmp (const char *a, const char *b)
723 PROTOTYPE: $$
724 CODE:
725 RETVAL = strverscmp (a, b);
726 OUTPUT:
727 RETVAL
728
729#endif
730

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines