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.15 by root, Thu Sep 18 02:58:42 2014 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
59 SvREFCNT_dec (msg);
60 msg = 0;
61 cur_bufobj = 0;
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); 452MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::Message
147 cur = buf;
148 rem = len;
149#ifdef BENCHMARK
150 t1 = tstamp ();
151#endif
152 453
153void 454void
154clr_msg () 455_buffer_append (BUFOBJ self, SV *value)
456 ALIAS:
457 _buffer_put = 1
155 CODE: 458 PPCODE:
156 SvREFCNT_dec (msg); 459{
157 buf = cur = ""; 460 STRLEN vlen;
158 len = rem = 0; 461 const char *vstr = SvPVbyte (value, vlen);
159#ifdef BENCHMARK
160 printf ("%f\n", tstamp () - t1);//D
161#endif
162 462
163MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::Message 463 if (ix)
464 sv_insert (bufsv, 0, 0, vstr, vlen);
465 else
466 sv_catpvn (bufsv, vstr, vlen);
467
468 buf = SvPVbyte (bufsv, len);
469 cur = buf;
470 rem = len;
471
472 SV *len_sv = *hv_fetch ((HV *)cur_bufobj, "_length", sizeof ("_length") - 1, 1);
473 sv_setiv (len_sv, len);
474
475 // some callers test for defined'ness of the returnvalue. *sigh*
476 XPUSHs (&PL_sv_yes);
477}
164 478
165void 479void
166_buffer_get (SV *self, int count = -1) 480_buffer_get (BUFOBJ self, int count = -1)
167 PPCODE: 481 PPCODE:
168{ 482{
169 // grrr. 483 // grrr.
170 if (count < 0) 484 if (count < 0)
171 { 485 {
172 hv_delete ((HV *)SvRV (self), "_index" , 6, G_DISCARD); 486 hv_delete ((HV *)SvRV (self), "_index" , 6, G_DISCARD);
173 hv_delete ((HV *)SvRV (self), "_length", 7, G_DISCARD); 487 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))); 488 XPUSHs (sv_2mortal (newSVsv (bufsv)));
176 sv_setpvn (*svp, "", 0); 489 sv_setpvn (bufsv, "", 0);
490
491 buf = "";
492 cur = buf;
493 rem = 0;
494
177 XSRETURN (1); 495 XSRETURN (1);
178 } 496 }
179 497
180 char *data = getn (count, 0); 498 char *data = getn (count, 0);
181 499
182 if (data) 500 if (data)
183 XPUSHs (sv_2mortal (newSVpvn (data, count))); 501 XPUSHs (sv_2mortal (newSVpvn (data, count)));
184} 502}
185 503
186U32 504U32
187index (SV *self, int ndx = -1) 505index (BUFOBJ self, int ndx = -1)
188 CODE: 506 CODE:
189{ 507{
190 if (ndx >= 0 && ndx < len) 508 if (ndx >= 0 && ndx < len)
191 { 509 {
192 cur = buf + ndx; 510 cur = buf + ndx;
197} 515}
198 OUTPUT: 516 OUTPUT:
199 RETVAL 517 RETVAL
200 518
201U32 519U32
202_process_length (SV *self, ...) 520_process_length (BUFOBJ self, ...)
203 ALIAS: 521 ALIAS:
204 _process_sequence = 1 522 _process_sequence = 0
205 CODE: 523 CODE:
206 RETVAL = process_length (); 524 RETVAL = process_length ();
207 OUTPUT: 525 OUTPUT:
208 RETVAL 526 RETVAL
209 527
210I32 528SV *
211_process_integer32 (SV *self, ...) 529_process_integer32 (BUFOBJ self, ...)
530 CODE:
531 RETVAL = process_integer32_sv ();
532 OUTPUT:
533 RETVAL
534
535SV *
536_process_counter (BUFOBJ self, ...)
212 ALIAS: 537 ALIAS:
213 _process_counter = 0
214 _process_gauge = 0 538 _process_gauge = 0
539 _process_timeticks = 0
215 CODE: 540 CODE:
216{ 541 RETVAL = process_unsigned32_sv ();
217 U32 length = process_length (); 542 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; 543 RETVAL
242} 544
243 OUTPUT: 545#if IVSIZE >= 8
244 RETVAL
245 546
246SV * 547SV *
247_process_object_identifier (SV *self, ...) 548_process_counter64 (BUFOBJ self, ...)
248 CODE: 549 CODE:
249{ 550 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: 551 OUTPUT:
272 RETVAL 552 RETVAL
553
554#endif
273 555
274SV * 556SV *
557_process_object_identifier (BUFOBJ self, ...)
558 CODE:
559 RETVAL = process_object_identifier_sv ();
560 OUTPUT:
561 RETVAL
562
563SV *
275_process_octet_string (SV *self, ...) 564_process_octet_string (BUFOBJ self, ...)
276 ALIAS: 565 ALIAS:
277 _process_opaque = 0 566 _process_opaque = 0
278 CODE: 567 CODE:
279{ 568 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: 569 OUTPUT:
292 RETVAL 570 RETVAL
293 571
294SV * 572SV *
295_process_ipaddress (SV *self, ...) 573_process_ipaddress (BUFOBJ self, ...)
296 CODE: 574 CODE:
297{ 575{
298 U32 length = process_length (); 576 U32 length = process_length ();
299 if (length != 4) 577 if (length != 4)
300 { 578 {
306 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]); 584 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]);
307} 585}
308 OUTPUT: 586 OUTPUT:
309 RETVAL 587 RETVAL
310 588
589SV *
590process (BUFOBJ self, SV *expected = &PL_sv_undef, SV *found = 0)
591 CODE:
592{
593 int type;
594
595 RETVAL = process_sv (&type);
596
597 if (found)
598 sv_setiv (found, type);
599
600 if (SvOK (expected) && type != SvIV (expected))
601 error ("Expected a different type than found");
602}
603 OUTPUT:
604 RETVAL
605
606MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
607
608SV *
609_process_var_bind_list (BUFOBJ self)
610 CODE:
611{
612 if (get8 () != ASN_SEQUENCE)
613 error ("SEQUENCE expected at beginning of VarBindList");
614 int seqlen = process_length ();
615 U8 *end = cur + seqlen;
616
617 HV *list = newHV ();
618 AV *names = newAV ();
619 HV *types = newHV ();
620
621 hv_store ((HV *)cur_bufobj, "_var_bind_list" , sizeof ("_var_bind_list" ) - 1, newRV_noinc ((SV *)list ), 0);
622 hv_store ((HV *)cur_bufobj, "_var_bind_names", sizeof ("_var_bind_names") - 1, newRV_noinc ((SV *)names), 0);
623 hv_store ((HV *)cur_bufobj, "_var_bind_types", sizeof ("_var_bind_types") - 1, newRV_noinc ((SV *)types), 0);
624
625 while (cur < end && !errflag)
626 {
627 // SEQUENCE ObjectName ObjectSyntax
628 if (get8 () != ASN_SEQUENCE)
629 error ("SEQUENCE expected at beginning of VarBind");
630 process_length ();
631
632 if (get8 () != ASN_OBJECT_IDENTIFIER)
633 error ("OBJECT IDENTIFIER expected at beginning of VarBind");
634 int type, oidlen;
635 SV *oid = process_object_identifier_sv ();
636 SV *val = process_sv (&type);
637
638 hv_store_ent (types, oid, newSViv (type), 0);
639 hv_store_ent (list , oid, val, 0);
640 av_push (names, oid);
641 }
642
643 // sigh - great design to do it here
644 SV *pdu_type = *hv_fetch ((HV *)cur_bufobj, "_pdu_type" , sizeof ("_pdu_type" ) - 1, 1);
645
646 if (SvIV (pdu_type) == 0xa8) // REPORT
647 {
648 PUSHMARK (SP);
649 XPUSHs (msg);
650 PUTBACK;
651 call_method ("_report_pdu_error", G_VOID | G_DISCARD);
652 SPAGAIN;
653 XSRETURN_EMPTY;
654 }
655
656 RETVAL = newRV_inc ((SV *)list);
657}
658 OUTPUT:
659 RETVAL
660
661MODULE = Net::SNMP::XS PACKAGE = Net::SNMP
662
663void
664oid_base_match (SV *base_, SV *oid_)
665 PROTOTYPE: $$
666 ALIAS:
667 oid_context_match = 0
668 PPCODE:
669{
670 if (!SvOK (base_) || !SvOK (oid_))
671 XSRETURN_NO;
672
673 STRLEN blen, olen;
674 char *base = SvPVbyte (base_, blen);
675 char *oid = SvPVbyte (oid_ , olen);
676
677 blen -= *base == '.'; base += *base == '.';
678 olen -= *base == '.'; oid += *oid == '.';
679
680 if (olen < blen)
681 XSRETURN_NO;
682
683 if (memcmp (base, oid, blen))
684 XSRETURN_NO;
685
686 if (oid [blen] && oid [blen] != '.')
687 XSRETURN_NO;
688
689 XSRETURN_YES;
690}
691
692#if HAVE_VERSIONSORT
693
694void
695oid_lex_sort (...)
696 PROTOTYPE: @
697 PPCODE:
698{
699 // make sure SvPVX is valid
700 int i;
701 for (i = items; i--; )
702 {
703 SV *sv = ST (i);
704
705 if (SvTYPE (sv) < SVt_PV || SvTYPE (sv) == SVt_PVAV && SvTYPE (sv) == SVt_PVHV)
706 SvPV_force_nolen (sv);
707 }
708
709 qsort (&ST (0), items, sizeof (SV *), oid_lex_cmp);
710
711 EXTEND (SP, items);
712 // we cheat somewhat by not returning copies here
713 for (i = 0; i < items; ++i)
714 PUSHs (sv_2mortal (SvREFCNT_inc (ST (i))));
715}
716
717int
718_index_cmp (const char *a, const char *b)
719 PROTOTYPE: $$
720 CODE:
721 RETVAL = strverscmp (a, b);
722 OUTPUT:
723 RETVAL
724
725#endif
726

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines