snmpCallbackDomain.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:14k
- #include <net-snmp/net-snmp-config.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <ctype.h>
- #include <errno.h>
- #ifdef WIN32
- #include <net-snmp/library/winpipe.h>
- #endif
- #if HAVE_STRING_H
- #include <string.h>
- #else
- #include <strings.h>
- #endif
- #if HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #if HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #if HAVE_SYS_SOCKET_H
- #include <sys/socket.h>
- #endif
- #if HAVE_SYS_UN_H
- #include <sys/un.h>
- #endif
- #if HAVE_IO_H
- #include <io.h>
- #endif
- #if HAVE_FCNTL_H
- #include <fcntl.h>
- #endif
- #if HAVE_DMALLOC_H
- #include <dmalloc.h>
- #endif
- #include <net-snmp/types.h>
- #include <net-snmp/output_api.h>
- #include <net-snmp/config_api.h>
- #include <net-snmp/utilities.h>
- #include <net-snmp/library/snmp_transport.h>
- #include <net-snmp/library/snmpUnixDomain.h>
- #include <net-snmp/library/snmp_api.h>
- #include <net-snmp/library/snmp_client.h>
- #include <net-snmp/library/snmpCallbackDomain.h>
- #ifndef NETSNMP_STREAM_QUEUE_LEN
- #define NETSNMP_STREAM_QUEUE_LEN 5
- #endif
- #ifdef SNMP_TRANSPORT_CALLBACK_DOMAIN
- static netsnmp_transport_list *trlist = NULL;
- static int callback_count = 0;
- typedef struct callback_hack_s {
- void *orig_transport_data;
- netsnmp_pdu *pdu;
- } callback_hack;
- typedef struct callback_queue_s {
- int callback_num;
- netsnmp_callback_pass *item;
- struct callback_queue_s *next, *prev;
- } callback_queue;
- callback_queue *thequeue;
- static netsnmp_transport *
- find_transport_from_callback_num(int num)
- {
- static netsnmp_transport_list *ptr;
- for (ptr = trlist; ptr; ptr = ptr->next)
- if (((netsnmp_callback_info *) ptr->transport->data)->
- callback_num == num)
- return ptr->transport;
- return NULL;
- }
- static void
- callback_debug_pdu(const char *ourstring, netsnmp_pdu *pdu)
- {
- netsnmp_variable_list *vb;
- int i = 1;
- DEBUGMSGTL((ourstring,
- "PDU: command = %d, errstat = %d, errindex = %dn",
- pdu->command, pdu->errstat, pdu->errindex));
- for (vb = pdu->variables; vb; vb = vb->next_variable) {
- DEBUGMSGTL((ourstring, " var %d:", i++));
- DEBUGMSGVAR((ourstring, vb));
- DEBUGMSG((ourstring, "n"));
- }
- }
- void
- callback_push_queue(int num, netsnmp_callback_pass *item)
- {
- callback_queue *newitem = SNMP_MALLOC_TYPEDEF(callback_queue);
- callback_queue *ptr;
- newitem->callback_num = num;
- newitem->item = item;
- if (thequeue) {
- for (ptr = thequeue; ptr && ptr->next; ptr = ptr->next) {
- }
- ptr->next = newitem;
- newitem->prev = ptr;
- } else {
- thequeue = newitem;
- }
- DEBUGIF("dump_send_callback_transport") {
- callback_debug_pdu("dump_send_callback_transport", item->pdu);
- }
- }
- netsnmp_callback_pass *
- callback_pop_queue(int num)
- {
- netsnmp_callback_pass *cp;
- callback_queue *ptr;
- for (ptr = thequeue; ptr; ptr = ptr->next) {
- if (ptr->callback_num == num) {
- if (ptr->prev) {
- ptr->prev->next = ptr->next;
- } else {
- thequeue = ptr->next;
- }
- if (ptr->next) {
- ptr->next->prev = ptr->prev;
- }
- cp = ptr->item;
- SNMP_FREE(ptr);
- DEBUGIF("dump_recv_callback_transport") {
- callback_debug_pdu("dump_recv_callback_transport",
- cp->pdu);
- }
- return cp;
- }
- }
- return NULL;
- }
- /*
- * Return a string representing the address in data, or else the "far end"
- * address if data is NULL.
- */
- char *
- netsnmp_callback_fmtaddr(netsnmp_transport *t, void *data, int len)
- {
- char buf[SPRINT_MAX_LEN];
- netsnmp_callback_info *mystuff;
- if (!t)
- return strdup("callback: unknown");
- mystuff = (netsnmp_callback_info *) t->data;
- if (!mystuff)
- return strdup("callback: unknown");
- snprintf(buf, SPRINT_MAX_LEN, "callback: %d on fd %d",
- mystuff->callback_num, mystuff->pipefds[0]);
- return strdup(buf);
- }
- /*
- * You can write something into opaque that will subsequently get passed back
- * to your send function if you like. For instance, you might want to
- * remember where a PDU came from, so that you can send a reply there...
- */
- int
- netsnmp_callback_recv(netsnmp_transport *t, void *buf, int size,
- void **opaque, int *olength)
- {
- int rc = -1;
- char newbuf[1];
- netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
- DEBUGMSGTL(("transport_callback", "hook_recv entern"));
- while (rc < 0) {
- #ifdef WIN32
- rc = recv(mystuff->pipefds[0], newbuf, 1, 0);
- #else
- rc = read(mystuff->pipefds[0], newbuf, 1);
- #endif
- if (rc < 0 && errno != EINTR) {
- break;
- }
- }
- if (mystuff->linkedto) {
- /*
- * we're the client. We don't need to do anything.
- */
- } else {
- /*
- * malloc the space here, but it's filled in by
- * snmp_callback_created_pdu() below
- */
- int *returnnum = (int *) calloc(1, sizeof(int));
- *opaque = returnnum;
- *olength = sizeof(int);
- }
- DEBUGMSGTL(("transport_callback", "hook_recv exitn"));
- return rc;
- }
- int
- netsnmp_callback_send(netsnmp_transport *t, void *buf, int size,
- void **opaque, int *olength)
- {
- int from, rc = -1;
- netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
- netsnmp_callback_pass *cp;
- /*
- * extract the pdu from the hacked buffer
- */
- netsnmp_transport *other_side;
- callback_hack *ch = (callback_hack *) * opaque;
- netsnmp_pdu *pdu = ch->pdu;
- *opaque = ch->orig_transport_data;
- SNMP_FREE(ch);
- DEBUGMSGTL(("transport_callback", "hook_send entern"));
- cp = SNMP_MALLOC_TYPEDEF(netsnmp_callback_pass);
- if (!cp)
- return -1;
- cp->pdu = snmp_clone_pdu(pdu);
- if (cp->pdu->transport_data) {
- /*
- * not needed and not properly freed later
- */
- SNMP_FREE(cp->pdu->transport_data);
- }
- if (cp->pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE)
- cp->pdu->flags ^= UCD_MSG_FLAG_EXPECT_RESPONSE;
- /*
- * push the sent pdu onto the stack
- */
- /*
- * AND send a bogus byte to the remote callback receiver's pipe
- */
- if (mystuff->linkedto) {
- /*
- * we're the client, send it to the parent
- */
- cp->return_transport_num = mystuff->callback_num;
- other_side = find_transport_from_callback_num(mystuff->linkedto);
- if (!other_side)
- return -1;
- while (rc < 0) {
- #ifdef WIN32
- rc = send(((netsnmp_callback_info*) other_side->data)->pipefds[1], " ", 1, 0);
- #else
- rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1],
- " ", 1);
- #endif
- if (rc < 0 && errno != EINTR) {
- break;
- }
- }
- callback_push_queue(mystuff->linkedto, cp);
- /*
- * we don't need the transport data any more
- */
- if (*opaque) {
- SNMP_FREE(*opaque);
- *opaque = NULL;
- }
- } else {
- /*
- * we're the server, send it to the person that sent us the request
- */
- from = **((int **) opaque);
- /*
- * we don't need the transport data any more
- */
- if (*opaque) {
- SNMP_FREE(*opaque);
- *opaque = NULL;
- }
- other_side = find_transport_from_callback_num(from);
- if (!other_side)
- return -1;
- while (rc < 0) {
- #ifdef WIN32
- rc = send(((netsnmp_callback_info*) other_side->data)->pipefds[1], " ", 1, 0);
- #else
- rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1],
- " ", 1);
- #endif
- if (rc < 0 && errno != EINTR) {
- break;
- }
- }
- callback_push_queue(from, cp);
- }
- DEBUGMSGTL(("transport_callback", "hook_send exitn"));
- return 0;
- }
- int
- netsnmp_callback_close(netsnmp_transport *t)
- {
- int rc;
- netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
- DEBUGMSGTL(("transport_callback", "hook_close entern"));
- #ifdef WIN32
- rc = closesocket(mystuff->pipefds[0]);
- rc |= closesocket(mystuff->pipefds[1]);
- #else
- rc = close(mystuff->pipefds[0]);
- rc |= close(mystuff->pipefds[1]);
- #endif
- rc |= netsnmp_transport_remove_from_list(&trlist, t);
- DEBUGMSGTL(("transport_callback", "hook_close exitn"));
- return rc;
- }
- int
- netsnmp_callback_accept(netsnmp_transport *t)
- {
- DEBUGMSGTL(("transport_callback", "hook_accept entern"));
- DEBUGMSGTL(("transport_callback", "hook_accept exitn"));
- return 0;
- }
- /*
- * Open a Callback-domain transport for SNMP. Local is TRUE if addr
- * is the local address to bind to (i.e. this is a server-type
- * session); otherwise addr is the remote address to send things to
- * (and we make up a temporary name for the local end of the
- * connection).
- */
- netsnmp_transport *
- netsnmp_callback_transport(int to)
- {
- netsnmp_transport *t = NULL;
- netsnmp_callback_info *mydata;
- int rc;
- /*
- * transport
- */
- t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
- if (!t)
- return NULL;
- /*
- * our stuff
- */
- mydata = SNMP_MALLOC_TYPEDEF(netsnmp_callback_info);
- mydata->linkedto = to;
- mydata->callback_num = ++callback_count;
- mydata->data = NULL;
- t->data = mydata;
- #ifdef WIN32
- rc = create_winpipe_transport(mydata->pipefds);
- #else
- rc = pipe(mydata->pipefds);
- #endif
- t->sock = mydata->pipefds[0];
- if (rc) {
- SNMP_FREE(mydata);
- SNMP_FREE(t);
- return NULL;
- }
- t->f_recv = netsnmp_callback_recv;
- t->f_send = netsnmp_callback_send;
- t->f_close = netsnmp_callback_close;
- t->f_accept = netsnmp_callback_accept;
- t->f_fmtaddr = netsnmp_callback_fmtaddr;
- netsnmp_transport_add_to_list(&trlist, t);
- if (to)
- DEBUGMSGTL(("transport_callback", "initialized %d linked to %dn",
- mydata->callback_num, to));
- else
- DEBUGMSGTL(("transport_callback",
- "initialized master listening on %dn",
- mydata->callback_num));
- return t;
- }
- int
- netsnmp_callback_hook_parse(netsnmp_session * sp,
- netsnmp_pdu *pdu,
- u_char * packetptr, size_t len)
- {
- if (SNMP_MSG_RESPONSE == pdu->command ||
- SNMP_MSG_REPORT == pdu->command)
- pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
- else
- pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
- return SNMP_ERR_NOERROR;
- }
- int
- netsnmp_callback_hook_build(netsnmp_session * sp,
- netsnmp_pdu *pdu, u_char * ptk, size_t * len)
- {
- /*
- * very gross hack, as this is passed later to the transport_send
- * function
- */
- callback_hack *ch = SNMP_MALLOC_TYPEDEF(callback_hack);
- DEBUGMSGTL(("transport_callback", "hook_build entern"));
- ch->pdu = pdu;
- ch->orig_transport_data = pdu->transport_data;
- pdu->transport_data = ch;
- switch (pdu->command) {
- case SNMP_MSG_RESPONSE:
- case SNMP_MSG_TRAP:
- case SNMP_MSG_TRAP2:
- pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
- break;
- }
- *len = 1;
- DEBUGMSGTL(("transport_callback", "hook_build exitn"));
- return 1;
- }
- int
- netsnmp_callback_check_packet(u_char * pkt, size_t len)
- {
- return 1;
- }
- netsnmp_pdu *
- netsnmp_callback_create_pdu(netsnmp_transport *transport,
- void *opaque, size_t olength)
- {
- netsnmp_pdu *pdu;
- netsnmp_callback_pass *cp =
- callback_pop_queue(((netsnmp_callback_info *) transport->data)->
- callback_num);
- if (!cp)
- return NULL;
- pdu = cp->pdu;
- pdu->transport_data = opaque;
- pdu->transport_data_length = olength;
- if (opaque) /* if created, we're the server */
- *((int *) opaque) = cp->return_transport_num;
- SNMP_FREE(cp);
- return pdu;
- }
- netsnmp_session *
- netsnmp_callback_open(int attach_to,
- int (*return_func) (int op,
- netsnmp_session * session,
- int reqid, netsnmp_pdu *pdu,
- void *magic),
- int (*fpre_parse) (netsnmp_session *,
- struct netsnmp_transport_s *,
- void *, int),
- int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
- int))
- {
- netsnmp_session callback_sess, *callback_ss;
- netsnmp_transport *callback_tr;
- callback_tr = netsnmp_callback_transport(attach_to);
- snmp_sess_init(&callback_sess);
- callback_sess.callback = return_func;
- if (attach_to) {
- /*
- * client
- */
- /*
- * trysess.community = (u_char *) callback_ss;
- */
- } else {
- callback_sess.isAuthoritative = SNMP_SESS_AUTHORITATIVE;
- }
- callback_sess.remote_port = 0;
- callback_sess.retries = 0;
- callback_sess.timeout = 30000000;
- callback_sess.version = SNMP_DEFAULT_VERSION; /* (mostly) bogus */
- callback_ss = snmp_add_full(&callback_sess, callback_tr,
- fpre_parse,
- netsnmp_callback_hook_parse, fpost_parse,
- netsnmp_callback_hook_build,
- NULL,
- netsnmp_callback_check_packet,
- netsnmp_callback_create_pdu);
- if (callback_ss)
- callback_ss->local_port =
- ((netsnmp_callback_info *) callback_tr->data)->callback_num;
- return callback_ss;
- }
- void
- netsnmp_clear_callback_list(void)
- {
- netsnmp_transport_list *list = trlist, *next = NULL;
- netsnmp_transport *tr = NULL;
- DEBUGMSGTL(("callback_clear", "called netsnmp_callback_clear_list()n"));
- while (list != NULL) {
- next = list->next;
- tr = list->transport;
- if (tr != NULL) {
- tr->f_close(tr);
- netsnmp_transport_remove_from_list(&trlist, list->transport);
- netsnmp_transport_free(list->transport);
- }
- list = next;
- }
- trlist = NULL;
- }
- #endif /* SNMP_TRANSPORT_CALLBACK_DOMAIN */