1 /* -*- C -*- */
2 
3 #include "EXTERN.h"
4 #include "perl.h"
5 #include "XSUB.h"
6 #include <netdb.h>
7 #include <sys/socket.h>
8 
9 #include <net-snmp/net-snmp-config.h>
10 #include <net-snmp/net-snmp-includes.h>
11 #include <net-snmp/agent/net-snmp-agent-includes.h>
12 
13 #ifndef sv_undef
14 #define sv_undef PL_sv_undef
15 #endif
16 
17 typedef netsnmp_handler_registration *NetSNMP__agent__netsnmp_handler_registration;
18 
19 /*
20  * needs to be in sync with the definitions in snmplib/snmpUDPDomain.c
21  * and snmplib/snmpTCPDomain.c
22  */
23 typedef netsnmp_indexed_addr_pair netsnmp_udp_addr_pair;
24 
25 typedef struct handler_cb_data_s {
26    SV *perl_cb;
27 } handler_cb_data;
28 
29 typedef struct netsnmp_oid_s {
30     oid                 *name;
31     size_t               len;
32     oid                  namebuf[ MAX_OID_LEN ];
33 } netsnmp_oid;
34 
35 #define TEST_CONSTANT(value, name, C)           \
36     if (strEQ(name, #C)) {                      \
37         *value = C;                             \
38         return 0;                               \
39     }
40 
constant_MODE_G(double * value,const char * name,const int len)41 static int constant_MODE_G(double *value, const char *name, const int len)
42 {
43     switch (len >= 8 ? name[8] : -1) {
44     case '\0':
45         TEST_CONSTANT(value, name, MODE_GET);
46         break;
47     case 'B':
48         TEST_CONSTANT(value, name, MODE_GETBULK);
49         break;
50     case 'N':
51         TEST_CONSTANT(value, name, MODE_GETNEXT);
52         break;
53     }
54     return EINVAL;
55 }
56 
constant_MODE_SET_R(double * value,const char * name,const int len)57 static int constant_MODE_SET_R(double *value, const char *name, const int len)
58 {
59     switch (len >= 16 ? name[16] : -1) {
60 #ifndef NETSNMP_NO_WRITE_SUPPORT
61     case '1':
62 	TEST_CONSTANT(value, name, MODE_SET_RESERVE1);
63         break;
64     case '2':
65 	TEST_CONSTANT(value, name, MODE_SET_RESERVE2);
66         break;
67 #endif /* NETSNMP_NO_WRITE_SUPPORT */
68     }
69     return EINVAL;
70 }
71 
constant_SNMP_ERR(double * value,char * name,int len)72 static int constant_SNMP_ERR(double *value, char *name, int len)
73 {
74     switch (len >= 9 ? name[9] : -1) {
75     case 'A':
76         TEST_CONSTANT(value, name, SNMP_ERR_AUTHORIZATIONERROR);
77         break;
78     case 'B':
79         TEST_CONSTANT(value, name, SNMP_ERR_BADVALUE);
80         break;
81     case 'C':
82         TEST_CONSTANT(value, name, SNMP_ERR_COMMITFAILED);
83         break;
84     case 'G':
85 	TEST_CONSTANT(value, name, SNMP_ERR_GENERR);
86         break;
87     case 'I':
88 	TEST_CONSTANT(value, name, SNMP_ERR_INCONSISTENTVALUE);
89         break;
90     case 'N':
91         TEST_CONSTANT(value, name, SNMP_ERR_NOACCESS);
92         TEST_CONSTANT(value, name, SNMP_ERR_NOCREATION);
93         TEST_CONSTANT(value, name, SNMP_ERR_NOERROR);
94         TEST_CONSTANT(value, name, SNMP_ERR_NOSUCHNAME);
95         TEST_CONSTANT(value, name, SNMP_ERR_NOTWRITABLE);
96         break;
97     case 'R':
98         TEST_CONSTANT(value, name, SNMP_ERR_READONLY);
99         TEST_CONSTANT(value, name, SNMP_ERR_RESOURCEUNAVAILABLE);
100         break;
101     case 'T':
102         TEST_CONSTANT(value, name, SNMP_ERR_TOOBIG);
103         break;
104     case 'U':
105         TEST_CONSTANT(value, name, SNMP_ERR_UNDOFAILED);
106         break;
107     case 'W':
108         TEST_CONSTANT(value, name, SNMP_ERR_WRONGENCODING);
109         TEST_CONSTANT(value, name, SNMP_ERR_WRONGLENGTH);
110         TEST_CONSTANT(value, name, SNMP_ERR_WRONGTYPE);
111         TEST_CONSTANT(value, name, SNMP_ERR_WRONGVALUE);
112         break;
113     }
114     return EINVAL;
115 }
116 
constant_MODE_S(double * value,char * name,int len)117 static int constant_MODE_S(double *value, char *name, int len)
118 {
119     if (!strnEQ(name + 6, "ET_", 3))
120         return EINVAL;
121 
122     switch (len >= 9 ? name[9] : -1) {
123 #ifndef NETSNMP_NO_WRITE_SUPPORT
124     case 'A':
125         TEST_CONSTANT(value, name, MODE_SET_ACTION);
126         break;
127     case 'B':
128         TEST_CONSTANT(value, name, MODE_SET_BEGIN);
129         break;
130     case 'C':
131         TEST_CONSTANT(value, name, MODE_SET_COMMIT);
132         break;
133     case 'F':
134         TEST_CONSTANT(value, name, MODE_SET_FREE);
135         break;
136     case 'U':
137         TEST_CONSTANT(value, name, MODE_SET_UNDO);
138         break;
139 #endif /* NETSNMP_NO_WRITE_SUPPORT */
140     case 'R':
141         return constant_MODE_SET_R(value, name, len);
142     }
143     return EINVAL;
144 }
145 
constant(double * value,char * name,int len)146 static int constant(double *value, char *name, int len)
147 {
148     switch (len >= 5 ? name[5] : -1) {
149     case 'G':
150 	if (strnEQ(name + 0,"MODE_", 5))
151             return constant_MODE_G(value, name, len);
152         break;
153     case 'S':
154 	if (strnEQ(name + 0,"MODE_", 5))
155             return constant_MODE_S(value, name, len);
156         break;
157     case 'E':
158 	if (strnEQ(name + 0,"SNMP_ERR_", 9))
159             return constant_SNMP_ERR(value, name, len);
160         break;
161     }
162     return EINVAL;
163 }
164 
165 int
handler_wrapper(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)166 handler_wrapper(netsnmp_mib_handler          *handler,
167                 netsnmp_handler_registration *reginfo,
168                 netsnmp_agent_request_info   *reqinfo,
169                 netsnmp_request_info         *requests)
170 {
171     handler_cb_data *cb_data = (handler_cb_data *) handler->myvoid;
172     SV *cb;
173 
174     if (cb_data && (cb = cb_data->perl_cb)) {
175         SV *arg;
176         SV *rarg;
177         dSP;
178         ENTER;
179         SAVETMPS;
180         PUSHMARK(sp);
181         rarg = newSViv(0);
182         arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_mib_handler");
183         sv_setiv(arg, (IV) handler);
184         XPUSHs(sv_2mortal(rarg));
185         rarg = newSViv(0);
186         arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_handler_registrationPtr");
187         sv_setiv(arg, (IV) reginfo);
188         XPUSHs(sv_2mortal(rarg));
189         rarg = newSViv(0);
190         arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_agent_request_info");
191         sv_setiv(arg, (IV) reqinfo);
192         XPUSHs(sv_2mortal(rarg));
193         rarg = newSViv(0);
194         arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_request_infoPtr");
195         sv_setiv(arg, (IV) requests);
196         XPUSHs(sv_2mortal(rarg));
197         PUTBACK;
198         if (SvTYPE(cb) == SVt_PVCV) {
199             perl_call_sv(cb, G_DISCARD);
200 
201         } else if (SvROK(cb) && SvTYPE(SvRV(cb)) == SVt_PVCV) {
202             perl_call_sv(SvRV(cb), G_DISCARD);
203         }
204         SPAGAIN;
205         PUTBACK;
206         FREETMPS;
207         LEAVE;
208     }
209     return SNMP_ERR_NOERROR;
210 }
211 
212 MODULE = NetSNMP::agent		PACKAGE = NetSNMP::agent
213 
214 void
215 constant(sv)
216     PREINIT:
217 	STRLEN		len;
218     INPUT:
219 	SV *		sv
220 	char *		s = SvPV(sv, len);
221     INIT:
222         int status;
223         double value;
224     PPCODE:
225         value = 0;
226         status = constant(&value, s, len);
227         XPUSHs(sv_2mortal(newSVuv(status)));
228         XPUSHs(sv_2mortal(newSVnv(value)));
229 
230 int
231 __agent_check_and_process(block = 1)
232 	int block;
233     CODE:
234 	RETVAL = agent_check_and_process(block);
235     OUTPUT:
236 	RETVAL
237 
238 int
239 _uptime()
240     CODE:
241         RETVAL = netsnmp_get_agent_uptime();
242     OUTPUT:
243 	RETVAL
244 
245 void
init_mib()246 init_mib()
247     CODE:
248     {
249         netsnmp_init_mib();
250     }
251 
252 int
253 init_agent(name)
254         const char *name;
255     CODE:
256         SOCK_STARTUP;
257         RETVAL = init_agent(name);
258     OUTPUT:
259         RETVAL
260 
261 void
262 init_snmp(name)
263         const char *name;
264 
265 int
266 init_master_agent()
267 
268 void
269 snmp_enable_stderrlog()
270 
271 MODULE = NetSNMP::agent  PACKAGE = NetSNMP::agent PREFIX = na_
272 
273 void
274 na_shutdown(me)
275     SV *me;
276     CODE:
277     {
278         if (0)
279             printf("me = %p\n", me);
280         snmp_shutdown("perl");
281     }
282 
283 void
284 na_errlog(me,value)
285     SV *me;
286     SV *value;
287    PREINIT:
288         STRLEN stringlen;
289         char * stringptr;
290     CODE:
291     {
292         if (0)
293             printf("me = %p\n", me);
294         stringptr = SvPV(value, stringlen);
295         snmp_log(LOG_ERR, "%s", stringptr );
296     }
297 
298 
299 
300 MODULE = NetSNMP::agent  PACKAGE = NetSNMP::agent::netsnmp_handler_registration  PREFIX = nsahr_
301 
302 NetSNMP::agent::netsnmp_handler_registration
303 nsahr_new(name, regoid, perlcallback)
304         char *name;
305 	char *regoid;
306         SV   *perlcallback;
307     PREINIT:
308 	oid myoid[MAX_OID_LEN];
309 	size_t myoid_len = MAX_OID_LEN;
310         handler_cb_data *cb_data;
311         int gotit=1;
312     CODE:
313 	if (!snmp_parse_oid(regoid, myoid, &myoid_len)) {
314             if (!read_objid(regoid, myoid, &myoid_len)) {
315                 snmp_log(LOG_ERR, "couldn't parse %s (reg name: %s)\n",
316                         regoid, name);
317                 RETVAL = NULL;
318                 gotit = 0;
319             }
320         }
321         if (gotit) {
322             cb_data = (handler_cb_data *) malloc(sizeof(handler_cb_data));
323             RETVAL = netsnmp_create_handler_registration(name, handler_wrapper,
324                                                  myoid, myoid_len,
325                                                  HANDLER_CAN_RWRITE);
326             cb_data->perl_cb = newSVsv(perlcallback);
327             RETVAL->handler->myvoid = cb_data;
328         }
329     OUTPUT:
330         RETVAL
331 
332 void
nsahr_DESTROY(reginfo)333 nsahr_DESTROY(reginfo)
334 	netsnmp_handler_registration *reginfo
335     PREINIT:
336         handler_cb_data *cb_data;
337     CODE:
338         if (reginfo && reginfo->handler && reginfo->handler->myvoid) {
339 	    cb_data = (handler_cb_data *) (reginfo->handler->myvoid);
340 	    SvREFCNT_dec(cb_data->perl_cb);
341 	    free(cb_data);
342         }
343 	netsnmp_handler_registration_free(reginfo);
344 
345 int
346 nsahr_register(me)
347         SV *me;
348         PREINIT:
349         netsnmp_handler_registration *reginfo;
350         handler_cb_data *cb_data = NULL;
351         CODE:
352             {
353                 reginfo = (netsnmp_handler_registration *) SvIV(SvRV(me));
354                 if (reginfo && reginfo->handler && reginfo->handler->myvoid)
355                     cb_data = (handler_cb_data *) (reginfo->handler->myvoid);
356                 RETVAL = netsnmp_register_handler(reginfo);
357                 if (!RETVAL) {
358                     /* the agent now has a "reference" to this reg pointer */
359                     SvREFCNT_inc(me);
360                 } else {
361                     /*
362                      * The reginfo was freed by netsnmp_register_handler,
363                      * don't touch it in nsahr_DESTROY!
364                      */
365                     sv_setiv(SvRV(me), 0);
366                     if (cb_data) {
367                         /* And just free the callback. */
368                         SvREFCNT_dec(cb_data->perl_cb);
369                         free(cb_data);
370                     }
371                 }
372             }
373     OUTPUT:
374 	RETVAL
375 
376 
377 MODULE = NetSNMP::agent PACKAGE = NetSNMP::agent::netsnmp_handler_registrationPtr PREFIX = nsahr_
378 
379 void
380 nsahr_getRootOID(me)
381     SV *me;
382     PREINIT:
383         int i;
384         netsnmp_oid *o;
385         netsnmp_handler_registration *reginfo;
386         SV *arg, *rarg;
387     PPCODE:
388     {
389         dSP;
390         PUSHMARK(SP);
391         reginfo = (netsnmp_handler_registration *) SvIV(SvRV(me));
392 
393         o = malloc(sizeof(netsnmp_oid));
394         o->name = o->namebuf;
395         o->len = reginfo->rootoid_len;
396         memcpy(o->name, reginfo->rootoid,
397                reginfo->rootoid_len * sizeof(oid));
398 
399         rarg = newSViv((int) 0);
400         arg = newSVrv(rarg, "netsnmp_oidPtr");
401         sv_setiv(arg, (IV) o);
402 
403         XPUSHs(sv_2mortal(rarg));
404 
405         PUTBACK;
406         i = perl_call_pv("NetSNMP::OID::newwithptr", G_SCALAR);
407         SPAGAIN;
408         if (i != 1) {
409             snmp_log(LOG_ERR, "unhandled OID error.\n");
410             /* ack XXX */
411         }
412         ST(0) = POPs;
413         XSRETURN(1);
414     }
415 
416 MODULE = NetSNMP::agent  PACKAGE = NetSNMP::agent::netsnmp_request_infoPtr PREFIX = nari_
417 
418 void
419 getOID(me)
420     SV *me;
421     PREINIT:
422         int i;
423         netsnmp_oid *o;
424         netsnmp_request_info *request;
425         SV *arg, *rarg;
426     PPCODE:
427     {
428         dSP;
429         PUSHMARK(SP);
430         request = (netsnmp_request_info *) SvIV(SvRV(me));
431 
432         o = malloc(sizeof(netsnmp_oid));
433         o->name = o->namebuf;
434         o->len = request->requestvb->name_length;
435         memcpy(o->name, request->requestvb->name,
436                request->requestvb->name_length * sizeof(oid));
437 
438         rarg = newSViv((int) 0);
439         arg = newSVrv(rarg, "netsnmp_oidPtr");
440         sv_setiv(arg, (IV) o);
441 
442         XPUSHs(sv_2mortal(rarg));
443 
444         PUTBACK;
445         i = perl_call_pv("NetSNMP::OID::newwithptr", G_SCALAR);
446         SPAGAIN;
447         if (i != 1) {
448             snmp_log(LOG_ERR, "unhandled OID error.\n");
449             /* ack XXX */
450         }
451         ST(0) = POPs;
452         XSRETURN(1);
453     }
454 
455 netsnmp_oid *
456 nari_getOIDptr(me)
457         SV *me;
458         PREINIT:
459         netsnmp_request_info *request;
460         CODE:
461         request = (netsnmp_request_info *) SvIV(SvRV(me));
462         RETVAL = malloc(sizeof(netsnmp_oid));
463         RETVAL->name = RETVAL->namebuf;
464         RETVAL->len = request->requestvb->name_length;
465         memcpy(RETVAL->name, request->requestvb->name,
466                request->requestvb->name_length * sizeof(oid));
467     OUTPUT:
468         RETVAL
469 
470 int
471 nari_getType(me)
472         SV *me;
473     PREINIT:
474         netsnmp_request_info *request;
475     CODE:
476         request = (netsnmp_request_info *) SvIV(SvRV(me));
477 
478         RETVAL =  request->requestvb->type ;
479     OUTPUT:
480         RETVAL
481 
482 void
483 nari_setType(me, newvalue)
484         SV *me;
485         int newvalue;
486     PREINIT:
487         netsnmp_request_info *request;
488     CODE:
489         request = (netsnmp_request_info *) SvIV(SvRV(me));
490         request->requestvb->type=newvalue;
491 
492 SV *
493 nari_getValue(me)
494         SV *me;
495     PREINIT:
496         char *outbuf = NULL;
497         size_t ob_len = 0, oo_len = 0;
498         netsnmp_request_info *request;
499     CODE:
500         request = (netsnmp_request_info *) SvIV(SvRV(me));
501 	sprint_realloc_by_type((u_char **) &outbuf, &ob_len, &oo_len, 1,
502                                request->requestvb, 0, 0, 0);
503         RETVAL = newSVpv(outbuf, 0);
504 	netsnmp_free(outbuf);
505     OUTPUT:
506         RETVAL
507 
508 int
509 nari_getDelegated(me)
510         SV *me;
511     PREINIT:
512         netsnmp_request_info *request;
513     CODE:
514         request = (netsnmp_request_info *) SvIV(SvRV(me));
515         RETVAL = request->delegated;
516     OUTPUT:
517         RETVAL
518 
519 void
520 nari_setDelegated(me, newdelegated)
521         SV *me;
522         int newdelegated;
523     PREINIT:
524         netsnmp_request_info *request;
525     CODE:
526         request = (netsnmp_request_info *) SvIV(SvRV(me));
527         request->delegated = newdelegated;
528 
529 int
530 nari_getProcessed(me)
531         SV *me;
532     PREINIT:
533         netsnmp_request_info *request;
534     CODE:
535         request = (netsnmp_request_info *) SvIV(SvRV(me));
536         RETVAL = request->processed;
537     OUTPUT:
538         RETVAL
539 
540 void
541 nari_setProcessed(me, newprocessed)
542         SV *me;
543         int newprocessed;
544     PREINIT:
545         netsnmp_request_info *request;
546     CODE:
547         request = (netsnmp_request_info *) SvIV(SvRV(me));
548         request->processed = newprocessed;
549 
550 int
551 nari_getStatus(me)
552         SV *me;
553     PREINIT:
554         netsnmp_request_info *request;
555     CODE:
556         request = (netsnmp_request_info *) SvIV(SvRV(me));
557         RETVAL = request->status;
558     OUTPUT:
559         RETVAL
560 
561 void
562 nari_setStatus(me, newstatus)
563         SV *me;
564         int newstatus;
565     PREINIT:
566         netsnmp_request_info *request;
567     CODE:
568         request = (netsnmp_request_info *) SvIV(SvRV(me));
569         request->status = newstatus;
570 
571 int
572 nari_getRepeat(me)
573         SV *me;
574     PREINIT:
575         netsnmp_request_info *request;
576     CODE:
577         request = (netsnmp_request_info *) SvIV(SvRV(me));
578         RETVAL = request->repeat;
579     OUTPUT:
580         RETVAL
581 
582 void
583 nari_setRepeat(me, newrepeat)
584         SV *me;
585         int newrepeat;
586     PREINIT:
587         netsnmp_request_info *request;
588     CODE:
589         request = (netsnmp_request_info *) SvIV(SvRV(me));
590         request->repeat = newrepeat;
591 
592 int
593 nari_setValue(me, type, value)
594         SV *me;
595         int type;
596         SV *value;
597     PREINIT:
598         netsnmp_request_info *request;
599         u_long utmp;
600         long ltmp;
601         uint64_t ulltmp;
602         struct counter64 c64;
603 	oid myoid[MAX_OID_LEN];
604 	size_t myoid_len;
605         STRLEN stringlen;
606         char * stringptr;
607     CODE:
608         request = (netsnmp_request_info *) SvIV(SvRV(me));
609         switch(type) {
610           case  SNMP_NOSUCHINSTANCE :
611               snmp_set_var_typed_value(request->requestvb,SNMP_NOSUCHINSTANCE,0,0) ;
612               RETVAL = 1;
613               break ;
614           case  SNMP_NOSUCHOBJECT :
615               snmp_set_var_typed_value(request->requestvb,SNMP_NOSUCHOBJECT,0,0) ;
616               RETVAL = 1;
617               break ;
618           case  SNMP_ENDOFMIBVIEW :
619               snmp_set_var_typed_value(request->requestvb,SNMP_ENDOFMIBVIEW,0,0) ;
620               RETVAL = 1;
621               break ;
622           case ASN_INTEGER:
623 	      /* We want an integer here */
624 	      if ((SvTYPE(value) == SVt_IV) || (SvTYPE(value) == SVt_PVMG) ||
625                    SvIOK(value)) {
626 		  /* Good - got a real one (or a blessed object that we hope will turn out OK) */
627 		  ltmp = SvIV(value);
628 		  snmp_set_var_typed_value(request->requestvb, (u_char)type,
629 					   (u_char *) &ltmp, sizeof(ltmp));
630 		  RETVAL = 1;
631 		  break;
632 	      }
633 	      else if (SvPOKp(value)) {
634 	          /* Might be OK - got a string, so try to convert it, allowing base 10, octal, and hex forms */
635 	          stringptr = SvPV(value, stringlen);
636 		  ltmp = strtol( stringptr, NULL, 0 );
637 		  if (errno == EINVAL) {
638 		  	snmp_log(LOG_ERR, "Could not convert string to number in setValue: '%s'", stringptr);
639 			RETVAL = 0;
640 			break;
641 		  }
642 
643 		  snmp_set_var_typed_value(request->requestvb, (u_char)type,
644 					   (u_char *) &ltmp, sizeof(ltmp));
645 		  RETVAL = 1;
646 		  break;
647 	      }
648 	      else {
649 		snmp_log(LOG_ERR, "Non-integer value passed to setValue with ASN_INTEGER: type was %lu\n",
650 			(unsigned long)SvTYPE(value));
651 		RETVAL = 0;
652 		break;
653 	      }
654 
655 
656           case ASN_UNSIGNED:
657           case ASN_COUNTER:
658           case ASN_TIMETICKS:
659 	      /* We want an integer here */
660 	      if ((SvTYPE(value) == SVt_IV) || (SvTYPE(value) == SVt_PVMG) ||
661                    SvIOK(value)) {
662 		  /* Good - got a real one (or a blessed scalar which we have to hope will turn out OK) */
663 		  utmp = SvIV(value);
664                   snmp_set_var_typed_value(request->requestvb, (u_char)type,
665                                        (u_char *) &utmp, sizeof(utmp));
666 		  RETVAL = 1;
667 		  break;
668 	      }
669 	      else if (SvPOKp(value)) {
670 	          /* Might be OK - got a string, so try to convert it, allowing base 10, octal, and hex forms */
671 	          stringptr = SvPV(value, stringlen);
672 		  utmp = strtoul( stringptr, NULL, 0 );
673 		  if (errno == EINVAL) {
674 		  	snmp_log(LOG_ERR, "Could not convert string to number in setValue: '%s'", stringptr);
675 			RETVAL = 0;
676 			break;
677 		  }
678 
679                   snmp_set_var_typed_value(request->requestvb, (u_char)type,
680                                        (u_char *) &utmp, sizeof(utmp));
681 		  RETVAL = 1;
682 		  break;
683 	      }
684 	      else {
685 		snmp_log(LOG_ERR, "Non-unsigned-integer value passed to setValue with ASN_UNSIGNED/ASN_COUNTER/ASN_TIMETICKS: type was %lu\n",
686 			(unsigned long)SvTYPE(value));
687 		RETVAL = 0;
688 		break;
689 	      }
690 
691           case ASN_COUNTER64:
692 	      /* We want an integer here */
693 	      if ((SvTYPE(value) == SVt_IV) || (SvTYPE(value) == SVt_PVMG)) {
694 		  /* Good - got a real one (or a blessed scalar which we have to hope will turn out OK) */
695 		  ulltmp = SvIV(value);
696 		  RETVAL = 1;
697 	      }
698 	      else if (SvPOKp(value)) {
699 	          /* Might be OK - got a string, so try to convert it, allowing base 10, octal, and hex forms */
700 	          stringptr = SvPV(value, stringlen);
701 	          errno = 0;
702 		  ulltmp = strtoull( stringptr, NULL, 0 );
703 		  if (errno != 0) {
704 		      snmp_log(LOG_ERR, "Could not convert string to number in setValue: '%s'", stringptr);
705 		      RETVAL = 0;
706 		  } else
707 
708 		      RETVAL = 1;
709 	      }
710 	      else {
711 		snmp_log(LOG_ERR, "Non-unsigned-integer value passed to setValue with ASN_COUNTER64: type was %lu\n",
712 			(unsigned long)SvTYPE(value));
713 		RETVAL = 0;
714 	      }
715 	      if (RETVAL) {
716 		  c64.high = (uint32_t)(ulltmp >> 32);
717 		  c64.low  = (uint32_t)(ulltmp >> 0);
718 		  snmp_set_var_typed_value(request->requestvb, (u_char)type,
719 				     (u_char *) &c64, sizeof(struct counter64));
720 	      }
721 	      break;
722 
723           case ASN_OCTET_STR:
724           case ASN_BIT_STR:
725           case ASN_OPAQUE:
726 	      /* Check that we have been passed something with a string value (or a blessed scalar) */
727 	      if (!SvPOKp(value) && (SvTYPE(value) != SVt_PVMG)) {
728 		snmp_log(LOG_ERR, "Non-string value passed to setValue with ASN_OCTET_STR/ASN_BIT_STR: type was %lu\n",
729 			(unsigned long)SvTYPE(value));
730 		RETVAL = 0;
731 		break;
732 	      }
733 
734 	      /* Find length of string (strlen will *not* do, as these are binary strings) */
735 	      stringptr = SvPV(value, stringlen);
736 
737               snmp_set_var_typed_value(request->requestvb, (u_char)type,
738                                        (u_char *) stringptr,
739                                        stringlen);
740               RETVAL = 1;
741               break;
742 
743           case ASN_IPADDRESS:
744 	      /* IP addresses are passed as *binary* strings.
745 	       * In the case of IPv4 addresses, these are 4 bytes long.
746 	       * NOTE: the use of binary strings rather than dotted-quad or FQDNs was
747 	       * introduced here by Andrew Findlay's patch of March 17th 2003,
748 	       * and is effectively a change to the previous implied API which assumed
749 	       * the value was a (valid) hostname.
750 	       * Responsibility for decoding and resolving has been passed up to the Perl script.
751 	       */
752 
753 	      /* Check that we have been passed something with a string value (or a blessed scalar) */
754 	      if (!SvPOKp(value) && (SvTYPE(value) != SVt_PVMG)) {
755 		snmp_log(LOG_ERR, "Non-string value passed to setValue with ASN_IPADDRESS: type was %lu\n",
756 			(unsigned long)SvTYPE(value));
757 		RETVAL = 0;
758 		break;
759 	      }
760 
761 	      /* Find length of string (strlen will *not* do, as these are binary strings) */
762 	      stringptr = SvPV(value, stringlen);
763 
764 	      # snmp_log(LOG_ERR, "IP address returned with length %d: %u.%u.%u.%u\n", stringlen, stringptr[0],
765 	      #     stringptr[1], stringptr[2], stringptr[3] );
766 
767 	      # Sanity check on address length
768 	      if ((stringlen != 4) && (stringlen != 16)) {
769 	      		snmp_log(LOG_ERR, "IP address of %" NETSNMP_PRIz "d bytes passed to setValue with ASN_IPADDRESS\n", stringlen);
770 			RETVAL = 0;
771 			break;
772 	      }
773 
774               snmp_set_var_typed_value(request->requestvb, (u_char)type,
775                                    stringptr, stringlen);
776               RETVAL = 1;
777               break;
778 
779           case ASN_OBJECT_ID:
780 	      /* Check that we have been passed something with a string value (or a blessed scalar) */
781 	      if (!SvPOKp(value) && (SvTYPE(value) != SVt_PVMG)) {
782 		snmp_log(LOG_ERR, "Non-string value passed to setValue with ASN_OBJECT_ID: type was %lu\n",
783 			(unsigned long)SvTYPE(value));
784 		RETVAL = 0;
785 		break;
786 	      }
787 
788 	      /* Extract the string */
789 	      stringptr = SvPV(value, stringlen);
790 
791 	      /* snmp_log(LOG_ERR, "setValue returning OID '%s'\n", stringptr); */
792 
793 	      myoid_len = MAX_OID_LEN;
794               if (!snmp_parse_oid(stringptr, myoid, &myoid_len)) {
795                   snmp_log(LOG_ERR, "couldn't parse %s in setValue\n", stringptr);
796 		  RETVAL = 0;
797 		  break;
798               } else {
799 		  /* snmp_log(LOG_ERR, "setValue returning OID length %d\n", myoid_len); */
800 
801                   request = (netsnmp_request_info *) SvIV(SvRV(me));
802                   snmp_set_var_typed_value(request->requestvb, (u_char)type,
803                                            (u_char *) myoid, (myoid_len * sizeof(myoid[0])) );
804               }
805 
806               RETVAL = 1;
807               break;
808 
809             default:
810                 snmp_log(LOG_ERR, "unknown var value type: %d\n",
811                         type);
812                 RETVAL = 0;
813                 break;
814         }
815 
816     OUTPUT:
817         RETVAL
818 
819 void
820 nari_setOID(me, value)
821         SV *me;
822         char *value;
823     PREINIT:
824 	oid myoid[MAX_OID_LEN];
825 	size_t myoid_len = MAX_OID_LEN;
826         netsnmp_request_info *request;
827     CODE:
828 	myoid_len = MAX_OID_LEN;
829 	if (!snmp_parse_oid(value, myoid, &myoid_len)) {
830             snmp_log(LOG_ERR, "couldn't parse %s in setOID\n", value);
831         } else {
832             request = (netsnmp_request_info *) SvIV(SvRV(me));
833             snmp_set_var_objid(request->requestvb, myoid, myoid_len);
834         }
835 
836 void
837 nari_setError(me, rinfo, ecode)
838         SV *me;
839         SV *rinfo;
840         int ecode;
841     PREINIT:
842         netsnmp_request_info *request;
843         netsnmp_agent_request_info *reqinfo;
844     CODE:
845         request = (netsnmp_request_info *) SvIV(SvRV(me));
846         reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(rinfo));
847         netsnmp_set_request_error(reqinfo, request, ecode);
848 
849 SV *
850 nari_next(me)
851         SV *me;
852     PREINIT:
853         netsnmp_request_info *request;
854         SV *arg, *rarg;
855     CODE:
856         {
857             request = (netsnmp_request_info *) SvIV(SvRV(me));
858             if (request && request->next) {
859                 request = request->next;
860                 rarg = newSViv(0);
861                 arg = newSVrv(rarg, "NetSNMP::agent::netsnmp_request_infoPtr");
862                 sv_setiv(arg, (IV) request);
863                 RETVAL = rarg;
864             } else {
865                 RETVAL = &sv_undef;
866             }
867         }
868     OUTPUT:
869         RETVAL
870 
871 MODULE = NetSNMP::agent  PACKAGE = NetSNMP::agent::netsnmp_agent_request_info PREFIX = narqi_
872 
873 
874 SV *
875 narqi_getSourceIp(me)
876         SV *me;
877     PREINIT:
878         netsnmp_agent_request_info *reqinfo;
879 	netsnmp_udp_addr_pair *addr_pair;
880 	struct sockaddr_in *from;
881         SV *rarg;
882 
883     CODE:
884         reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(me));
885 
886         /* XXX: transport-specific: UDP/IPv4 only! */
887 	addr_pair = (netsnmp_udp_addr_pair *) (reqinfo->asp->pdu->transport_data);
888 	from = (struct sockaddr_in *) &(addr_pair->remote_addr);
889         rarg = newSVpv((const char *)(&from->sin_addr.s_addr), sizeof(from->sin_addr.s_addr));
890         RETVAL = rarg;
891     OUTPUT:
892         RETVAL
893 
894 
895 SV *
896 narqi_getDestIp(me)
897         SV *me;
898     PREINIT:
899         netsnmp_agent_request_info *reqinfo;
900 	netsnmp_udp_addr_pair *addr_pair;
901 	struct in_addr *to;
902         SV *rarg;
903 
904     CODE:
905         reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(me));
906 
907         /* XXX: transport-specific: UDP/IPv4 only! */
908 	addr_pair = (netsnmp_udp_addr_pair *) (reqinfo->asp->pdu->transport_data);
909 	to = (struct in_addr *) &(addr_pair->local_addr);
910         rarg = newSVpv((const char *)(&to->s_addr), sizeof(to->s_addr));
911         RETVAL = rarg;
912     OUTPUT:
913         RETVAL
914 
915 int
916 narqi_getMode(me)
917         SV *me;
918     PREINIT:
919         netsnmp_agent_request_info *reqinfo;
920     CODE:
921         reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(me));
922         RETVAL = reqinfo->mode;
923     OUTPUT:
924         RETVAL
925 
926 void
927 narqi_setMode(me, newvalue)
928         SV *me;
929         int newvalue;
930     PREINIT:
931         netsnmp_agent_request_info *reqinfo;
932     CODE:
933         reqinfo = (netsnmp_agent_request_info *) SvIV(SvRV(me));
934         reqinfo->mode = newvalue;
935 
936 
937 MODULE = NetSNMP::agent		PACKAGE = NetSNMP::agent
938 
939