f37cf6b5896344762a97149098ac755ae9c3bf88
[olsrd.git] / lib / dot_draw / src / olsrd_dot_draw.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /*
43  * Dynamic linked library for the olsr.org olsr daemon
44  */
45
46 #include "olsr.h"
47 #include "ipcalc.h"
48 #include "neighbor_table.h"
49 #include "tc_set.h"
50 #include "hna_set.h"
51 #include "link_set.h"
52 #include "olsr_ip_prefix_list.h"
53 #include "olsr_logging.h"
54 #include "os_net.h"
55 #include "plugin_util.h"
56
57 #ifdef _WRS_KERNEL
58 #include <vxWorks.h>
59 #include <sockLib.h>
60 #include <wrn/coreip/netinet/in.h>
61 #else
62 #include <unistd.h>
63 #include <errno.h>
64 #include <stdarg.h>
65 #endif
66
67 #define PLUGIN_DESCR    "OLSRD dot draw plugin"
68 #define PLUGIN_AUTHOR   "Andreas Tonnesen"
69
70 #ifdef _WRS_KERNEL
71 static int ipc_open;
72 static int ipc_socket_up;
73 #define DOT_DRAW_PORT 2004
74 #endif
75
76 static int dotdraw_init(void);
77 static int dotdraw_enable(void);
78 static int dotdraw_exit(void);
79
80 static int ipc_socket;
81
82 static union olsr_ip_addr ipc_accept_ip;
83 static int ipc_port;
84
85 /* plugin parameters */
86 static const struct olsrd_plugin_parameters plugin_parameters[] = {
87   {.name = "port",.set_plugin_parameter = &set_plugin_port,.data = &ipc_port},
88   {.name = "accept",.set_plugin_parameter = &set_plugin_ipaddress,.data = &ipc_accept_ip},
89 };
90
91 OLSR_PLUGIN6(plugin_parameters) {
92   .descr = PLUGIN_DESCR,
93   .author = PLUGIN_AUTHOR,
94   .init = dotdraw_init,
95   .enable = dotdraw_enable,
96   .exit = dotdraw_exit,
97   .deactivate = false
98 };
99
100 /* Event function to register with the sceduler */
101 static int
102   pcf_event(int, int, int, int);
103
104 static void
105   ipc_action(int, void *, unsigned int);
106
107 static void
108   ipc_print_neigh_link(int, const struct nbr_entry *neighbor);
109
110 static void
111   ipc_print_tc_link(int, const struct tc_entry *, const struct tc_edge_entry *);
112
113 static void
114   ipc_print_net(int, const union olsr_ip_addr *, const struct olsr_ip_prefix *);
115
116 static void
117   ipc_send(int, const char *, int);
118
119 static void
120   ipc_send_fmt(int, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
121
122 #define ipc_send_str(fd, data) ipc_send((fd), (data), strlen(data))
123
124
125 static int
126 dotdraw_init(void)
127 {
128   /* defaults for parameters */
129   ipc_port = 2004;
130   ipc_accept_ip.v4.s_addr = htonl(INADDR_LOOPBACK);
131
132   ipc_socket = -1;
133   return 0;
134 }
135
136 /**
137  * destructor - called at unload
138  */
139 static int
140 dotdraw_exit(void)
141 {
142   if (ipc_socket != -1) {
143     os_close(ipc_socket);
144     ipc_socket = -1;
145   }
146   return 0;
147 }
148
149
150 static void
151 ipc_print_neigh_link(int ipc_connection, const struct nbr_entry *neighbor)
152 {
153   struct ipaddr_str mainaddrstrbuf, strbuf;
154   olsr_linkcost etx = 0.0;
155   const char *style;
156   const char *adr = olsr_ip_to_string(&mainaddrstrbuf, &olsr_cnf->router_id);
157   char lqbuffer[LQTEXT_MAXLENGTH];
158
159   if (neighbor->is_sym == 0) {  /* non SYM */
160     style = "dashed";
161   } else {
162     const struct link_entry *lnk = get_best_link_to_neighbor_ip(&neighbor->nbr_addr);
163     if (lnk) {
164       etx = lnk->linkcost;
165     }
166     style = "solid";
167   }
168
169   ipc_send_fmt(ipc_connection,
170                "\"%s\" -> \"%s\"[label=\"%s\", style=%s];\n",
171                adr, olsr_ip_to_string(&strbuf, &neighbor->nbr_addr),
172                olsr_get_linkcost_text(etx, false, lqbuffer, sizeof(lqbuffer)), style);
173
174   if (neighbor->is_mpr) {
175     ipc_send_fmt(ipc_connection, "\"%s\"[shape=box];\n", adr);
176   }
177 }
178
179 static int
180 dotdraw_enable(void) {
181   struct sockaddr_in addr;
182   uint32_t yes = 1;
183
184   if (ipc_socket != -1) {
185     os_close(ipc_socket);
186   }
187
188   /* Init ipc socket */
189   ipc_socket = socket(AF_INET, SOCK_STREAM, 0);
190   if (ipc_socket == -1) {
191     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC socket %s\n", strerror(errno));
192     return 1;
193   }
194
195   if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
196     OLSR_WARN(LOG_PLUGINS, "SO_REUSEADDR failed %s\n", strerror(errno));
197     os_close(ipc_socket);
198     return 1;
199   }
200 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
201   if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
202     OLSR_WARN(LOG_PLUGINS, "SO_REUSEADDR failed %s\n", strerror(errno));
203     CLOSESOCKET(ipc_socket);
204     return 1;
205   }
206 #endif
207
208   /* Bind the socket */
209
210   /* complete the socket structure */
211   memset(&addr, 0, sizeof(addr));
212   addr.sin_family = AF_INET;
213   addr.sin_addr.s_addr = INADDR_ANY;
214   addr.sin_port = htons(ipc_port);
215
216   /* bind the socket to the port number */
217   if (bind(ipc_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
218     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC bind %s\n", strerror(errno));
219     os_close(ipc_socket);
220     return 1;
221   }
222
223   /* show that we are willing to listen */
224   if (listen(ipc_socket, 1) == -1) {
225     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC listen %s\n", strerror(errno));
226     os_close(ipc_socket);
227     return 1;
228   }
229
230   /* Register socket with olsrd */
231   add_olsr_socket(ipc_socket, &ipc_action, NULL, NULL, SP_PR_READ);
232
233   return 0;
234 }
235
236
237 static void
238 ipc_action(int fd __attribute__ ((unused)), void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
239 {
240   struct sockaddr_in pin;
241   socklen_t addrlen = sizeof(struct sockaddr_in);
242   int ipc_connection = accept(ipc_socket, (struct sockaddr *)&pin, &addrlen);
243   if (ipc_connection == -1) {
244     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
245     return;
246   }
247 #ifndef _WRS_KERNEL
248   if (ip4cmp(&pin.sin_addr, &ipc_accept_ip.v4) != 0) {
249     OLSR_WARN(LOG_PLUGINS, "Front end-connection from foreign host (%s) not allowed!\n", inet_ntoa(pin.sin_addr));
250     os_close(ipc_connection);
251     return;
252   }
253 #endif
254   OLSR_DEBUG(LOG_PLUGINS, "(DOT DRAW)IPC: Connection from %s\n", inet_ntoa(pin.sin_addr));
255   pcf_event(ipc_connection, 1, 1, 1);
256   os_close(ipc_connection);  /* close connection after one output */
257 }
258
259
260 /**
261  *Scheduled event
262  */
263 static int
264 pcf_event(int ipc_connection, int chgs_neighborhood, int chgs_topology, int chgs_hna)
265 {
266   int res = 0;
267
268   if (chgs_neighborhood || chgs_topology || chgs_hna) {
269     struct nbr_entry *neighbor_table_tmp, *nbr_iterator;
270     struct tc_entry *tc, *tc_iterator;
271     struct hna_net *hna, *hna_iterator;
272     struct ip_prefix_entry *prefix, *prefix_iterator;
273
274     /* Print tables to IPC socket */
275     ipc_send_str(ipc_connection, "digraph topology\n{\n");
276
277     /* Neighbors */
278     OLSR_FOR_ALL_NBR_ENTRIES(neighbor_table_tmp, nbr_iterator) {
279       ipc_print_neigh_link(ipc_connection, neighbor_table_tmp);
280     }
281
282     /* Topology */
283     OLSR_FOR_ALL_TC_ENTRIES(tc, tc_iterator) {
284       struct tc_edge_entry *tc_edge, *edge_iterator;
285       OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge, edge_iterator) {
286         if (tc_edge->edge_inv) {
287           ipc_print_tc_link(ipc_connection, tc, tc_edge);
288         }
289       }
290     }
291
292     /* HNA entries */
293     OLSR_FOR_ALL_TC_ENTRIES(tc, tc_iterator) {
294       /* Check all networks */
295       OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, hna, hna_iterator) {
296         ipc_print_net(ipc_connection, &tc->addr, &hna->hna_prefix);
297       }
298     }
299
300     /* Local HNA entries */
301     OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, prefix, prefix_iterator) {
302       ipc_print_net(ipc_connection, &olsr_cnf->router_id, &prefix->net);
303     }
304       ipc_send_str(ipc_connection, "}\n\n");
305
306     res = 1;
307   }
308
309   if (ipc_socket == -1) {
310     dotdraw_enable();
311   }
312   return res;
313 }
314
315 static void
316 ipc_print_tc_link(int ipc_connection, const struct tc_entry *entry, const struct tc_edge_entry *dst_entry)
317 {
318   struct ipaddr_str strbuf1, strbuf2;
319   char lqbuffer[LQTEXT_MAXLENGTH];
320
321   ipc_send_fmt(ipc_connection,
322                "\"%s\" -> \"%s\"[label=\"%s\"];\n",
323                olsr_ip_to_string(&strbuf1, &entry->addr),
324                olsr_ip_to_string(&strbuf2, &dst_entry->T_dest_addr),
325                olsr_get_linkcost_text(dst_entry->cost, false, lqbuffer, sizeof(lqbuffer)));
326 }
327
328
329 static void
330 ipc_print_net(int ipc_connection, const union olsr_ip_addr *gw, const struct olsr_ip_prefix *net)
331 {
332   struct ipaddr_str gwbuf;
333   struct ipprefix_str netbuf;
334
335   ipc_send_fmt(ipc_connection,
336                "\"%s\" -> \"%s\"[label=\"HNA\"];\n", olsr_ip_to_string(&gwbuf, gw), olsr_ip_prefix_to_string(&netbuf, net));
337   ipc_send_fmt(ipc_connection, "\"%s\"[shape=diamond];\n", netbuf.buf);
338 }
339
340 static void
341 ipc_send(int ipc_connection, const char *data, int size)
342 {
343   if (ipc_connection != -1) {
344 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __MacOSX__ || \
345 defined _WRS_KERNEL
346 #define FLAGS 0
347 #else
348 #define FLAGS MSG_NOSIGNAL
349 #endif
350     if (send(ipc_connection, data, size, FLAGS) == -1) {
351       OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC connection lost!\n");
352       os_close(ipc_connection);
353     }
354   }
355 }
356
357 static void
358 ipc_send_fmt(int ipc_connection, const char *format, ...)
359 {
360   if (ipc_connection != -1) {
361     char buf[4096];
362     int len;
363     va_list arg;
364     va_start(arg, format);
365     len = vsnprintf(buf, sizeof(buf), format, arg);
366     va_end(arg);
367     ipc_send(ipc_connection, buf, len);
368   }
369 }
370
371 /*
372  * Local Variables:
373  * c-basic-offset: 2
374  * indent-tabs-mode: nil
375  * End:
376  */