eccf20e6b58a2a00928869bb341639d55bc26749
[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 T√łnnesen(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  * $Id: olsrd_dot_draw.c,v 1.33 2007/11/16 19:52:09 bernd67 Exp $
41  */
42
43 /*
44  * Dynamic linked library for the olsr.org olsr daemon
45  */
46
47  
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <netinet/in.h>
51 #include <arpa/inet.h>
52 #include <sys/time.h>
53 #include <time.h>
54 #include <math.h>
55 #include <stdio.h>
56 #include <string.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <errno.h>
60 #include <stdarg.h>
61
62 #include "olsr.h"
63 #include "olsr_types.h"
64 #include "neighbor_table.h"
65 #include "two_hop_neighbor_table.h"
66 #include "tc_set.h"
67 #include "hna_set.h"
68 #include "mid_set.h"
69 #include "link_set.h"
70 #include "socket_parser.h"
71 #include "net_olsr.h"
72
73 #include "olsrd_dot_draw.h"
74 #include "olsrd_plugin.h"
75
76
77 #ifdef WIN32
78 #define close(x) closesocket(x)
79 #endif
80
81
82 static int ipc_socket;
83 static int ipc_connection;
84
85
86
87 /* IPC initialization function */
88 static int
89 plugin_ipc_init(void);
90
91 static char*
92 olsr_netmask_to_string(const union hna_netmask *mask);
93
94 /* Event function to register with the sceduler */
95 static int
96 pcf_event(int, int, int);
97
98 static void
99 ipc_action(int);
100
101 static void
102 ipc_print_neigh_link(const struct neighbor_entry *neighbor);
103
104 static void
105 ipc_print_tc_link(const struct tc_entry *entry, const struct tc_edge_entry *dst_entry);
106
107 static void
108 ipc_print_net(const union olsr_ip_addr *, const union olsr_ip_addr *, const union hna_netmask *);
109
110 static void
111 ipc_send(const char *, int);
112
113 static void
114 ipc_send_fmt(const char *format, ...) __attribute__((format(printf,1,2)));
115
116 #define ipc_send_str(data) ipc_send((data), strlen(data))
117
118
119 /**
120  *Do initialization here
121  *
122  *This function is called by the my_init
123  *function in uolsrd_plugin.c
124  */
125 int
126 olsrd_plugin_init(void)
127 {
128   /* Initial IPC value */
129   ipc_socket = -1;
130   ipc_connection = -1;
131
132   /* Register the "ProcessChanges" function */
133   register_pcf(&pcf_event);
134
135   plugin_ipc_init();
136
137   return 1;
138 }
139
140
141 /**
142  * destructor - called at unload
143  */
144 void
145 olsr_plugin_exit(void)
146 {
147   if (ipc_connection != -1) {
148     CLOSE(ipc_connection);
149   }
150   if (ipc_socket != -1) {
151     CLOSE(ipc_socket);
152   }
153 }
154
155
156 static void
157 ipc_print_neigh_link(const struct neighbor_entry *neighbor)
158 {
159   struct ipaddr_str mainaddrstrbuf, strbuf;
160   double etx = 0.0;
161   const char *style;
162   const char *adr = olsr_ip_to_string(&mainaddrstrbuf, &olsr_cnf->main_addr);
163   struct link_entry* link;
164
165   if (neighbor->status == 0) { // non SYM
166     style = "dashed";
167   } else {   
168     link = get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
169     if (link) {
170       etx = olsr_calc_link_etx(link);
171     }
172     style = "solid";
173   }
174     
175   ipc_send_fmt("\"%s\" -> \"%s\"[label=\"%.2f\", style=%s];\n",
176                adr,
177                olsr_ip_to_string(&strbuf, &neighbor->neighbor_main_addr),
178                etx,
179                style);
180   
181   if (neighbor->is_mpr) {
182     ipc_send_fmt("\"%s\"[shape=box];\n", adr);
183   }
184 }
185
186
187 static int
188 plugin_ipc_init(void)
189 {
190   struct sockaddr_in sin;
191   olsr_u32_t yes = 1;
192
193   if (ipc_socket != -1) {
194     close(ipc_socket);
195   }
196
197   /* Init ipc socket */
198   ipc_socket = socket(AF_INET, SOCK_STREAM, 0);
199   if (ipc_socket == -1) {
200     olsr_printf(1, "(DOT DRAW)IPC socket %s\n", strerror(errno));
201     return 0;
202   }
203
204   if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
205     perror("SO_REUSEADDR failed");
206     CLOSE(ipc_socket);
207     return 0;
208   }
209
210 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
211   if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
212     perror("SO_REUSEADDR failed");
213     CLOSE(ipc_socket);
214     return 0;
215   }
216 #endif
217
218   /* Bind the socket */
219       
220   /* complete the socket structure */
221   memset(&sin, 0, sizeof(sin));
222   sin.sin_family = AF_INET;
223   sin.sin_addr.s_addr = INADDR_ANY;
224   sin.sin_port = htons(ipc_port);
225       
226   /* bind the socket to the port number */
227   if (bind(ipc_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
228     olsr_printf(1, "(DOT DRAW)IPC bind %s\n", strerror(errno));
229     CLOSE(ipc_socket);
230     return 0;
231   }
232       
233   /* show that we are willing to listen */
234   if (listen(ipc_socket, 1) == -1) {
235     olsr_printf(1, "(DOT DRAW)IPC listen %s\n", strerror(errno));
236     CLOSE(ipc_socket);
237     return 0;
238   }
239
240   /* Register with olsrd */
241   //printf("Adding socket with olsrd\n");
242   add_olsr_socket(ipc_socket, &ipc_action);
243
244   return 1;
245 }
246
247
248 static void
249 ipc_action(int fd __attribute__((unused)))
250 {
251   struct sockaddr_in pin;
252   socklen_t addrlen = sizeof(struct sockaddr_in);
253
254   if (ipc_connection != -1) {
255     close(ipc_connection);
256   }
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   if (!ip4equal(&pin.sin_addr, &ipc_accept_ip.v4)) {
264     olsr_printf(0, "Front end-connection from foreign host (%s) not allowed!\n", inet_ntoa(pin.sin_addr));
265     CLOSE(ipc_connection);
266     return;
267   }
268   olsr_printf(1, "(DOT DRAW)IPC: Connection from %s\n", inet_ntoa(pin.sin_addr));
269   pcf_event(1, 1, 1);
270 }
271
272
273 /**
274  *Scheduled event
275  */
276 static int
277 pcf_event(int changes_neighborhood,
278           int changes_topology,
279           int changes_hna)
280 {
281   int res = 0;
282   if(changes_neighborhood || changes_topology || changes_hna) {
283     struct neighbor_entry *neighbor_table_tmp;
284     struct tc_entry *tc;
285     struct tc_edge_entry *tc_edge;
286     struct local_hna_entry *hna;
287     int idx;
288     
289     /* Print tables to IPC socket */
290     ipc_send_str("digraph topology\n{\n");
291
292     /* Neighbors */
293     for (idx = 0; idx < HASHSIZE; idx++) {        
294       for(neighbor_table_tmp = neighbortable[idx].next;
295           neighbor_table_tmp != &neighbortable[idx];
296           neighbor_table_tmp = neighbor_table_tmp->next){
297         ipc_print_neigh_link( neighbor_table_tmp );
298       }
299     }
300
301     /* Topology */  
302     OLSR_FOR_ALL_TC_ENTRIES(tc) {
303       OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
304         ipc_print_tc_link(tc, tc_edge);
305       } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
306     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
307
308     /* HNA entries */
309     for (idx = 0; idx < HASHSIZE; idx++) {
310       struct hna_entry *tmp_hna;
311       /* Check all entrys */
312       for (tmp_hna = hna_set[idx].next; tmp_hna != &hna_set[idx]; tmp_hna = tmp_hna->next) {
313         /* Check all networks */
314         struct hna_net *tmp_net;
315         for (tmp_net = tmp_hna->networks.next; tmp_net != &tmp_hna->networks; tmp_net = tmp_net->next) {
316           ipc_print_net(&tmp_hna->A_gateway_addr, 
317                         &tmp_net->A_network_addr, 
318                         &tmp_net->A_netmask);
319         }
320       }
321     }
322
323     /* Local HNA entries */
324     for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
325       union hna_netmask hna_msk;
326       if (olsr_cnf->ip_version == AF_INET) {
327         union olsr_ip_addr netmask;
328         //hna_msk.v4 = hna4->netmask.v4;
329         olsr_prefix_to_netmask(&netmask, hna->net.prefix_len);
330         hna_msk.v4 = netmask.v4.s_addr;
331       } else {
332         hna_msk.v6 = hna->net.prefix_len;
333       }
334       ipc_print_net(&olsr_cnf->interfaces->interf->ip_addr,
335                     &hna->net.prefix,
336                     &hna_msk);
337     }
338     ipc_send_str("}\n\n");
339
340     res = 1;
341   }
342
343   if (ipc_socket == -1) {
344     plugin_ipc_init();
345   }
346   return res;
347 }
348
349 static void
350 ipc_print_tc_link(const struct tc_entry *entry, const struct tc_edge_entry *dst_entry)
351 {
352   struct ipaddr_str strbuf1, strbuf2;
353
354   ipc_send_fmt("\"%s\" -> \"%s\"[label=\"%.2f\"];\n",
355                olsr_ip_to_string(&strbuf1, &entry->addr),
356                olsr_ip_to_string(&strbuf2, &dst_entry->T_dest_addr),
357                olsr_calc_tc_etx(dst_entry));
358 }
359
360
361 static void
362 ipc_print_net(const union olsr_ip_addr *gw, const union olsr_ip_addr *net, const union hna_netmask *mask)
363 {
364   struct ipaddr_str gwbuf, netbuf;
365
366   ipc_send_fmt("\"%s\" -> \"%s/%s\"[label=\"HNA\"];\n",
367                olsr_ip_to_string(&gwbuf, gw),
368                olsr_ip_to_string(&netbuf, net),
369                olsr_netmask_to_string(mask));
370
371   ipc_send_fmt("\"%s/%s\"[shape=diamond];\n",
372                olsr_ip_to_string(&netbuf, net),
373                olsr_netmask_to_string(mask));
374 }
375
376 static void
377 ipc_send(const char *data, int size)
378 {
379   if (ipc_connection != -1) {
380 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __MacOSX__
381 #define FLAGS 0
382 #else
383 #define FLAGS MSG_NOSIGNAL
384 #endif
385     if (send(ipc_connection, data, size, FLAGS) == -1) {
386       olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
387       CLOSE(ipc_connection);
388     }
389   }
390 }
391
392 static void
393 ipc_send_fmt(const char *format, ...)
394 {
395   if (ipc_connection != -1) {
396     char buf[4096];
397     int len;
398     va_list arg;
399     va_start(arg, format);
400     len = vsnprintf(buf, sizeof(buf), format, arg);
401     va_end(arg);
402     ipc_send(buf, len);
403   }
404 }
405
406 static char*
407 olsr_netmask_to_string(const union hna_netmask *mask)
408 {
409   char *ret;
410   struct in_addr in;
411
412   if (olsr_cnf->ip_version == AF_INET) {
413       in.s_addr = mask->v4;
414       ret = inet_ntoa(in);
415   } else {
416       /* IPv6 */
417       static char netmask[5];
418       sprintf(netmask, "%d", mask->v6);
419       ret = netmask;
420   }
421   return ret;
422 }