Support for Debian/FreeBSD
[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 #include "common/autobuf.h"
80
81 #include "olsrd_dot_draw.h"
82 #include "olsrd_plugin.h"
83
84 #ifdef WIN32
85 #define close(x) closesocket(x)
86 #endif
87
88 #ifdef _WRS_KERNEL
89 static int ipc_open;
90 static int ipc_socket_up;
91 #define DOT_DRAW_PORT 2004
92 #endif
93
94 static int ipc_socket = -1;
95
96 struct autobuf outbuffer;
97 static int outbuffer_socket = -1;
98
99 static struct timer_entry *writetimer_entry = NULL;
100
101 /* IPC initialization function */
102 static int plugin_ipc_init(void);
103
104 /* Event function to register with the sceduler */
105 static int pcf_event(int, int, int);
106
107 static void ipc_action(int);
108
109 static void ipc_print_neigh_link(struct autobuf *abuf, const struct neighbor_entry *neighbor);
110
111 static void ipc_print_tc_link(struct autobuf *abuf, const struct tc_entry *, const struct tc_edge_entry *);
112
113 static void ipc_print_net(struct autobuf *abuf, const union olsr_ip_addr *, const union olsr_ip_addr *, uint8_t);
114
115 /**
116  *Do initialization here
117  *
118  *This function is called by the my_init
119  *function in uolsrd_plugin.c
120  */
121 #ifdef _WRS_KERNEL
122 int
123 olsrd_dotdraw_init(void)
124 #else
125 int
126 olsrd_plugin_init(void)
127 #endif
128 {
129   /* Initial IPC */
130   plugin_ipc_init();
131
132   /* Register the "ProcessChanges" function */
133   register_pcf(&pcf_event);
134
135   return 1;
136 }
137
138 /**
139  * destructor - called at unload
140  */
141 #ifdef _WRS_KERNEL
142 void
143 olsrd_dotdraw_exit(void)
144 #else
145 void
146 olsr_plugin_exit(void)
147 #endif
148 {
149   if (writetimer_entry) {
150     close(outbuffer_socket);
151     abuf_free(&outbuffer);
152     olsr_stop_timer(writetimer_entry);
153   }
154   if (ipc_socket != -1) {
155     CLOSE(ipc_socket);
156   }
157 }
158
159 static void
160 ipc_print_neigh_link(struct autobuf *abuf, const struct neighbor_entry *neighbor)
161 {
162   static const char DASHED[] = "dashed";
163   static const char SOLID[] = "solid";
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 *the_link;
170   struct lqtextbuffer lqbuffer;
171
172   if (neighbor->status == 0) {  /* non SYM */
173     style = DASHED;
174   } else {
175     the_link = get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
176     if (the_link) {
177       etx = the_link->linkcost;
178     }
179     style = SOLID;
180   }
181
182   abuf_appendf(abuf, "\"%s\" -> \"%s\"[label=\"%s\", style=%s];\n", adr, olsr_ip_to_string(&strbuf, &neighbor->neighbor_main_addr),
183                get_linkcost_text(etx, false, &lqbuffer), style);
184
185   if (neighbor->is_mpr) {
186     abuf_appendf(abuf, "\"%s\"[shape=box];\n", adr);
187   }
188 }
189
190 static int
191 plugin_ipc_init(void)
192 {
193   struct sockaddr_in sock_in;
194   uint32_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__ || __FreeBSD_kernel__) && 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(&sock_in, 0, sizeof(sock_in));
224   sock_in.sin_family = AF_INET;
225   sock_in.sin_addr.s_addr = ipc_listen_ip.v4.s_addr;
226   sock_in.sin_port = htons(ipc_port);
227
228   /* bind the socket to the port number */
229   if (bind(ipc_socket, (struct sockaddr *)&sock_in, sizeof(sock_in)) == -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   int ipc_connection;
257
258   ipc_connection = accept(ipc_socket, (struct sockaddr *)&pin, &addrlen);
259   if (ipc_connection == -1) {
260     olsr_printf(1, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
261     return;
262   }
263
264   if (outbuffer_socket != -1) {
265     olsr_printf(1, "(DOT DRAW)Only one connection at once allowed.\n");
266     close(ipc_connection);
267     return;
268   }
269 #ifndef _WRS_KERNEL
270   if (!ip4equal(&pin.sin_addr, &ipc_accept_ip.v4)) {
271     olsr_printf(0, "Front end-connection from foreign host (%s) not allowed!\n", inet_ntoa(pin.sin_addr));
272     CLOSE(ipc_connection);
273     return;
274   }
275 #endif
276   olsr_printf(1, "(DOT DRAW)IPC: Connection from %s\n", inet_ntoa(pin.sin_addr));
277
278   abuf_init(&outbuffer, 4096);
279   outbuffer_socket = ipc_connection;
280
281   pcf_event(1, 1, 1);
282 }
283
284 static void
285 dotdraw_write_data(void *foo __attribute__ ((unused))) {
286   fd_set set;
287   int result;
288   struct timeval tv;
289
290   FD_ZERO(&set);
291   FD_SET(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 = write(outbuffer_socket, outbuffer.buf, outbuffer.len);
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, &tmp_net->A_network_addr, tmp_net->prefixlen);
363       }
364     }
365     OLSR_FOR_ALL_HNA_ENTRIES_END(tmp_hna);
366
367     /* Local HNA entries */
368     for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
369       ipc_print_net(&outbuffer, &olsr_cnf->main_addr, &hna->net.prefix, hna->net.prefix_len);
370     }
371     abuf_puts(&outbuffer, "}\n\n");
372
373     res = 1;
374   }
375
376   if (writetimer_entry == NULL) {
377     writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &dotdraw_write_data, NULL, 0);
378   }
379
380   return res;
381 }
382
383 static void
384 ipc_print_tc_link(struct autobuf *abuf, const struct tc_entry *entry, const struct tc_edge_entry *dst_entry)
385 {
386   struct ipaddr_str strbuf1, strbuf2;
387   struct lqtextbuffer lqbuffer;
388
389   abuf_appendf(abuf, "\"%s\" -> \"%s\"[label=\"%s\"];\n", olsr_ip_to_string(&strbuf1, &entry->addr),
390                olsr_ip_to_string(&strbuf2, &dst_entry->T_dest_addr), get_linkcost_text(dst_entry->cost, false, &lqbuffer));
391 }
392
393 static void
394 ipc_print_net(struct autobuf *abuf, const union olsr_ip_addr *gw, const union olsr_ip_addr *net, uint8_t prefixlen)
395 {
396   struct ipaddr_str gwbuf, netbuf;
397
398   abuf_appendf(abuf, "\"%s\" -> \"%s/%d\"[label=\"HNA\"];\n", olsr_ip_to_string(&gwbuf, gw), olsr_ip_to_string(&netbuf, net), prefixlen);
399
400   abuf_appendf(abuf, "\"%s/%d\"[shape=diamond];\n", olsr_ip_to_string(&netbuf, net), prefixlen);
401 }
402
403 /*
404  * Local Variables:
405  * c-basic-offset: 2
406  * indent-tabs-mode: nil
407  * End:
408  */