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

SNMP编程

开发平台:

Unix_Linux

  1. #include <net-snmp/net-snmp-config.h>
  2. #include <stdio.h>
  3. #include <sys/types.h>
  4. #include <ctype.h>
  5. #include <errno.h>
  6. #ifdef WIN32
  7. #include <net-snmp/library/winpipe.h>
  8. #endif
  9. #if HAVE_STRING_H
  10. #include <string.h>
  11. #else
  12. #include <strings.h>
  13. #endif
  14. #if HAVE_STDLIB_H
  15. #include <stdlib.h>
  16. #endif
  17. #if HAVE_UNISTD_H
  18. #include <unistd.h>
  19. #endif
  20. #if HAVE_SYS_SOCKET_H
  21. #include <sys/socket.h>
  22. #endif
  23. #if HAVE_SYS_UN_H
  24. #include <sys/un.h>
  25. #endif
  26. #if HAVE_IO_H
  27. #include <io.h>
  28. #endif
  29. #if HAVE_FCNTL_H
  30. #include <fcntl.h>
  31. #endif
  32. #if HAVE_DMALLOC_H
  33. #include <dmalloc.h>
  34. #endif
  35. #include <net-snmp/types.h>
  36. #include <net-snmp/output_api.h>
  37. #include <net-snmp/config_api.h>
  38. #include <net-snmp/utilities.h>
  39. #include <net-snmp/library/snmp_transport.h>
  40. #include <net-snmp/library/snmpUnixDomain.h>
  41. #include <net-snmp/library/snmp_api.h>
  42. #include <net-snmp/library/snmp_client.h>
  43. #include <net-snmp/library/snmpCallbackDomain.h>
  44. #ifndef NETSNMP_STREAM_QUEUE_LEN
  45. #define NETSNMP_STREAM_QUEUE_LEN  5
  46. #endif
  47. #ifdef SNMP_TRANSPORT_CALLBACK_DOMAIN
  48. static netsnmp_transport_list *trlist = NULL;
  49. static int      callback_count = 0;
  50. typedef struct callback_hack_s {
  51.     void           *orig_transport_data;
  52.     netsnmp_pdu    *pdu;
  53. } callback_hack;
  54. typedef struct callback_queue_s {
  55.     int             callback_num;
  56.     netsnmp_callback_pass *item;
  57.     struct callback_queue_s *next, *prev;
  58. } callback_queue;
  59. callback_queue *thequeue;
  60. static netsnmp_transport *
  61. find_transport_from_callback_num(int num)
  62. {
  63.     static netsnmp_transport_list *ptr;
  64.     for (ptr = trlist; ptr; ptr = ptr->next)
  65.         if (((netsnmp_callback_info *) ptr->transport->data)->
  66.             callback_num == num)
  67.             return ptr->transport;
  68.     return NULL;
  69. }
  70. static void
  71. callback_debug_pdu(const char *ourstring, netsnmp_pdu *pdu)
  72. {
  73.     netsnmp_variable_list *vb;
  74.     int             i = 1;
  75.     DEBUGMSGTL((ourstring,
  76.                 "PDU: command = %d, errstat = %d, errindex = %dn",
  77.                 pdu->command, pdu->errstat, pdu->errindex));
  78.     for (vb = pdu->variables; vb; vb = vb->next_variable) {
  79.         DEBUGMSGTL((ourstring, "  var %d:", i++));
  80.         DEBUGMSGVAR((ourstring, vb));
  81.         DEBUGMSG((ourstring, "n"));
  82.     }
  83. }
  84. void
  85. callback_push_queue(int num, netsnmp_callback_pass *item)
  86. {
  87.     callback_queue *newitem = SNMP_MALLOC_TYPEDEF(callback_queue);
  88.     callback_queue *ptr;
  89.     newitem->callback_num = num;
  90.     newitem->item = item;
  91.     if (thequeue) {
  92.         for (ptr = thequeue; ptr && ptr->next; ptr = ptr->next) {
  93.         }
  94.         ptr->next = newitem;
  95.         newitem->prev = ptr;
  96.     } else {
  97.         thequeue = newitem;
  98.     }
  99.     DEBUGIF("dump_send_callback_transport") {
  100.         callback_debug_pdu("dump_send_callback_transport", item->pdu);
  101.     }
  102. }
  103. netsnmp_callback_pass *
  104. callback_pop_queue(int num)
  105. {
  106.     netsnmp_callback_pass *cp;
  107.     callback_queue *ptr;
  108.     for (ptr = thequeue; ptr; ptr = ptr->next) {
  109.         if (ptr->callback_num == num) {
  110.             if (ptr->prev) {
  111.                 ptr->prev->next = ptr->next;
  112.             } else {
  113.                 thequeue = ptr->next;
  114.             }
  115.             if (ptr->next) {
  116.                 ptr->next->prev = ptr->prev;
  117.             }
  118.             cp = ptr->item;
  119.             SNMP_FREE(ptr);
  120.             DEBUGIF("dump_recv_callback_transport") {
  121.                 callback_debug_pdu("dump_recv_callback_transport",
  122.                                    cp->pdu);
  123.             }
  124.             return cp;
  125.         }
  126.     }
  127.     return NULL;
  128. }
  129. /*
  130.  * Return a string representing the address in data, or else the "far end"
  131.  * address if data is NULL.  
  132.  */
  133. char *
  134. netsnmp_callback_fmtaddr(netsnmp_transport *t, void *data, int len)
  135. {
  136.     char buf[SPRINT_MAX_LEN];
  137.     netsnmp_callback_info *mystuff;
  138.     if (!t)
  139.         return strdup("callback: unknown");
  140.     mystuff = (netsnmp_callback_info *) t->data;
  141.     if (!mystuff)
  142.         return strdup("callback: unknown");
  143.     snprintf(buf, SPRINT_MAX_LEN, "callback: %d on fd %d",
  144.              mystuff->callback_num, mystuff->pipefds[0]);
  145.     return strdup(buf);
  146. }
  147. /*
  148.  * You can write something into opaque that will subsequently get passed back 
  149.  * to your send function if you like.  For instance, you might want to
  150.  * remember where a PDU came from, so that you can send a reply there...  
  151.  */
  152. int
  153. netsnmp_callback_recv(netsnmp_transport *t, void *buf, int size,
  154.       void **opaque, int *olength)
  155. {
  156.     int rc = -1;
  157.     char newbuf[1];
  158.     netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
  159.     DEBUGMSGTL(("transport_callback", "hook_recv entern"));
  160.     while (rc < 0) {
  161. #ifdef WIN32
  162. rc = recv(mystuff->pipefds[0], newbuf, 1, 0);
  163. #else
  164. rc = read(mystuff->pipefds[0], newbuf, 1);
  165. #endif
  166. if (rc < 0 && errno != EINTR) {
  167.     break;
  168. }
  169.     }
  170.     if (mystuff->linkedto) {
  171.         /*
  172.          * we're the client.  We don't need to do anything. 
  173.          */
  174.     } else {
  175.         /*
  176.          * malloc the space here, but it's filled in by
  177.          * snmp_callback_created_pdu() below 
  178.          */
  179.         int            *returnnum = (int *) calloc(1, sizeof(int));
  180.         *opaque = returnnum;
  181.         *olength = sizeof(int);
  182.     }
  183.     DEBUGMSGTL(("transport_callback", "hook_recv exitn"));
  184.     return rc;
  185. }
  186. int
  187. netsnmp_callback_send(netsnmp_transport *t, void *buf, int size,
  188.       void **opaque, int *olength)
  189. {
  190.     int from, rc = -1;
  191.     netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
  192.     netsnmp_callback_pass *cp;
  193.     /*
  194.      * extract the pdu from the hacked buffer 
  195.      */
  196.     netsnmp_transport *other_side;
  197.     callback_hack  *ch = (callback_hack *) * opaque;
  198.     netsnmp_pdu    *pdu = ch->pdu;
  199.     *opaque = ch->orig_transport_data;
  200.     SNMP_FREE(ch);
  201.     DEBUGMSGTL(("transport_callback", "hook_send entern"));
  202.     cp = SNMP_MALLOC_TYPEDEF(netsnmp_callback_pass);
  203.     if (!cp)
  204.         return -1;
  205.     cp->pdu = snmp_clone_pdu(pdu);
  206.     if (cp->pdu->transport_data) {
  207.         /*
  208.          * not needed and not properly freed later 
  209.          */
  210.         SNMP_FREE(cp->pdu->transport_data);
  211.     }
  212.     if (cp->pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE)
  213.         cp->pdu->flags ^= UCD_MSG_FLAG_EXPECT_RESPONSE;
  214.     /*
  215.      * push the sent pdu onto the stack 
  216.      */
  217.     /*
  218.      * AND send a bogus byte to the remote callback receiver's pipe 
  219.      */
  220.     if (mystuff->linkedto) {
  221.         /*
  222.          * we're the client, send it to the parent 
  223.          */
  224.         cp->return_transport_num = mystuff->callback_num;
  225.         other_side = find_transport_from_callback_num(mystuff->linkedto);
  226.         if (!other_side)
  227.             return -1;
  228. while (rc < 0) {
  229. #ifdef WIN32
  230.     rc = send(((netsnmp_callback_info*) other_side->data)->pipefds[1], " ", 1, 0);
  231. #else
  232.     rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1],
  233.        " ", 1);
  234. #endif
  235.     if (rc < 0 && errno != EINTR) {
  236. break;
  237.     }
  238. }
  239.         callback_push_queue(mystuff->linkedto, cp);
  240.         /*
  241.          * we don't need the transport data any more 
  242.          */
  243.         if (*opaque) {
  244.             SNMP_FREE(*opaque);
  245.             *opaque = NULL;
  246.         }
  247.     } else {
  248.         /*
  249.          * we're the server, send it to the person that sent us the request 
  250.          */
  251.         from = **((int **) opaque);
  252.         /*
  253.          * we don't need the transport data any more 
  254.          */
  255.         if (*opaque) {
  256.             SNMP_FREE(*opaque);
  257.             *opaque = NULL;
  258.         }
  259.         other_side = find_transport_from_callback_num(from);
  260.         if (!other_side)
  261.             return -1;
  262. while (rc < 0) {
  263. #ifdef WIN32
  264.     rc = send(((netsnmp_callback_info*) other_side->data)->pipefds[1], " ", 1, 0);
  265. #else
  266.     rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1],
  267.        " ", 1);
  268. #endif
  269.     if (rc < 0 && errno != EINTR) {
  270. break;
  271.     }
  272. }
  273.         callback_push_queue(from, cp);
  274.     }
  275.     DEBUGMSGTL(("transport_callback", "hook_send exitn"));
  276.     return 0;
  277. }
  278. int
  279. netsnmp_callback_close(netsnmp_transport *t)
  280. {
  281.     int             rc;
  282.     netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
  283.     DEBUGMSGTL(("transport_callback", "hook_close entern"));
  284. #ifdef WIN32
  285.     rc  = closesocket(mystuff->pipefds[0]);
  286.     rc |= closesocket(mystuff->pipefds[1]);
  287. #else
  288.     rc  = close(mystuff->pipefds[0]);
  289.     rc |= close(mystuff->pipefds[1]);
  290. #endif
  291.     rc |= netsnmp_transport_remove_from_list(&trlist, t);
  292.     DEBUGMSGTL(("transport_callback", "hook_close exitn"));
  293.     return rc;
  294. }
  295. int
  296. netsnmp_callback_accept(netsnmp_transport *t)
  297. {
  298.     DEBUGMSGTL(("transport_callback", "hook_accept entern"));
  299.     DEBUGMSGTL(("transport_callback", "hook_accept exitn"));
  300.     return 0;
  301. }
  302. /*
  303.  * Open a Callback-domain transport for SNMP.  Local is TRUE if addr
  304.  * is the local address to bind to (i.e. this is a server-type
  305.  * session); otherwise addr is the remote address to send things to
  306.  * (and we make up a temporary name for the local end of the
  307.  * connection).  
  308.  */
  309. netsnmp_transport *
  310. netsnmp_callback_transport(int to)
  311. {
  312.     netsnmp_transport *t = NULL;
  313.     netsnmp_callback_info *mydata;
  314.     int             rc;
  315.     /*
  316.      * transport 
  317.      */
  318.     t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
  319.     if (!t)
  320.         return NULL;
  321.     /*
  322.      * our stuff 
  323.      */
  324.     mydata = SNMP_MALLOC_TYPEDEF(netsnmp_callback_info);
  325.     mydata->linkedto = to;
  326.     mydata->callback_num = ++callback_count;
  327.     mydata->data = NULL;
  328.     t->data = mydata;
  329. #ifdef WIN32
  330.     rc = create_winpipe_transport(mydata->pipefds);
  331. #else
  332.     rc = pipe(mydata->pipefds);
  333. #endif
  334.     t->sock = mydata->pipefds[0];
  335.     if (rc) {
  336.         SNMP_FREE(mydata);
  337.         SNMP_FREE(t);
  338.         return NULL;
  339.     }
  340.     t->f_recv    = netsnmp_callback_recv;
  341.     t->f_send    = netsnmp_callback_send;
  342.     t->f_close   = netsnmp_callback_close;
  343.     t->f_accept  = netsnmp_callback_accept;
  344.     t->f_fmtaddr = netsnmp_callback_fmtaddr;
  345.     netsnmp_transport_add_to_list(&trlist, t);
  346.     if (to)
  347.         DEBUGMSGTL(("transport_callback", "initialized %d linked to %dn",
  348.                     mydata->callback_num, to));
  349.     else
  350.         DEBUGMSGTL(("transport_callback",
  351.                     "initialized master listening on %dn",
  352.                     mydata->callback_num));
  353.     return t;
  354. }
  355. int
  356. netsnmp_callback_hook_parse(netsnmp_session * sp,
  357.                             netsnmp_pdu *pdu,
  358.                             u_char * packetptr, size_t len)
  359. {
  360.     if (SNMP_MSG_RESPONSE == pdu->command ||
  361.         SNMP_MSG_REPORT == pdu->command)
  362.         pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
  363.     else
  364.         pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
  365.     return SNMP_ERR_NOERROR;
  366. }
  367. int
  368. netsnmp_callback_hook_build(netsnmp_session * sp,
  369.                             netsnmp_pdu *pdu, u_char * ptk, size_t * len)
  370. {
  371.     /*
  372.      * very gross hack, as this is passed later to the transport_send
  373.      * function 
  374.      */
  375.     callback_hack  *ch = SNMP_MALLOC_TYPEDEF(callback_hack);
  376.     DEBUGMSGTL(("transport_callback", "hook_build entern"));
  377.     ch->pdu = pdu;
  378.     ch->orig_transport_data = pdu->transport_data;
  379.     pdu->transport_data = ch;
  380.     switch (pdu->command) {
  381.     case SNMP_MSG_RESPONSE:
  382.     case SNMP_MSG_TRAP:
  383.     case SNMP_MSG_TRAP2:
  384.         pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
  385.         break;
  386.     }
  387.     *len = 1;
  388.     DEBUGMSGTL(("transport_callback", "hook_build exitn"));
  389.     return 1;
  390. }
  391. int
  392. netsnmp_callback_check_packet(u_char * pkt, size_t len)
  393. {
  394.     return 1;
  395. }
  396. netsnmp_pdu    *
  397. netsnmp_callback_create_pdu(netsnmp_transport *transport,
  398.                             void *opaque, size_t olength)
  399. {
  400.     netsnmp_pdu    *pdu;
  401.     netsnmp_callback_pass *cp =
  402.         callback_pop_queue(((netsnmp_callback_info *) transport->data)->
  403.                            callback_num);
  404.     if (!cp)
  405.         return NULL;
  406.     pdu = cp->pdu;
  407.     pdu->transport_data = opaque;
  408.     pdu->transport_data_length = olength;
  409.     if (opaque)                 /* if created, we're the server */
  410.         *((int *) opaque) = cp->return_transport_num;
  411.     SNMP_FREE(cp);
  412.     return pdu;
  413. }
  414. netsnmp_session *
  415. netsnmp_callback_open(int attach_to,
  416.                       int (*return_func) (int op,
  417.                                           netsnmp_session * session,
  418.                                           int reqid, netsnmp_pdu *pdu,
  419.                                           void *magic),
  420.                       int (*fpre_parse) (netsnmp_session *,
  421.                                          struct netsnmp_transport_s *,
  422.                                          void *, int),
  423.                       int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
  424.                                           int))
  425. {
  426.     netsnmp_session callback_sess, *callback_ss;
  427.     netsnmp_transport *callback_tr;
  428.     callback_tr = netsnmp_callback_transport(attach_to);
  429.     snmp_sess_init(&callback_sess);
  430.     callback_sess.callback = return_func;
  431.     if (attach_to) {
  432.         /*
  433.          * client 
  434.          */
  435.         /*
  436.          * trysess.community = (u_char *) callback_ss; 
  437.          */
  438.     } else {
  439.         callback_sess.isAuthoritative = SNMP_SESS_AUTHORITATIVE;
  440.     }
  441.     callback_sess.remote_port = 0;
  442.     callback_sess.retries = 0;
  443.     callback_sess.timeout = 30000000;
  444.     callback_sess.version = SNMP_DEFAULT_VERSION;       /* (mostly) bogus */
  445.     callback_ss = snmp_add_full(&callback_sess, callback_tr,
  446.                                 fpre_parse,
  447.                                 netsnmp_callback_hook_parse, fpost_parse,
  448.                                 netsnmp_callback_hook_build,
  449.                                 NULL,
  450.                                 netsnmp_callback_check_packet,
  451.                                 netsnmp_callback_create_pdu);
  452.     if (callback_ss)
  453.         callback_ss->local_port =
  454.             ((netsnmp_callback_info *) callback_tr->data)->callback_num;
  455.     return callback_ss;
  456. }
  457. void
  458. netsnmp_clear_callback_list(void)
  459. {
  460.     netsnmp_transport_list *list = trlist, *next = NULL;
  461.     netsnmp_transport *tr = NULL;
  462.     DEBUGMSGTL(("callback_clear", "called netsnmp_callback_clear_list()n"));
  463.     while (list != NULL) {
  464. next = list->next;
  465. tr = list->transport;
  466. if (tr != NULL) {
  467.     tr->f_close(tr);
  468.        netsnmp_transport_remove_from_list(&trlist, list->transport);
  469.     netsnmp_transport_free(list->transport);
  470. }
  471. list = next;
  472.     }
  473.     trlist = NULL;
  474. }
  475. #endif /* SNMP_TRANSPORT_CALLBACK_DOMAIN */