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