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.9 by root, Sat Apr 11 04:22:49 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
30static SV *msg; 24static SV *msg;
31static int errflag; 25static int errflag, leading_dot;
32static U8 *buf, *cur; 26static U8 *buf, *cur;
33static STRLEN len, rem; 27static STRLEN len, rem;
34 28
29static SV *
30x_get_cv (SV *cb_sv)
31{
32 HV *st;
33 GV *gvp;
34 CV *cv = sv_2cv (cb_sv, &st, &gvp, 0);
35
36 if (!cv)
37 croak ("CODE reference expected");
38
39 return (SV *)cv;
40}
41
35static void 42static void
36error (const char *msg) 43error (const char *errmsg)
37{ 44{
38 errflag = 1; 45 errflag = 1;
39 46
40 printf ("<<<%s>>>\n", msg);//D 47 if (!msg)
48 croak ("Net::SNMP::XS fatal error, parser called without parsing context");
49
50 dSP;
51 PUSHMARK (SP);
52 EXTEND (SP, 2);
53 PUSHs (msg);
54 PUSHs (sv_2mortal (newSVpv (errmsg, 0)));
55 PUTBACK;
56 call_method ("_error", G_VOID | G_DISCARD);
41} 57}
42 58
43static int 59static int
44need (int count) 60need (int count)
45{ 61{
134 } 150 }
135 151
136 return res; 152 return res;
137} 153}
138 154
155static U32
156process_integer32 (void)
157{
158 U32 length = process_length ();
159
160 if (length <= 0)
161 {
162 error ("INTEGER32 length equal to zero");
163 return 0;
164 }
165
166 U8 *data = getn (length, 0);
167
168 if (!data)
169 return 0;
170
171 if (length > 5 || (length > 4 && data [0]))
172 {
173 error ("INTEGER32 length too long");
174 return 0;
175 }
176
177 U32 res = data [0] & 0x80 ? 0xffffffff : 0;
178
179 while (length--)
180 res = (res << 8) | *data++;
181
182 return res;
183}
184
185static SV *
186process_integer32_sv (void)
187{
188 return newSViv ((I32)process_integer32 ());
189}
190
191static SV *
192process_unsigned32_sv (void)
193{
194 return newSVuv ((U32)process_integer32 ());
195}
196
197#if IVSIZE >= 8
198
199static U64TYPE
200process_integer64 (void)
201{
202 U32 length = process_length ();
203
204 if (length <= 0)
205 {
206 error ("INTEGER64 length equal to zero");
207 return 0;
208 }
209
210 U8 *data = getn (length, 0);
211
212 if (!data)
213 return 0;
214
215 if (length > 9 || (length > 8 && data [0]))
216 {
217 error ("INTEGER64 length too long");
218 return 0;
219 }
220
221 U64TYPE res = data [0] & 0x80 ? 0xffffffffffffffff : 0;
222
223 while (length--)
224 res = (res << 8) | *data++;
225
226 return res;
227}
228
229static SV *
230process_integer64_sv (void)
231{
232 return newSViv ((I64TYPE)process_integer64 ());
233}
234
235static SV *
236process_unsigned64_sv (void)
237{
238 return newSVuv ((U64TYPE)process_integer64 ());
239}
240
241#endif
242
243static SV *
244process_octet_string_sv (void)
245{
246 U32 length = process_length ();
247
248 U8 *data = getn (length, 0);
249 if (!data)
250 {
251 error ("OCTET STRING too long");
252 return &PL_sv_undef;
253 }
254
255 return newSVpvn (data, length);
256}
257
258static char *
259write_uv (char *buf, U32 u)
260{
261 // the one-digit case is absolutely predominant
262 if (u < 10)
263 *buf++ = u + '0';
264 else
265 buf += sprintf (buf, "%u", (unsigned int)u);
266
267 return buf;
268}
269
270static SV *
271process_object_identifier_sv (void)
272{
273 U32 length = process_length ();
274
275 if (length <= 0)
276 {
277 error ("OBJECT IDENTIFIER length equal to zero");
278 return &PL_sv_undef;
279 }
280
281 U8 *end = cur + length;
282 U32 w = getb ();
283
284 static char oid[MAX_OID_STRLEN]; // must be static
285 char *app = oid;
286
287 *app = '.'; app += ! ! leading_dot;
288 app = write_uv (app, (U8)w / 40);
289 *app++ = '.';
290 app = write_uv (app, (U8)w % 40);
291
292 // we assume an oid component is never > 64 bytes
293 while (cur < end && oid + sizeof (oid) - app > 64)
294 {
295 w = getb ();
296 *app++ = '.';
297 app = write_uv (app, w);
298 }
299
300 return newSVpvn (oid, app - oid);
301}
302
303static AV *av_type;
304
305static SV *
306process_sv (int *found)
307{
308 int type = get8 ();
309
310 *found = type;
311
312 SV *res;
313
314 switch (type)
315 {
316 case ASN_OBJECT_IDENTIFIER:
317 res = process_object_identifier_sv ();
318 break;
319
320 case ASN_INTEGER32:
321 res = process_integer32_sv ();
322 break;
323
324 case ASN_UNSIGNED32:
325 case ASN_COUNTER32:
326 case ASN_TIMETICKS:
327 res = process_unsigned32_sv ();
328 break;
329
330 case ASN_SEQUENCE:
331 res = newSVuv (process_length ());
332 break;
333
334 case ASN_OCTET_STRING:
335 case ASN_OPAQUE:
336 res = process_octet_string_sv ();
337 break;
338
339 default:
340 {
341 if (type > AvFILLp (av_type) || !SvTYPE (AvARRAY (av_type)[type]) == SVt_PVCV)
342 {
343 error ("Unknown ASN.1 type");
344 return &PL_sv_undef;
345 }
346
347 dSP;
348 PUSHMARK (SP);
349 EXTEND (SP, 2);
350 PUSHs (msg);
351 PUSHs (sv_2mortal (newSViv (type)));
352 PUTBACK;
353 int count = call_sv (AvARRAY (av_type)[type], G_SCALAR);
354 SPAGAIN;
355 res = count ? SvREFCNT_inc (TOPs) : &PL_sv_undef;
356 }
357 }
358
359 return errflag ? &PL_sv_undef : res;
360}
361
139MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS 362MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
363
364PROTOTYPES: ENABLE
365
366BOOT:
367 av_type = newAV ();
368
369void
370set_type (int type, SV *cv)
371 CODE:
372 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
140 373
141void 374void
142set_msg (SV *msg_, SV *buf_) 375set_msg (SV *msg_, SV *buf_)
143 CODE: 376 CODE:
377{
378 if (msg)
379 croak ("recursive invocation of Net::SNMP::XS parser is not supported");
380
144 errflag = 0; 381 errflag = 0;
382 leading_dot = -1;
145 msg = SvREFCNT_inc (msg_); 383 msg = SvREFCNT_inc (msg_);
146 buf = SvPVbyte (buf_, len); 384 buf = SvPVbyte (buf_, len);
147 cur = buf; 385 cur = buf;
148 rem = len; 386 rem = len;
149#ifdef BENCHMARK 387#ifdef BENCHMARK
150 t1 = tstamp (); 388 t1 = tstamp ();
151#endif 389#endif
390}
152 391
153void 392void
154clr_msg () 393clr_msg ()
155 CODE: 394 CODE:
156 SvREFCNT_dec (msg); 395 SvREFCNT_dec (msg); msg = 0;
157 buf = cur = ""; 396 buf = cur = (U8 *)"";
158 len = rem = 0; 397 len = rem = 0;
159#ifdef BENCHMARK 398#ifdef BENCHMARK
160 printf ("%f\n", tstamp () - t1);//D 399 printf ("%f\n", tstamp () - t1);//D
161#endif 400#endif
162 401
199 RETVAL 438 RETVAL
200 439
201U32 440U32
202_process_length (SV *self, ...) 441_process_length (SV *self, ...)
203 ALIAS: 442 ALIAS:
204 _process_sequence = 1 443 _process_sequence = 0
205 CODE: 444 CODE:
206 RETVAL = process_length (); 445 RETVAL = process_length ();
207 OUTPUT: 446 OUTPUT:
208 RETVAL 447 RETVAL
209 448
210I32 449SV *
211_process_integer32 (SV *self, ...) 450_process_integer32 (SV *self, ...)
451 CODE:
452 RETVAL = process_integer32_sv ();
453 OUTPUT:
454 RETVAL
455
456SV *
457_process_counter (SV *self, ...)
212 ALIAS: 458 ALIAS:
213 _process_counter = 0
214 _process_gauge = 0 459 _process_gauge = 0
460 _process_timeticks = 0
215 CODE: 461 CODE:
216{ 462 RETVAL = process_unsigned32_sv ();
217 U32 length = process_length (); 463 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; 464 RETVAL
242} 465
466#if IVSIZE >= 8
467
468SV *
469_process_counter64 (SV *self, ...)
470 CODE:
471 RETVAL = process_unsigned64_sv ();
243 OUTPUT: 472 OUTPUT:
244 RETVAL 473 RETVAL
474
475#endif
245 476
246SV * 477SV *
247_process_object_identifier (SV *self, ...) 478_process_object_identifier (SV *self, ...)
248 CODE: 479 CODE:
249{ 480 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: 481 OUTPUT:
272 RETVAL 482 RETVAL
273 483
274SV * 484SV *
275_process_octet_string (SV *self, ...) 485_process_octet_string (SV *self, ...)
276 ALIAS: 486 ALIAS:
277 _process_opaque = 0 487 _process_opaque = 0
278 CODE: 488 CODE:
279{ 489 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: 490 OUTPUT:
292 RETVAL 491 RETVAL
293 492
294SV * 493SV *
295_process_ipaddress (SV *self, ...) 494_process_ipaddress (SV *self, ...)
306 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]); 505 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]);
307} 506}
308 OUTPUT: 507 OUTPUT:
309 RETVAL 508 RETVAL
310 509
510SV *
511process (SV *self, SV *expected = &PL_sv_undef, SV *found = 0)
512 CODE:
513{
514 int type;
515
516 RETVAL = process_sv (&type);
517
518 if (found)
519 sv_setiv (found, type);
520
521 if (SvOK (expected) && type != SvIV (expected))
522 error ("Expected a different type than found");
523}
524 OUTPUT:
525 RETVAL
526
527MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
528
529SV *
530_process_var_bind_list (SV *self)
531 CODE:
532{
533 if (get8 () != ASN_SEQUENCE)
534 error ("SEQUENCE expected at beginning of VarBindList");
535 int seqlen = process_length ();
536 U8 *end = cur + seqlen;
537
538 HV *list = newHV ();
539 AV *names = newAV ();
540 HV *types = newHV ();
541
542 hv_store ((HV *)SvRV (self), "_var_bind_list" , sizeof ("_var_bind_list" ) - 1, newRV_noinc ((SV *)list ), 0);
543 hv_store ((HV *)SvRV (self), "_var_bind_names", sizeof ("_var_bind_names") - 1, newRV_noinc ((SV *)names), 0);
544 hv_store ((HV *)SvRV (self), "_var_bind_types", sizeof ("_var_bind_types") - 1, newRV_noinc ((SV *)types), 0);
545
546 while (cur < end && !errflag)
547 {
548 // SEQUENCE ObjectName ObjectSyntax
549 if (get8 () != ASN_SEQUENCE)
550 error ("SEQUENCE expected at beginning of VarBind");
551 process_length ();
552
553 if (get8 () != ASN_OBJECT_IDENTIFIER)
554 error ("OBJECT IDENTIFIER expected at beginning of VarBind");
555 int type, oidlen;
556 SV *oid = process_object_identifier_sv ();
557 SV *val = process_sv (&type);
558
559 hv_store_ent (types, oid, newSViv (type), 0);
560 hv_store_ent (list , oid, val, 0);
561 av_push (names, oid);
562 }
563
564 //return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT);
565
566 RETVAL = newRV_inc ((SV *)list);
567}
568 OUTPUT:
569 RETVAL
570
571

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines