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