1 #include <net-snmp/net-snmp-config.h>
20 #include <sys/socket.h>
36 #include <net-snmp/types.h>
37 #include <net-snmp/output_api.h>
38 #include <net-snmp/config_api.h>
39 #include <net-snmp/utilities.h>
41 #include <net-snmp/library/snmp_transport.h>
42 #include <net-snmp/library/snmpUnixDomain.h>
43 #include <net-snmp/library/snmp_api.h>
44 #include <net-snmp/library/snmp_client.h>
45 #include <net-snmp/library/snmpCallbackDomain.h>
47 #ifndef NETSNMP_STREAM_QUEUE_LEN
48 #define NETSNMP_STREAM_QUEUE_LEN 5
51 static netsnmp_transport_list *trlist = NULL;
53 static int callback_count = 0;
55 typedef struct callback_hack_s {
56 void *orig_transport_data;
60 typedef struct callback_queue_s {
62 netsnmp_callback_pass *item;
63 struct callback_queue_s *next, *prev;
66 callback_queue *thequeue;
68 static netsnmp_transport *
69 find_transport_from_callback_num(int num)
71 static netsnmp_transport_list *ptr;
72 for (ptr = trlist; ptr; ptr = ptr->next)
73 if (((netsnmp_callback_info *) ptr->transport->data)->
75 return ptr->transport;
80 callback_debug_pdu(const char *ourstring, netsnmp_pdu *pdu)
82 netsnmp_variable_list *vb;
84 DEBUGMSGTL((ourstring,
85 "PDU: command = %d, errstat = %d, errindex = %d\n",
86 pdu->command, pdu->errstat, pdu->errindex));
87 for (vb = pdu->variables; vb; vb = vb->next_variable) {
88 DEBUGMSGTL((ourstring, " var %d:", i++));
89 DEBUGMSGVAR((ourstring, vb));
90 DEBUGMSG((ourstring, "\n"));
95 callback_push_queue(int num, netsnmp_callback_pass *item)
97 callback_queue *newitem = SNMP_MALLOC_TYPEDEF(callback_queue);
100 newitem->callback_num = num;
101 newitem->item = item;
103 for (ptr = thequeue; ptr && ptr->next; ptr = ptr->next) {
110 DEBUGIF("dump_send_callback_transport") {
111 callback_debug_pdu("dump_send_callback_transport", item->pdu);
115 netsnmp_callback_pass *
116 callback_pop_queue(int num)
118 netsnmp_callback_pass *cp;
121 for (ptr = thequeue; ptr; ptr = ptr->next) {
122 if (ptr->callback_num == num) {
124 ptr->prev->next = ptr->next;
126 thequeue = ptr->next;
129 ptr->next->prev = ptr->prev;
133 DEBUGIF("dump_recv_callback_transport") {
134 callback_debug_pdu("dump_recv_callback_transport",
144 * Return a string representing the address in data, or else the "far end"
145 * address if data is NULL.
149 netsnmp_callback_fmtaddr(netsnmp_transport *t, void *data, int len)
151 char buf[SPRINT_MAX_LEN];
152 netsnmp_callback_info *mystuff;
155 return strdup("callback: unknown");
157 mystuff = (netsnmp_callback_info *) t->data;
160 return strdup("callback: unknown");
162 snprintf(buf, SPRINT_MAX_LEN, "callback: %d on fd %d",
163 mystuff->callback_num, mystuff->pipefds[0]);
170 * You can write something into opaque that will subsequently get passed back
171 * to your send function if you like. For instance, you might want to
172 * remember where a PDU came from, so that you can send a reply there...
176 netsnmp_callback_recv(netsnmp_transport *t, void *buf, int size,
177 void **opaque, int *olength)
181 netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
183 DEBUGMSGTL(("transport_callback", "hook_recv enter\n"));
186 rc = read(mystuff->pipefds[0], newbuf, 1);
187 if (rc < 0 && errno != EINTR) {
192 if (mystuff->linkedto) {
194 * we're the client. We don't need to do anything.
198 * malloc the space here, but it's filled in by
199 * snmp_callback_created_pdu() below
201 int *returnnum = (int *) calloc(1, sizeof(int));
203 *olength = sizeof(int);
205 DEBUGMSGTL(("transport_callback", "hook_recv exit\n"));
212 netsnmp_callback_send(netsnmp_transport *t, void *buf, int size,
213 void **opaque, int *olength)
216 netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
217 netsnmp_callback_pass *cp;
220 * extract the pdu from the hacked buffer
222 netsnmp_transport *other_side;
223 callback_hack *ch = (callback_hack *) * opaque;
224 netsnmp_pdu *pdu = ch->pdu;
225 *opaque = ch->orig_transport_data;
228 DEBUGMSGTL(("transport_callback", "hook_send enter\n"));
230 cp = SNMP_MALLOC_TYPEDEF(netsnmp_callback_pass);
234 cp->pdu = snmp_clone_pdu(pdu);
235 if (cp->pdu->transport_data) {
237 * not needed and not properly freed later
239 SNMP_FREE(cp->pdu->transport_data);
242 if (cp->pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE)
243 cp->pdu->flags ^= UCD_MSG_FLAG_EXPECT_RESPONSE;
246 * push the sent pdu onto the stack
249 * AND send a bogus byte to the remote callback receiver's pipe
251 if (mystuff->linkedto) {
253 * we're the client, send it to the parent
255 cp->return_transport_num = mystuff->callback_num;
257 other_side = find_transport_from_callback_num(mystuff->linkedto);
262 rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1],
264 if (rc < 0 && errno != EINTR) {
268 callback_push_queue(mystuff->linkedto, cp);
270 * we don't need the transport data any more
278 * we're the server, send it to the person that sent us the request
280 from = **((int **) opaque);
282 * we don't need the transport data any more
288 other_side = find_transport_from_callback_num(from);
292 rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1],
294 if (rc < 0 && errno != EINTR) {
298 callback_push_queue(from, cp);
301 DEBUGMSGTL(("transport_callback", "hook_send exit\n"));
308 netsnmp_callback_close(netsnmp_transport *t)
311 netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
312 DEBUGMSGTL(("transport_callback", "hook_close enter\n"));
314 rc = close(mystuff->pipefds[0]);
315 rc = close(mystuff->pipefds[1]);
317 netsnmp_transport_remove_from_list(&trlist, t);
319 DEBUGMSGTL(("transport_callback", "hook_close exit\n"));
326 netsnmp_callback_accept(netsnmp_transport *t)
328 DEBUGMSGTL(("transport_callback", "hook_accept enter\n"));
329 DEBUGMSGTL(("transport_callback", "hook_accept exit\n"));
336 * Open a Callback-domain transport for SNMP. Local is TRUE if addr
337 * is the local address to bind to (i.e. this is a server-type
338 * session); otherwise addr is the remote address to send things to
339 * (and we make up a temporary name for the local end of the
344 netsnmp_callback_transport(int to)
347 netsnmp_transport *t = NULL;
348 netsnmp_callback_info *mydata;
354 t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
361 mydata = SNMP_MALLOC_TYPEDEF(netsnmp_callback_info);
362 mydata->linkedto = to;
363 mydata->callback_num = ++callback_count;
368 rc = _pipe(mydata->pipefds, 1024, O_BINARY);
370 rc = pipe(mydata->pipefds);
372 t->sock = mydata->pipefds[0];
380 t->f_recv = netsnmp_callback_recv;
381 t->f_send = netsnmp_callback_send;
382 t->f_close = netsnmp_callback_close;
383 t->f_accept = netsnmp_callback_accept;
384 t->f_fmtaddr = netsnmp_callback_fmtaddr;
386 netsnmp_transport_add_to_list(&trlist, t);
389 DEBUGMSGTL(("transport_callback", "initialized %d linked to %d\n",
390 mydata->callback_num, to));
392 DEBUGMSGTL(("transport_callback",
393 "initialized master listening on %d\n",
394 mydata->callback_num));
399 netsnmp_callback_hook_parse(netsnmp_session * sp,
401 u_char * packetptr, size_t len)
403 if (SNMP_MSG_RESPONSE == pdu->command ||
404 SNMP_MSG_REPORT == pdu->command)
405 pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
407 pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
409 return SNMP_ERR_NOERROR;
413 netsnmp_callback_hook_build(netsnmp_session * sp,
414 netsnmp_pdu *pdu, u_char * ptk, size_t * len)
417 * very gross hack, as this is passed later to the transport_send
420 callback_hack *ch = SNMP_MALLOC_TYPEDEF(callback_hack);
421 DEBUGMSGTL(("transport_callback", "hook_build enter\n"));
423 ch->orig_transport_data = pdu->transport_data;
424 pdu->transport_data = ch;
425 switch (pdu->command) {
426 case SNMP_MSG_RESPONSE:
429 pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
433 DEBUGMSGTL(("transport_callback", "hook_build exit\n"));
438 netsnmp_callback_check_packet(u_char * pkt, size_t len)
444 netsnmp_callback_create_pdu(netsnmp_transport *transport,
445 void *opaque, size_t olength)
448 netsnmp_callback_pass *cp =
449 callback_pop_queue(((netsnmp_callback_info *) transport->data)->
454 pdu->transport_data = opaque;
455 pdu->transport_data_length = olength;
456 if (opaque) /* if created, we're the server */
457 *((int *) opaque) = cp->return_transport_num;
463 netsnmp_callback_open(int attach_to,
464 int (*return_func) (int op,
465 netsnmp_session * session,
466 int reqid, netsnmp_pdu *pdu,
468 int (*fpre_parse) (netsnmp_session *,
469 struct netsnmp_transport_s *,
471 int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
474 netsnmp_session callback_sess, *callback_ss;
475 netsnmp_transport *callback_tr;
477 callback_tr = netsnmp_callback_transport(attach_to);
478 snmp_sess_init(&callback_sess);
479 callback_sess.callback = return_func;
485 * trysess.community = (u_char *) callback_ss;
488 callback_sess.isAuthoritative = SNMP_SESS_AUTHORITATIVE;
490 callback_sess.remote_port = 0;
491 callback_sess.retries = 0;
492 callback_sess.timeout = 30000000;
493 callback_sess.version = SNMP_DEFAULT_VERSION; /* (mostly) bogus */
494 callback_ss = snmp_add_full(&callback_sess, callback_tr,
496 netsnmp_callback_hook_parse, fpost_parse,
497 netsnmp_callback_hook_build,
499 netsnmp_callback_check_packet,
500 netsnmp_callback_create_pdu);
502 callback_ss->local_port =
503 ((netsnmp_callback_info *) callback_tr->data)->callback_num;