TrapReceiver.xs
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:8k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /* -*- c -*- */
  2. #include "EXTERN.h"
  3. #include "perl.h"
  4. #include "XSUB.h"
  5. #include "ppport.h"
  6. #include <net-snmp/net-snmp-config.h>
  7. #include <net-snmp/net-snmp-includes.h>
  8. #include <net-snmp/agent/net-snmp-agent-includes.h>
  9. #include "perl_snmptrapd.h"
  10. #include "const-c.inc"
  11. typedef struct trapd_cb_data_s {
  12.    SV *perl_cb;
  13. } trapd_cb_data;
  14. typedef struct netsnmp_oid_s {
  15.     unsigned int        *name;
  16.     unsigned int         len;
  17.     unsigned int         namebuf[ MAX_OID_LEN ];
  18. } netsnmp_oid;
  19. int   perl_trapd_handler( netsnmp_pdu           *pdu,
  20.                           netsnmp_transport     *transport,
  21.                           netsnmp_trapd_handler *handler)
  22. {
  23.     trapd_cb_data *cb_data;
  24.     SV *pcallback;
  25.     netsnmp_variable_list *vb;
  26.     netsnmp_oid *o;
  27.     SV *arg;
  28.     SV *rarg;
  29.     SV **tmparray;
  30.     int i, c = 0;
  31.     u_char *outbuf;
  32.     size_t ob_len = 0, oo_len = 0;
  33.     AV *varbinds;
  34.     HV *pduinfo;
  35.     dSP;
  36.     ENTER;
  37.     SAVETMPS;
  38.     if (!pdu || !handler)
  39.         return 0;
  40.     /* nuke v1 PDUs */
  41.     if (pdu->command == SNMP_MSG_TRAP)
  42.         pdu = convert_v1pdu_to_v2(pdu);
  43.     cb_data = handler->handler_data;
  44.     if (!cb_data || !cb_data->perl_cb)
  45.         return 0;
  46.     pcallback = cb_data->perl_cb;
  47.     /* get PDU related info */
  48.     pduinfo = newHV();
  49. #define STOREPDU(n, v) hv_store(pduinfo, n, strlen(n), v, 0)
  50. #define STOREPDUi(n, v) STOREPDU(n, newSViv(v))
  51. #define STOREPDUs(n, v) STOREPDU(n, newSVpv(v, 0))
  52.     STOREPDUi("version", pdu->version);
  53.     STOREPDUs("notificationtype", ((pdu->command == SNMP_MSG_INFORM) ? "INFORM":"TRAP"));
  54.     STOREPDUi("requestid", pdu->reqid);
  55.     STOREPDUi("messageid", pdu->msgid);
  56.     STOREPDUi("transactionid", pdu->transid);
  57.     STOREPDUi("errorstatus", pdu->errstat);
  58.     STOREPDUi("errorindex", pdu->errindex);
  59.     if (pdu->version == 3) {
  60.         STOREPDUi("securitymodel", pdu->securityModel);
  61.         STOREPDUi("securitylevel", pdu->securityLevel);
  62.         STOREPDU("contextName",
  63.                  newSVpv(pdu->contextName, pdu->contextNameLen));
  64.         STOREPDU("contextEngineID",
  65.                  newSVpv(pdu->contextEngineID,
  66.                                     pdu->contextEngineIDLen));
  67.         STOREPDU("securityEngineID",
  68.                  newSVpv(pdu->securityEngineID,
  69.                                     pdu->securityEngineIDLen));
  70.         STOREPDU("securityName",
  71.                  newSVpv(pdu->securityName, pdu->securityNameLen));
  72.     } else {
  73.         STOREPDU("community",
  74.                  newSVpv(pdu->community, pdu->community_len));
  75.     }
  76.     if (transport && transport->f_fmtaddr) {
  77.         char *tstr = transport->f_fmtaddr(transport, pdu->transport_data,
  78.                                           pdu->transport_data_length);
  79.         STOREPDUs("receivedfrom", tstr);
  80.         free(tstr);
  81.     }
  82.     /*
  83.      * collect OID objects in a temp array first
  84.      */
  85.     /* get VARBIND related info */
  86.     i = count_varbinds(pdu->variables);
  87.     tmparray = malloc(sizeof(*tmparray) * i);
  88.     for(vb = pdu->variables; vb; vb = vb->next_variable) {
  89.         /* get the oid */
  90.         o = SNMP_MALLOC_TYPEDEF(netsnmp_oid);
  91.         o->name = o->namebuf;
  92.         o->len = vb->name_length;
  93.         memcpy(o->name, vb->name, vb->name_length * sizeof(oid));
  94. #undef CALL_EXTERNAL_OID_NEW
  95. #ifdef CALL_EXTERNAL_OID_NEW
  96.         PUSHMARK(sp);
  97.         rarg = sv_2mortal(newSViv((int) 0));
  98.         arg = sv_2mortal(newSVrv(rarg, "netsnmp_oidPtr"));
  99.         sv_setiv(arg, (int) o);
  100.         XPUSHs(rarg);
  101.         PUTBACK;
  102.         i = perl_call_pv("NetSNMP::OID::newwithptr", G_SCALAR);
  103.         SPAGAIN;
  104.         if (i != 1) {
  105.             snmp_log(LOG_ERR, "unhandled OID error.n");
  106.             /* ack XXX */
  107.         }
  108.         /* get the value */
  109.         tmparray[c++] = POPs;
  110.         SvREFCNT_inc(tmparray[c-1]);
  111.         PUTBACK;
  112. #else /* build it and bless ourselves */
  113.         {
  114.             HV *hv = newHV();
  115.             SV *rv = newRV_noinc((SV *) hv);
  116.             SV *rvsub = newRV_noinc((SV *) newSViv((U32) o));
  117.             SV *sv;
  118.             rvsub = sv_bless(rvsub, gv_stashpv("netsnmp_oidPtr", 1));
  119.             hv_store(hv, "oidptr", 6,  rvsub, 0);
  120.             rv = sv_bless(rv, gv_stashpv("NetSNMP::OID", 1));
  121.             tmparray[c++] = rv;
  122.         }
  123.         
  124. #endif /* build oid ourselves */
  125.     }
  126.     /*
  127.      * build the varbind lists
  128.      */
  129.     varbinds = newAV();
  130.     for(vb = pdu->variables, i = 0; vb; vb = vb->next_variable, i++) {
  131.         /* push the oid */
  132.         AV *vba;
  133.         vba = newAV();
  134.         /* get the value */
  135.         outbuf = NULL;
  136.         ob_len = 0;
  137.         oo_len = 0;
  138. sprint_realloc_by_type(&outbuf, &ob_len, &oo_len, 1,
  139.                                vb, 0, 0, 0);
  140.         av_push(vba,tmparray[i]);
  141.         av_push(vba,newSVpvn(outbuf, oo_len));
  142.         free(outbuf);
  143.         av_push(vba,newSViv(vb->type));
  144.         av_push(varbinds, (SV *) newRV_noinc((SV *) vba));
  145.     }
  146.     PUSHMARK(sp);
  147.     /* store the collected information on the stack */
  148.     XPUSHs(sv_2mortal(newRV_noinc((SV*) pduinfo)));
  149.     XPUSHs(sv_2mortal(newRV_noinc((SV*) varbinds)));
  150.     /* put the stack back in order */
  151.     PUTBACK;
  152.     /* actually call the callback function */
  153.     if (SvTYPE(pcallback) == SVt_PVCV) {
  154.         perl_call_sv(pcallback, G_DISCARD);
  155.         /* XXX: it discards the results, which isn't right */
  156.     } else if (SvROK(pcallback) && SvTYPE(SvRV(pcallback)) == SVt_PVCV) {
  157.         /* reference to code */
  158.         perl_call_sv(SvRV(pcallback), G_DISCARD);
  159.     } else {
  160.         snmp_log(LOG_ERR, " tried to call a perl function but failed to understand its type: (ref = %x, svrok: %d, SVTYPE: %d)n", pcallback, SvROK(pcallback), SvTYPE(pcallback));
  161.     }
  162. #ifdef DUMPIT
  163.     fprintf(stderr, "DUMPDUMPDUMPDUMPDUMPDUMPn");
  164.     sv_dump(pduinfo);
  165.     fprintf(stderr, "--------------------n");
  166.     sv_dump(varbinds);
  167. #endif
  168.     
  169.     // svREFCNT_dec((SV *) pduinfo);
  170. #ifdef NOT_THIS
  171.     {
  172.         SV *vba;
  173.         while(vba = av_pop(varbinds)) {
  174.             av_undef((AV *) vba);
  175.         }
  176.     }
  177.     av_undef(varbinds);
  178. #endif    
  179.     free(tmparray);
  180.     // Not needed because of the G_DISCARD flag (I think)
  181.     // SPAGAIN;
  182.     // PUTBACK;
  183.     FREETMPS;
  184.     LEAVE;
  185.     return NETSNMPTRAPD_HANDLER_OK;
  186. }
  187. MODULE = NetSNMP::TrapReceiver PACKAGE = NetSNMP::TrapReceiver
  188. INCLUDE: const-xs.inc
  189. MODULE = NetSNMP::TrapReceiver PACKAGE = NetSNMP::TrapReceiver PREFIX=trapd_
  190. int
  191. trapd_register(regoid, perlcallback)
  192. char *regoid;
  193.         SV   *perlcallback;
  194.     PREINIT:
  195. oid myoid[MAX_OID_LEN];
  196. size_t myoid_len = MAX_OID_LEN;
  197.         trapd_cb_data *cb_data;
  198.         int gotit=1;
  199.         netsnmp_trapd_handler *handler = NULL;
  200.     CODE:
  201.         {
  202.             if (!regoid || !perlcallback) {
  203.                 RETVAL = 0;
  204.                 return;
  205.             }
  206.             if (strcmp(regoid,"all") == 0) {
  207.                 handler = 
  208.                     netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER,
  209.                                                    perl_trapd_handler);
  210.             } else if (strcmp(regoid,"default") == 0) {
  211.                 handler = 
  212.                     netsnmp_add_default_traphandler(perl_trapd_handler);
  213.             } else if (!snmp_parse_oid(regoid, myoid, &myoid_len)) {
  214.                 snmp_log(LOG_ERR,
  215.                          "Failed to parse oid for perl registration: %s %dn",
  216.                          regoid);
  217.                 RETVAL = 0;
  218.                 return;
  219.             } else {
  220.                 handler = 
  221.                     netsnmp_add_traphandler(perl_trapd_handler,
  222.                                             myoid, myoid_len);
  223.             }
  224.         
  225.             if (handler) {
  226.                 cb_data = SNMP_MALLOC_TYPEDEF(trapd_cb_data);
  227.                 cb_data->perl_cb = newSVsv(perlcallback);
  228.                 handler->handler_data = cb_data;
  229.                 RETVAL = 1;
  230.             } else {
  231.                 RETVAL = 0;
  232.             }
  233.         }
  234.     OUTPUT:
  235.         RETVAL