rename neighbor and neighbor2_list entry, preparation for neighbor refactoring
[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 "olsrd_dot_draw.h"
47 #include "olsr.h"
48 #include "ipcalc.h"
49 #include "neighbor_table.h"
50 #include "tc_set.h"
51 #include "hna_set.h"
52 #include "link_set.h"
53 #include "olsr_ip_prefix_list.h"
54 #include "olsr_logging.h"
55
56 #ifdef _WRS_KERNEL
57 #include <vxWorks.h>
58 #include <sockLib.h>
59 #include <wrn/coreip/netinet/in.h>
60 #else
61 #include <unistd.h>
62 #include <errno.h>
63 #include <stdarg.h>
64 #endif
65
66 #ifdef _WRS_KERNEL
67 static int ipc_open;
68 static int ipc_socket_up;
69 #define DOT_DRAW_PORT 2004
70 #endif
71
72 static int ipc_socket;
73
74 /* IPC initialization function */
75 static int
76   plugin_ipc_init(void);
77
78 /* Event function to register with the sceduler */
79 static int
80   pcf_event(int, int, int, int);
81
82 static void
83   ipc_action(int, void *, unsigned int);
84
85 static void
86   ipc_print_neigh_link(int, const struct nbr_entry *neighbor);
87
88 static void
89   ipc_print_tc_link(int, const struct tc_entry *, const struct tc_edge_entry *);
90
91 static void
92   ipc_print_net(int, const union olsr_ip_addr *, const struct olsr_ip_prefix *);
93
94 static void
95   ipc_send(int, const char *, int);
96
97 static void
98   ipc_send_fmt(int, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
99
100 #define ipc_send_str(fd, data) ipc_send((fd), (data), strlen(data))
101
102
103 /**
104  *Do initialization here
105  *
106  *This function is called by the my_init
107  *function in uolsrd_plugin.c
108  */
109 #ifdef _WRS_KERNEL
110 int
111 olsrd_dotdraw_init(void)
112 #else
113 int
114 olsrd_plugin_init(void)
115 #endif
116 {
117   /* Initial IPC value */
118   ipc_socket = -1;
119
120   plugin_ipc_init();
121
122   return 1;
123 }
124
125
126 /**
127  * destructor - called at unload
128  */
129 #ifdef _WRS_KERNEL
130 void
131 olsrd_dotdraw_exit(void)
132 #else
133 void
134 olsr_plugin_exit(void)
135 #endif
136 {
137   if (ipc_socket != -1) {
138     CLOSESOCKET(ipc_socket);
139   }
140 }
141
142
143 static void
144 ipc_print_neigh_link(int ipc_connection, const struct nbr_entry *neighbor)
145 {
146   struct ipaddr_str mainaddrstrbuf, strbuf;
147   olsr_linkcost etx = 0.0;
148   const char *style;
149   const char *adr = olsr_ip_to_string(&mainaddrstrbuf, &olsr_cnf->router_id);
150   struct lqtextbuffer lqbuffer;
151
152   if (neighbor->status == 0) {  /* non SYM */
153     style = "dashed";
154   } else {
155     const struct link_entry *lnk = get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
156     if (lnk) {
157       etx = lnk->linkcost;
158     }
159     style = "solid";
160   }
161
162   ipc_send_fmt(ipc_connection,
163                "\"%s\" -> \"%s\"[label=\"%s\", style=%s];\n",
164                adr, olsr_ip_to_string(&strbuf, &neighbor->neighbor_main_addr), get_linkcost_text(etx, false, &lqbuffer), style);
165
166   if (neighbor->is_mpr) {
167     ipc_send_fmt(ipc_connection, "\"%s\"[shape=box];\n", adr);
168   }
169 }
170
171
172 static int
173 plugin_ipc_init(void)
174 {
175   struct sockaddr_in addr;
176   uint32_t yes = 1;
177
178   if (ipc_socket != -1) {
179     CLOSESOCKET(ipc_socket);
180   }
181
182   /* Init ipc socket */
183   ipc_socket = socket(AF_INET, SOCK_STREAM, 0);
184   if (ipc_socket == -1) {
185     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC socket %s\n", strerror(errno));
186     return 0;
187   }
188
189   if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
190     OLSR_WARN(LOG_PLUGINS, "SO_REUSEADDR failed %s\n", strerror(errno));
191     CLOSESOCKET(ipc_socket);
192     return 0;
193   }
194 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
195   if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
196     OLSR_WARN(LOG_PLUGINS, "SO_REUSEADDR failed %s\n", strerror(errno));
197     CLOSESOCKET(ipc_socket);
198     return 0;
199   }
200 #endif
201
202   /* Bind the socket */
203
204   /* complete the socket structure */
205   memset(&addr, 0, sizeof(addr));
206   addr.sin_family = AF_INET;
207   addr.sin_addr.s_addr = INADDR_ANY;
208   addr.sin_port = htons(ipc_port);
209
210   /* bind the socket to the port number */
211   if (bind(ipc_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
212     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC bind %s\n", strerror(errno));
213     CLOSESOCKET(ipc_socket);
214     return 0;
215   }
216
217   /* show that we are willing to listen */
218   if (listen(ipc_socket, 1) == -1) {
219     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC listen %s\n", strerror(errno));
220     CLOSESOCKET(ipc_socket);
221     return 0;
222   }
223
224   /* Register with olsrd */
225   add_olsr_socket(ipc_socket, &ipc_action, NULL, NULL, SP_PR_READ);
226
227   return 1;
228 }
229
230
231 static void
232 ipc_action(int fd __attribute__ ((unused)), void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
233 {
234   struct sockaddr_in pin;
235   socklen_t addrlen = sizeof(struct sockaddr_in);
236   int ipc_connection = accept(ipc_socket, (struct sockaddr *)&pin, &addrlen);
237   if (ipc_connection == -1) {
238     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
239     return;
240   }
241 #ifndef _WRS_KERNEL
242   if (ip4cmp(&pin.sin_addr, &ipc_accept_ip.v4) != 0) {
243     OLSR_WARN(LOG_PLUGINS, "Front end-connection from foreign host (%s) not allowed!\n", inet_ntoa(pin.sin_addr));
244     CLOSESOCKET(ipc_connection);
245     return;
246   }
247 #endif
248   OLSR_DEBUG(LOG_PLUGINS, "(DOT DRAW)IPC: Connection from %s\n", inet_ntoa(pin.sin_addr));
249   pcf_event(ipc_connection, 1, 1, 1);
250   CLOSESOCKET(ipc_connection);  /* close connection after one output */
251 }
252
253
254 /**
255  *Scheduled event
256  */
257 static int
258 pcf_event(int ipc_connection, int chgs_neighborhood, int chgs_topology, int chgs_hna)
259 {
260   int res = 0;
261
262   if (chgs_neighborhood || chgs_topology || chgs_hna) {
263     struct nbr_entry *neighbor_table_tmp;
264     struct tc_entry *tc;
265     struct ip_prefix_entry *hna;
266
267     /* Print tables to IPC socket */
268     ipc_send_str(ipc_connection, "digraph topology\n{\n");
269
270     /* Neighbors */
271     OLSR_FOR_ALL_NBR_ENTRIES(neighbor_table_tmp) {
272       ipc_print_neigh_link(ipc_connection, neighbor_table_tmp);
273     } OLSR_FOR_ALL_NBR_ENTRIES_END(neighbor_table_tmp);
274
275     /* Topology */
276     OLSR_FOR_ALL_TC_ENTRIES(tc) {
277       struct tc_edge_entry *tc_edge;
278       OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
279         if (tc_edge->edge_inv) {
280           ipc_print_tc_link(ipc_connection, tc, tc_edge);
281         }
282       }
283       OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
284     }
285     OLSR_FOR_ALL_TC_ENTRIES_END(tc);
286
287     /* HNA entries */
288     OLSR_FOR_ALL_TC_ENTRIES(tc) {
289       /* Check all networks */
290       struct hna_net *tmp_net;
291       OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, tmp_net) {
292         ipc_print_net(ipc_connection, &tc->addr, &tmp_net->hna_prefix);
293       }
294     } OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, tmp_hna);
295     OLSR_FOR_ALL_TC_ENTRIES_END(tc);
296
297     /* Local HNA entries */
298     OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, hna) {
299       ipc_print_net(ipc_connection, &olsr_cnf->router_id, &hna->net);
300     } OLSR_FOR_ALL_IPPREFIX_ENTRIES_END()
301       ipc_send_str(ipc_connection, "}\n\n");
302
303     res = 1;
304   }
305
306   if (ipc_socket == -1) {
307     plugin_ipc_init();
308   }
309   return res;
310 }
311
312 static void
313 ipc_print_tc_link(int ipc_connection, const struct tc_entry *entry, const struct tc_edge_entry *dst_entry)
314 {
315   struct ipaddr_str strbuf1, strbuf2;
316   struct lqtextbuffer lqbuffer;
317
318   ipc_send_fmt(ipc_connection,
319                "\"%s\" -> \"%s\"[label=\"%s\"];\n",
320                olsr_ip_to_string(&strbuf1, &entry->addr),
321                olsr_ip_to_string(&strbuf2, &dst_entry->T_dest_addr), get_linkcost_text(dst_entry->cost, false, &lqbuffer));
322 }
323
324
325 static void
326 ipc_print_net(int ipc_connection, const union olsr_ip_addr *gw, const struct olsr_ip_prefix *net)
327 {
328   struct ipaddr_str gwbuf;
329   struct ipprefix_str netbuf;
330
331   ipc_send_fmt(ipc_connection,
332                "\"%s\" -> \"%s\"[label=\"HNA\"];\n", olsr_ip_to_string(&gwbuf, gw), olsr_ip_prefix_to_string(&netbuf, net));
333   ipc_send_fmt(ipc_connection, "\"%s\"[shape=diamond];\n", netbuf.buf);
334 }
335
336 static void
337 ipc_send(int ipc_connection, const char *data, int size)
338 {
339   if (ipc_connection != -1) {
340 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __MacOSX__ || \
341 defined _WRS_KERNEL
342 #define FLAGS 0
343 #else
344 #define FLAGS MSG_NOSIGNAL
345 #endif
346     if (send(ipc_connection, data, size, FLAGS) == -1) {
347       OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC connection lost!\n");
348       CLOSESOCKET(ipc_connection);
349     }
350   }
351 }
352
353 static void
354 ipc_send_fmt(int ipc_connection, const char *format, ...)
355 {
356   if (ipc_connection != -1) {
357     char buf[4096];
358     int len;
359     va_list arg;
360     va_start(arg, format);
361     len = vsnprintf(buf, sizeof(buf), format, arg);
362     va_end(arg);
363     ipc_send(ipc_connection, buf, len);
364   }
365 }
366
367 /*
368  * Local Variables:
369  * c-basic-offset: 2
370  * indent-tabs-mode: nil
371  * End:
372  */