Removed duplicate includes
[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.17 2005/07/13 21:43:16 kattemat 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
61 #include "olsr.h"
62 #include "olsr_types.h"
63 #include "neighbor_table.h"
64 #include "two_hop_neighbor_table.h"
65 #include "tc_set.h"
66 #include "hna_set.h"
67 #include "mid_set.h"
68 #include "link_set.h"
69 #include "socket_parser.h"
70
71 #include "olsrd_dot_draw.h"
72 #include "olsrd_plugin.h"
73
74
75 #ifdef WIN32
76 #define close(x) closesocket(x)
77 #endif
78
79
80 int ipc_socket;
81 int ipc_open;
82 int ipc_connection;
83 int ipc_socket_up;
84
85
86 /* IPC initialization function */
87 static int
88 plugin_ipc_init(void);
89
90 static char*
91 olsr_netmask_to_string(union hna_netmask *mask);
92
93 /* Event function to register with the sceduler */
94 static int
95 pcf_event(int, int, int);
96
97 static void
98 ipc_action(int);
99
100 static void inline
101 ipc_print_neigh_link(struct neighbor_entry *neighbor);
102
103 static void inline
104 ipc_print_tc_link(struct tc_entry *entry, struct topo_dst *dst_entry);
105
106 static void inline
107 ipc_print_net(union olsr_ip_addr *, union olsr_ip_addr *, union hna_netmask *);
108
109 static int
110 ipc_send(char *, int);
111
112 static double 
113 calc_etx(double, double);
114
115 static void inline
116 ipc_print_neigh_link(struct neighbor_entry *);
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()
127 {
128   /* Initial IPC value */
129   ipc_open = 0;
130   ipc_socket_up = 0;
131
132   /* Register the "ProcessChanges" function */
133   register_pcf(&pcf_event);
134
135   return 1;
136 }
137
138
139 /**
140  * destructor - called at unload
141  */
142 void
143 olsr_plugin_exit()
144 {
145   if(ipc_open)
146     close(ipc_socket);
147 }
148
149
150 static void inline
151 ipc_print_neigh_link(struct neighbor_entry *neighbor)
152 {
153   char buf[256];
154   int len;
155   char* adr;
156   double etx=0.0;
157   char* style = "solid";
158   struct link_entry* link;
159   adr = olsr_ip_to_string(&main_addr);
160   len = sprintf( buf, "\"%s\" -> ", adr );
161   ipc_send(buf, len);
162   
163   adr = olsr_ip_to_string(&neighbor->neighbor_main_addr);
164   
165   if (neighbor->status == 0) { // non SYM
166         style = "dashed";
167   }
168   else {   
169       link = get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
170       if (link) {
171         etx = calc_etx( link->loss_link_quality, link->neigh_link_quality);
172       }
173   }
174     
175   len = sprintf( buf, "\"%s\"[label=\"%.2f\", style=%s];\n", adr, etx, style );
176   ipc_send(buf, len);
177   
178    if (neighbor->is_mpr) {
179         len = sprintf( buf, "\"%s\"[shape=box];\n", adr );
180         ipc_send(buf, len);
181   }
182 }
183
184
185 static int
186 plugin_ipc_init()
187 {
188   struct sockaddr_in sin;
189   olsr_u32_t yes = 1;
190
191   /* Init ipc socket */
192   if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
193     {
194       olsr_printf(1, "(DOT DRAW)IPC socket %s\n", strerror(errno));
195       return 0;
196     }
197   else
198     {
199       if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
200       {
201         perror("SO_REUSEADDR failed");
202         return 0;
203       }
204
205 #ifdef __FreeBSD__
206       if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) 
207       {
208         perror("SO_REUSEADDR failed");
209         return 0;
210       }
211 #endif
212
213       /* Bind the socket */
214       
215       /* complete the socket structure */
216       memset(&sin, 0, sizeof(sin));
217       sin.sin_family = AF_INET;
218       sin.sin_addr.s_addr = INADDR_ANY;
219       sin.sin_port = htons(ipc_port);
220       
221       /* bind the socket to the port number */
222       if (bind(ipc_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
223         {
224           olsr_printf(1, "(DOT DRAW)IPC bind %s\n", strerror(errno));
225           return 0;
226         }
227       
228       /* show that we are willing to listen */
229       if (listen(ipc_socket, 1) == -1) 
230         {
231           olsr_printf(1, "(DOT DRAW)IPC listen %s\n", strerror(errno));
232           return 0;
233         }
234
235
236       /* Register with olsrd */
237       add_olsr_socket(ipc_socket, &ipc_action);
238       ipc_socket_up = 1;
239     }
240
241   return 1;
242 }
243
244
245 static void
246 ipc_action(int fd)
247 {
248   struct sockaddr_in pin;
249   socklen_t addrlen;
250   char *addr;  
251
252   addrlen = sizeof(struct sockaddr_in);
253
254   if (ipc_open)
255     {
256       while(close(ipc_connection) == -1) 
257         {
258           olsr_printf(1, "(DOT DRAW) Error on closing previously active TCP connection on fd %d: %s\n", ipc_connection, strerror(errno));
259           if (errno != EINTR)
260             {
261               break;
262             }
263         }
264       ipc_open = 0;
265     }
266   
267   if ((ipc_connection = accept(ipc_socket, (struct sockaddr *)  &pin, &addrlen)) == -1)
268     {
269       olsr_printf(1, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
270       exit(1);
271     }
272   else
273     {
274       addr = inet_ntoa(pin.sin_addr);
275       if(ntohl(pin.sin_addr.s_addr) != ntohl(ipc_accept_ip.s_addr))
276         {
277           olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
278           close(ipc_connection);
279           return;
280         }
281       else
282         {
283           ipc_open = 1;
284           olsr_printf(1, "(DOT DRAW)IPC: Connection from %s\n",addr);
285           pcf_event(1, 1, 1);
286         }
287     }
288 }
289
290
291 /**
292  *Scheduled event
293  */
294 static int
295 pcf_event(int changes_neighborhood,
296           int changes_topology,
297           int changes_hna)
298 {
299   int res;
300   olsr_u8_t index;
301   struct neighbor_entry *neighbor_table_tmp;
302   struct tc_entry *entry;
303   struct topo_dst *dst_entry;
304   struct hna_entry *tmp_hna;
305   struct hna_net *tmp_net;
306
307   res = 0;
308
309   if(changes_neighborhood || changes_topology || changes_hna)
310     {
311       /* Print tables to IPC socket */
312
313       ipc_send("digraph topology\n{\n", strlen("digraph topology\n{\n"));
314
315       /* Neighbors */
316       for(index=0;index<HASHSIZE;index++)
317         {
318           
319           for(neighbor_table_tmp = neighbortable[index].next;
320               neighbor_table_tmp != &neighbortable[index];
321               neighbor_table_tmp = neighbor_table_tmp->next)
322             {
323               ipc_print_neigh_link( neighbor_table_tmp );
324             }
325         }
326
327       /* Topology */  
328       for(index=0;index<HASHSIZE;index++)
329         {
330           /* For all TC entries */
331           entry = tc_table[index].next;
332           while(entry != &tc_table[index])
333             {
334               /* For all destination entries of that TC entry */
335               dst_entry = entry->destinations.next;
336               while(dst_entry != &entry->destinations)
337                 {
338                   ipc_print_tc_link(entry, dst_entry);
339                   dst_entry = dst_entry->next;
340                 }
341               entry = entry->next;
342             }
343         }
344
345       /* HNA entries */
346       for(index=0;index<HASHSIZE;index++)
347         {
348           tmp_hna = hna_set[index].next;
349           /* Check all entrys */
350           while(tmp_hna != &hna_set[index])
351             {
352               /* Check all networks */
353               tmp_net = tmp_hna->networks.next;
354               
355               while(tmp_net != &tmp_hna->networks)
356                 {
357                   ipc_print_net(&tmp_hna->A_gateway_addr, 
358                                 &tmp_net->A_network_addr, 
359                                 &tmp_net->A_netmask);
360                   tmp_net = tmp_net->next;
361                 }
362               
363               tmp_hna = tmp_hna->next;
364             }
365         }
366
367
368       ipc_send("}\n\n", strlen("}\n\n"));
369
370       res = 1;
371     }
372
373
374   if(!ipc_socket_up)
375     plugin_ipc_init();
376
377   return res;
378 }
379
380
381 #define MIN_LINK_QUALITY 0.01
382 static double 
383 calc_etx(double loss, double neigh_loss) 
384 {
385   if (loss < MIN_LINK_QUALITY || neigh_loss < MIN_LINK_QUALITY)
386     return 0.0;
387   else
388     return 1.0 / (loss * neigh_loss);
389 }
390
391
392 static void inline
393 ipc_print_tc_link(struct tc_entry *entry, struct topo_dst *dst_entry)
394 {
395   char buf[256];
396   int len;
397   char* adr;
398   double etx = calc_etx( dst_entry->link_quality, dst_entry->inverse_link_quality );
399
400   adr = olsr_ip_to_string(&entry->T_last_addr);
401   len = sprintf( buf, "\"%s\" -> ", adr );
402   ipc_send(buf, len);
403   
404   adr = olsr_ip_to_string(&dst_entry->T_dest_addr);
405   len = sprintf( buf, "\"%s\"[label=\"%.2f\"];\n", adr, etx );
406   ipc_send(buf, len);
407 }
408
409
410 static void inline
411 ipc_print_net(union olsr_ip_addr *gw, union olsr_ip_addr *net, union hna_netmask *mask)
412 {
413   char *adr;
414
415   adr = olsr_ip_to_string(gw);
416   ipc_send("\"", 1);
417   ipc_send(adr, strlen(adr));
418   ipc_send("\" -> \"", strlen("\" -> \""));
419   adr = olsr_ip_to_string(net);
420   ipc_send(adr, strlen(adr));
421   ipc_send("/", 1);
422   adr = olsr_netmask_to_string(mask);
423   ipc_send(adr, strlen(adr));
424   ipc_send("\"[label=\"HNA\"];\n", strlen("\"[label=\"HNA\"];\n"));
425   ipc_send("\"", 1);
426   adr = olsr_ip_to_string(net);
427   ipc_send(adr, strlen(adr));
428   ipc_send("/", 1);
429   adr = olsr_netmask_to_string(mask);
430   ipc_send(adr, strlen(adr));
431   ipc_send("\"", 1);
432   ipc_send("[shape=diamond];\n", strlen("[shape=diamond];\n"));
433 }
434
435
436 static int
437 ipc_send(char *data, int size)
438 {
439   if(!ipc_open)
440     return 0;
441
442 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
443   if (send(ipc_connection, data, size, 0) < 0) 
444 #else
445   if (send(ipc_connection, data, size, MSG_NOSIGNAL) < 0) 
446 #endif
447     {
448       olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
449       close(ipc_connection);
450       ipc_open = 0;
451       return -1;
452     }
453
454   return 1;
455 }
456
457
458 static char netmask[5];
459
460 static char*
461 olsr_netmask_to_string(union hna_netmask *mask)
462 {
463   char *ret;
464   struct in_addr in;
465
466   if(olsr_cnf->ip_version == AF_INET)
467     {
468       in.s_addr = mask->v4;
469       ret = inet_ntoa(in);
470       return ret;
471
472     }
473   else
474     {
475       /* IPv6 */
476       sprintf(netmask, "%d", mask->v6);
477       return netmask;
478     }
479
480   return ret;
481 }