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.10 by root, Sat Apr 11 06:24:18 2009 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
30static SV *msg; 26static SV *msg;
31static int errflag; 27static int errflag, leading_dot;
32static U8 *buf, *cur; 28static U8 *buf, *cur;
33static STRLEN len, rem; 29static STRLEN len, rem;
34 30
31static SV *
32x_get_cv (SV *cb_sv)
33{
34 HV *st;
35 GV *gvp;
36 CV *cv = sv_2cv (cb_sv, &st, &gvp, 0);
37
38 if (!cv)
39 croak ("CODE reference expected");
40
41 return (SV *)cv;
42}
43
35static void 44static void
36error (const char *msg) 45error (const char *errmsg)
37{ 46{
38 errflag = 1; 47 errflag = 1;
39 48
40 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);
41} 59}
42 60
43static int 61static int
44need (int count) 62need (int count)
45{ 63{
134 } 152 }
135 153
136 return res; 154 return res;
137} 155}
138 156
157static U32
158process_integer32 (void)
159{
160 U32 length = process_length ();
161
162 if (length <= 0)
163 {
164 error ("INTEGER32 length equal to zero");
165 return 0;
166 }
167
168 U8 *data = getn (length, 0);
169
170 if (!data)
171 return 0;
172
173 if (length > 5 || (length > 4 && data [0]))
174 {
175 error ("INTEGER32 length too long");
176 return 0;
177 }
178
179 U32 res = data [0] & 0x80 ? 0xffffffff : 0;
180
181 while (length--)
182 res = (res << 8) | *data++;
183
184 return res;
185}
186
187static SV *
188process_integer32_sv (void)
189{
190 return newSViv ((I32)process_integer32 ());
191}
192
193static SV *
194process_unsigned32_sv (void)
195{
196 return newSVuv ((U32)process_integer32 ());
197}
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
245static SV *
246process_octet_string_sv (void)
247{
248 U32 length = process_length ();
249
250 U8 *data = getn (length, 0);
251 if (!data)
252 {
253 error ("OCTET STRING too long");
254 return &PL_sv_undef;
255 }
256
257 return newSVpvn (data, length);
258}
259
260static char *
261write_uv (char *buf, U32 u)
262{
263 // the one-digit case is absolutely predominant
264 if (u < 10)
265 *buf++ = u + '0';
266 else
267 buf += sprintf (buf, "%u", (unsigned int)u);
268
269 return buf;
270}
271
272static SV *
273process_object_identifier_sv (void)
274{
275 U32 length = process_length ();
276
277 if (length <= 0)
278 {
279 error ("OBJECT IDENTIFIER length equal to zero");
280 return &PL_sv_undef;
281 }
282
283 U8 *end = cur + length;
284 U32 w = getb ();
285
286 static char oid[MAX_OID_STRLEN]; // must be static
287 char *app = oid;
288
289 *app = '.'; app += ! ! leading_dot;
290 app = write_uv (app, (U8)w / 40);
291 *app++ = '.';
292 app = write_uv (app, (U8)w % 40);
293
294 // we assume an oid component is never > 64 bytes
295 while (cur < end && oid + sizeof (oid) - app > 64)
296 {
297 w = getb ();
298 *app++ = '.';
299 app = write_uv (app, w);
300 }
301
302 return newSVpvn (oid, app - oid);
303}
304
305static AV *av_type;
306
307static SV *
308process_sv (int *found)
309{
310 int type = get8 ();
311
312 *found = type;
313
314 SV *res;
315
316 switch (type)
317 {
318 case ASN_OBJECT_IDENTIFIER:
319 res = process_object_identifier_sv ();
320 break;
321
322 case ASN_INTEGER32:
323 res = process_integer32_sv ();
324 break;
325
326 case ASN_UNSIGNED32:
327 case ASN_COUNTER32:
328 case ASN_TIMETICKS:
329 res = process_unsigned32_sv ();
330 break;
331
332 case ASN_SEQUENCE:
333 res = newSVuv (process_length ());
334 break;
335
336 case ASN_OCTET_STRING:
337 case ASN_OPAQUE:
338 res = process_octet_string_sv ();
339 break;
340
341 default:
342 {
343 if (type > AvFILLp (av_type) || !SvTYPE (AvARRAY (av_type)[type]) == SVt_PVCV)
344 {
345 error ("Unknown ASN.1 type");
346 return &PL_sv_undef;
347 }
348
349 dSP;
350 PUSHMARK (SP);
351 EXTEND (SP, 2);
352 PUSHs (msg);
353 PUSHs (sv_2mortal (newSViv (type)));
354 PUTBACK;
355 int count = call_sv (AvARRAY (av_type)[type], G_SCALAR);
356 SPAGAIN;
357 res = count ? SvREFCNT_inc (TOPs) : &PL_sv_undef;
358 }
359 }
360
361 return errflag ? &PL_sv_undef : res;
362}
363
364/////////////////////////////////////////////////////////////////////////////
365
366#if HAVE_VERSIONSORT
367
368static int
369oid_lex_cmp (const void *a_, const void *b_)
370{
371 const char *a = SvPVX (*(SV **)a_);
372 const char *b = SvPVX (*(SV **)b_);
373
374 a += *a == '.';
375 b += *b == '.';
376
377 return strverscmp (a, b);
378}
379
380#endif
381
139MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS 382MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
383
384PROTOTYPES: ENABLE
385
386BOOT:
387 av_type = newAV ();
388
389void
390set_type (int type, SV *cv)
391 CODE:
392 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
140 393
141void 394void
142set_msg (SV *msg_, SV *buf_) 395set_msg (SV *msg_, SV *buf_)
143 CODE: 396 CODE:
397{
398 if (msg)
399 croak ("recursive invocation of Net::SNMP::XS parser is not supported");
400
144 errflag = 0; 401 errflag = 0;
402 leading_dot = -1;
145 msg = SvREFCNT_inc (msg_); 403 msg = SvREFCNT_inc (msg_);
146 buf = SvPVbyte (buf_, len); 404 buf = SvPVbyte (buf_, len);
147 cur = buf; 405 cur = buf;
148 rem = len; 406 rem = len;
149#ifdef BENCHMARK 407#ifdef BENCHMARK
150 t1 = tstamp (); 408 t1 = tstamp ();
151#endif 409#endif
410}
152 411
153void 412void
154clr_msg () 413clr_msg ()
155 CODE: 414 CODE:
156 SvREFCNT_dec (msg); 415 SvREFCNT_dec (msg); msg = 0;
157 buf = cur = ""; 416 buf = cur = (U8 *)"";
158 len = rem = 0; 417 len = rem = 0;
159#ifdef BENCHMARK 418#ifdef BENCHMARK
160 printf ("%f\n", tstamp () - t1);//D 419 printf ("%f\n", tstamp () - t1);//D
161#endif 420#endif
162 421
199 RETVAL 458 RETVAL
200 459
201U32 460U32
202_process_length (SV *self, ...) 461_process_length (SV *self, ...)
203 ALIAS: 462 ALIAS:
204 _process_sequence = 1 463 _process_sequence = 0
205 CODE: 464 CODE:
206 RETVAL = process_length (); 465 RETVAL = process_length ();
207 OUTPUT: 466 OUTPUT:
208 RETVAL 467 RETVAL
209 468
210I32 469SV *
211_process_integer32 (SV *self, ...) 470_process_integer32 (SV *self, ...)
471 CODE:
472 RETVAL = process_integer32_sv ();
473 OUTPUT:
474 RETVAL
475
476SV *
477_process_counter (SV *self, ...)
212 ALIAS: 478 ALIAS:
213 _process_counter = 0
214 _process_gauge = 0 479 _process_gauge = 0
480 _process_timeticks = 0
215 CODE: 481 CODE:
216{ 482 RETVAL = process_unsigned32_sv ();
217 U32 length = process_length (); 483 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; 484 RETVAL
242} 485
486#if IVSIZE >= 8
487
488SV *
489_process_counter64 (SV *self, ...)
490 CODE:
491 RETVAL = process_unsigned64_sv ();
243 OUTPUT: 492 OUTPUT:
244 RETVAL 493 RETVAL
494
495#endif
245 496
246SV * 497SV *
247_process_object_identifier (SV *self, ...) 498_process_object_identifier (SV *self, ...)
248 CODE: 499 CODE:
249{ 500 RETVAL = process_object_identifier_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: 501 OUTPUT:
272 RETVAL 502 RETVAL
273 503
274SV * 504SV *
275_process_octet_string (SV *self, ...) 505_process_octet_string (SV *self, ...)
276 ALIAS: 506 ALIAS:
277 _process_opaque = 0 507 _process_opaque = 0
278 CODE: 508 CODE:
279{ 509 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: 510 OUTPUT:
292 RETVAL 511 RETVAL
293 512
294SV * 513SV *
295_process_ipaddress (SV *self, ...) 514_process_ipaddress (SV *self, ...)
306 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]); 525 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]);
307} 526}
308 OUTPUT: 527 OUTPUT:
309 RETVAL 528 RETVAL
310 529
530SV *
531process (SV *self, SV *expected = &PL_sv_undef, SV *found = 0)
532 CODE:
533{
534 int type;
535
536 RETVAL = process_sv (&type);
537
538 if (found)
539 sv_setiv (found, type);
540
541 if (SvOK (expected) && type != SvIV (expected))
542 error ("Expected a different type than found");
543}
544 OUTPUT:
545 RETVAL
546
547MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
548
549SV *
550_process_var_bind_list (SV *self)
551 CODE:
552{
553 if (get8 () != ASN_SEQUENCE)
554 error ("SEQUENCE expected at beginning of VarBindList");
555 int seqlen = process_length ();
556 U8 *end = cur + seqlen;
557
558 HV *list = newHV ();
559 AV *names = newAV ();
560 HV *types = newHV ();
561
562 hv_store ((HV *)SvRV (self), "_var_bind_list" , sizeof ("_var_bind_list" ) - 1, newRV_noinc ((SV *)list ), 0);
563 hv_store ((HV *)SvRV (self), "_var_bind_names", sizeof ("_var_bind_names") - 1, newRV_noinc ((SV *)names), 0);
564 hv_store ((HV *)SvRV (self), "_var_bind_types", sizeof ("_var_bind_types") - 1, newRV_noinc ((SV *)types), 0);
565
566 while (cur < end && !errflag)
567 {
568 // SEQUENCE ObjectName ObjectSyntax
569 if (get8 () != ASN_SEQUENCE)
570 error ("SEQUENCE expected at beginning of VarBind");
571 process_length ();
572
573 if (get8 () != ASN_OBJECT_IDENTIFIER)
574 error ("OBJECT IDENTIFIER expected at beginning of VarBind");
575 int type, oidlen;
576 SV *oid = process_object_identifier_sv ();
577 SV *val = process_sv (&type);
578
579 hv_store_ent (types, oid, newSViv (type), 0);
580 hv_store_ent (list , oid, val, 0);
581 av_push (names, oid);
582 }
583
584 //return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT);
585
586 RETVAL = newRV_inc ((SV *)list);
587}
588 OUTPUT:
589 RETVAL
590
591MODULE = Net::SNMP::XS PACKAGE = Net::SNMP
592
593void
594oid_base_match (SV *base_, SV *oid_)
595 PROTOTYPE: $$
596 ALIAS:
597 oid_context_match = 0
598 PPCODE:
599{
600 if (!SvOK (base_) || !SvOK (oid_))
601 XSRETURN_NO;
602
603 STRLEN blen, olen;
604 char *base = SvPV (base_, blen);
605 char *oid = SvPV (oid_ , olen);
606
607 blen -= *base == '.'; base += *base == '.';
608 olen -= *base == '.'; oid += *oid == '.';
609
610 if (olen < blen)
611 XSRETURN_NO;
612
613 if (memcmp (base, oid, blen))
614 XSRETURN_NO;
615
616 if (oid [blen] && oid [blen] != '.')
617 XSRETURN_NO;
618
619 XSRETURN_YES;
620}
621
622#if HAVE_VERSIONSORT
623
624void
625oid_lex_sort (...)
626 PROTOTYPE: @
627 PPCODE:
628{
629 // make sure SvPVX is valid
630 int i;
631 for (i = items; i--; )
632 {
633 SV *sv = ST (i);
634
635 if (SvTYPE (sv) < SVt_PV || SvTYPE (sv) == SVt_PVAV && SvTYPE (sv) == SVt_PVHV)
636 SvPV_force_nolen (sv);
637 }
638
639 qsort (&ST (0), items, sizeof (SV *), oid_lex_cmp);
640
641 EXTEND (SP, items);
642 // we cheat somewhat by not returning copies here
643 for (i = 0; i < items; ++i)
644 PUSHs (sv_2mortal (SvREFCNT_inc (ST (i))));
645}
646
647int
648_index_cmp (const char *a, const char *b)
649 PROTOTYPE: $$
650 CODE:
651 RETVAL = strverscmp (a, b);
652 OUTPUT:
653 RETVAL
654
655#endif
656

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines