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