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.6 by root, Thu Apr 9 05:56:36 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 7#define ASN_BOOLEAN 0x01
8#define ASN_INTEGER 0x02 8#define ASN_INTEGER32 0x02
9#define ASN_BIT_STR 0x03
10#define ASN_OCTET_STR 0x04 9#define ASN_OCTET_STRING 0x04
11#define ASN_NULL 0x05 10#define ASN_NULL 0x05
12#define ASN_OBJECT_ID 0x06 11#define ASN_OBJECT_IDENTIFIER 0x06
13#define ASN_SEQUENCE 0x10 12#define ASN_SEQUENCE 0x30
14#define ASN_SET 0x11
15
16#define ASN_UNIVERSAL 0x00 13#define ASN_IPADDRESS 0x40
17#define ASN_APPLICATION 0x40
18#define ASN_CONTEXT 0x80 14#define ASN_COUNTER32 0x41
15#define ASN_UNSIGNED32 0x42
16#define ASN_TIMETICKS 0x43
19#define ASN_PRIVATE 0xc0 17#define ASN_OPAQUE 0x44
20
21#define ASN_PRIMITIVE 0x00
22#define ASN_CONSTRUCTOR 0x20
23
24#define ASN_LONG_LEN 0x80 18#define ASN_COUNTER64 0x46
25#define ASN_EXTENSION_ID 0x1f
26#define ASN_BIT8 0x80
27 19
28//#define BENCHMARK 20//#define BENCHMARK
29 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;
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}
34 41
35static void 42static void
36error (const char *msg) 43error (const char *msg)
37{ 44{
38 errflag = 1; 45 errflag = 1;
134 } 141 }
135 142
136 return res; 143 return res;
137} 144}
138 145
146static U32
147process_integer32 (void)
148{
149 U32 length = process_length ();
150
151 if (length <= 0)
152 {
153 error ("INTEGER32 length equal to zero");
154 return 0;
155 }
156
157 U8 *data = getn (length, 0);
158
159 if (!data)
160 return 0;
161
162 if (length > 5 || (length > 4 && data [0]))
163 {
164 error ("INTEGER32 length too long");
165 return 0;
166 }
167
168 U32 res = data [0] & 0x80 ? 0xffffffff : 0;
169
170 while (length--)
171 res = (res << 8) | *data++;
172
173 return res;
174}
175
176static SV *
177process_integer32_sv (void)
178{
179 return newSViv ((I32)process_integer32 ());
180}
181
182static SV *
183process_unsigned32_sv (void)
184{
185 return newSVuv ((U32)process_integer32 ());
186}
187
188static SV *
189process_octet_string_sv (void)
190{
191 U32 length = process_length ();
192
193 U8 *data = getn (length, 0);
194 if (!data)
195 {
196 error ("OCTET STRING too long");
197 return &PL_sv_undef;
198 }
199
200 return newSVpvn (data, length);
201}
202
203static char *
204write_uv (char *buf, U32 u)
205{
206 // the one-digit case is absolutely predominant
207 if (u < 10)
208 *buf++ = u + '0';
209 else
210 buf += sprintf (buf, "%u", (unsigned int)u);
211
212 return buf;
213}
214
215static char *
216process_object_identifier (int *len)
217{
218 U32 length = process_length ();
219
220 if (length <= 0)
221 {
222 error ("OBJECT IDENTIFIER length equal to zero");
223 return "";
224 }
225
226 U8 *end = cur + length;
227 U32 w = getb ();
228
229 static char oid[MAX_OID_STRLEN]; // must be static
230 char *app = oid;
231
232 *app = '.'; app += ! ! leading_dot;
233 app = write_uv (app, (U8)w / 40);
234 *app++ = '.';
235 app = write_uv (app, (U8)w % 40);
236
237 // we assume an oid component is never > 64 bytes
238 while (cur < end && oid + sizeof (oid) - app > 64)
239 {
240 w = getb ();
241 *app++ = '.';
242 app = write_uv (app, w);
243 }
244
245 *len = app - oid;
246 return oid;
247}
248
249static SV *
250process_object_identifier_sv (void)
251{
252 int len;
253 char *oid = process_object_identifier (&len);
254
255 return newSVpvn (oid, len);
256}
257
258static AV *av_type;
259
260static SV *
261process_sv (int *found)
262{
263 int type = get8 ();
264
265 *found = type;
266
267 SV *res;
268
269 switch (type)
270 {
271 case ASN_OBJECT_IDENTIFIER:
272 res = process_object_identifier_sv ();
273 break;
274
275 case ASN_INTEGER32:
276 res = process_integer32_sv ();
277 break;
278
279 case ASN_UNSIGNED32:
280 case ASN_COUNTER32:
281 case ASN_TIMETICKS:
282 res = process_unsigned32_sv ();
283 break;
284
285 case ASN_SEQUENCE:
286 res = newSVuv (process_length ());
287 break;
288
289 case ASN_OCTET_STRING:
290 case ASN_OPAQUE:
291 res = process_octet_string_sv ();
292 break;
293
294 default:
295 {
296 if (type > AvFILLp (av_type) || !SvTYPE (AvARRAY (av_type)[type]) == SVt_PVCV)
297 {
298 error ("Unknown ASN.1 type");
299 return &PL_sv_undef;
300 }
301
302 dSP;
303 PUSHMARK (SP);
304 EXTEND (SP, 2);
305 PUSHs (msg);
306 PUSHs (sv_2mortal (newSViv (type)));
307 PUTBACK;
308 int count = call_sv (AvARRAY (av_type)[type], G_SCALAR);
309 SPAGAIN;
310 res = count ? SvREFCNT_inc (TOPs) : &PL_sv_undef;
311 }
312 }
313
314 return errflag ? &PL_sv_undef : res;
315}
316
139MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS 317MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::XS
318
319PROTOTYPES: ENABLE
320
321BOOT:
322 av_type = newAV ();
323
324void
325set_type (int type, SV *cv)
326 CODE:
327 av_store (av_type, type, SvREFCNT_inc (x_get_cv (cv)));
140 328
141void 329void
142set_msg (SV *msg_, SV *buf_) 330set_msg (SV *msg_, SV *buf_)
143 CODE: 331 CODE:
144 errflag = 0; 332 errflag = 0;
333 leading_dot = -1;
145 msg = SvREFCNT_inc (msg_); 334 msg = SvREFCNT_inc (msg_);
146 buf = SvPVbyte (buf_, len); 335 buf = SvPVbyte (buf_, len);
147 cur = buf; 336 cur = buf;
148 rem = len; 337 rem = len;
149#ifdef BENCHMARK 338#ifdef BENCHMARK
150 t1 = tstamp (); 339 t1 = tstamp ();
151#endif 340#endif
152 341
153void 342void
154clr_msg () 343clr_msg ()
155 CODE: 344 CODE:
199 RETVAL 388 RETVAL
200 389
201U32 390U32
202_process_length (SV *self, ...) 391_process_length (SV *self, ...)
203 ALIAS: 392 ALIAS:
204 _process_sequence = 1 393 _process_sequence = 0
205 CODE: 394 CODE:
206 RETVAL = process_length (); 395 RETVAL = process_length ();
207 OUTPUT: 396 OUTPUT:
208 RETVAL 397 RETVAL
209 398
210I32 399SV *
211_process_integer32 (SV *self, ...) 400_process_integer32 (SV *self, ...)
401 CODE:
402 RETVAL = process_integer32_sv ();
403 OUTPUT:
404 RETVAL
405
406SV *
407_process_counter (SV *self, ...)
212 ALIAS: 408 ALIAS:
213 _process_counter = 0
214 _process_gauge = 0 409 _process_gauge = 0
410 _process_timeticks = 0
215 CODE: 411 CODE:
216{ 412 RETVAL = process_unsigned32_sv ();
217 U32 length = process_length ();
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;
242}
243 OUTPUT: 413 OUTPUT:
244 RETVAL 414 RETVAL
245 415
246SV * 416SV *
247_process_object_identifier (SV *self, ...) 417_process_object_identifier (SV *self, ...)
248 CODE: 418 CODE:
249{ 419 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: 420 OUTPUT:
272 RETVAL 421 RETVAL
273 422
274SV * 423SV *
275_process_octet_string (SV *self, ...) 424_process_octet_string (SV *self, ...)
276 ALIAS: 425 ALIAS:
277 _process_opaque = 0 426 _process_opaque = 0
278 CODE: 427 CODE:
279{ 428 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: 429 OUTPUT:
292 RETVAL 430 RETVAL
293 431
294SV * 432SV *
295_process_ipaddress (SV *self, ...) 433_process_ipaddress (SV *self, ...)
306 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]); 444 RETVAL = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]);
307} 445}
308 OUTPUT: 446 OUTPUT:
309 RETVAL 447 RETVAL
310 448
449SV *
450process (SV *self, SV *expected = &PL_sv_undef, SV *found = 0)
451 CODE:
452{
453 int type;
454
455 RETVAL = process_sv (&type);
456
457 if (found)
458 sv_setiv (found, type);
459
460 if (SvOK (expected) && type != SvIV (expected))
461 error ("Expected a different type than found");
462}
463 OUTPUT:
464 RETVAL
465
466MODULE = Net::SNMP::XS PACKAGE = Net::SNMP::PDU
467
468SV *
469_process_var_bind_list (SV *self)
470 CODE:
471{
472 if (get8 () != ASN_SEQUENCE)
473 error ("SEQUENCE expected at beginning of VarBindList");
474 int seqlen = process_length ();
475 U8 *end = cur + seqlen;
476
477 HV *list = newHV ();
478 AV *names = newAV ();
479 HV *types = newHV ();
480
481 hv_store ((HV *)SvRV (self), "_var_bind_list" , sizeof ("_var_bind_list" ) - 1, newRV_noinc ((SV *)list ), 0);
482 hv_store ((HV *)SvRV (self), "_var_bind_names", sizeof ("_var_bind_names") - 1, newRV_noinc ((SV *)names), 0);
483 hv_store ((HV *)SvRV (self), "_var_bind_types", sizeof ("_var_bind_types") - 1, newRV_noinc ((SV *)types), 0);
484
485 while (cur < end && !errflag)
486 {
487 // SEQUENCE ObjectName ObjectSyntax
488 if (get8 () != ASN_SEQUENCE)
489 error ("SEQUENCE expected at beginning of VarBind");
490 process_length ();
491
492 if (get8 () != ASN_OBJECT_IDENTIFIER)
493 error ("OBJECT IDENTIFIER expected at beginning of VarBind");
494 int type, oidlen;
495 char *oid = process_object_identifier (&oidlen);
496 SV *val = process_sv (&type);
497
498 hv_store (types, oid, oidlen, newSViv (type), 0);
499 hv_store (list , oid, oidlen, val, 0);
500 av_push (names, newSVpvn (oid, oidlen));
501 }
502
503 //return $this->_report_pdu_error if ($this->{_pdu_type} == REPORT);
504
505 RETVAL = newRV_inc ((SV *)list);
506}
507 OUTPUT:
508 RETVAL
509
510

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines