4a8b9ece278ee704308f7c89e8cffb6dc2e4bee1
[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.14 2005/05/29 12:47:40 br1 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_connection = accept(ipc_socket, (struct sockaddr *)  &pin, &addrlen)) == -1)
255     {
256       olsr_printf(1, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
257       exit(1);
258     }
259   else
260     {
261       addr = inet_ntoa(pin.sin_addr);
262       if(ntohl(pin.sin_addr.s_addr) != ntohl(ipc_accept_ip.s_addr))
263         {
264           olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
265           close(ipc_connection);
266           return;
267         }
268       else
269         {
270           ipc_open = 1;
271           olsr_printf(1, "(DOT DRAW)IPC: Connection from %s\n",addr);
272           pcf_event(1, 1, 1);
273         }
274     }
275 }
276
277
278 /**
279  *Scheduled event
280  */
281 static int
282 pcf_event(int changes_neighborhood,
283           int changes_topology,
284           int changes_hna)
285 {
286   int res;
287   olsr_u8_t index;
288   struct neighbor_entry *neighbor_table_tmp;
289   struct tc_entry *entry;
290   struct topo_dst *dst_entry;
291   struct hna_entry *tmp_hna;
292   struct hna_net *tmp_net;
293
294   res = 0;
295
296   if(changes_neighborhood || changes_topology || changes_hna)
297     {
298       /* Print tables to IPC socket */
299
300       ipc_send("digraph topology\n{\n", strlen("digraph topology\n{\n"));
301
302       /* Neighbors */
303       for(index=0;index<HASHSIZE;index++)
304         {
305           
306           for(neighbor_table_tmp = neighbortable[index].next;
307               neighbor_table_tmp != &neighbortable[index];
308               neighbor_table_tmp = neighbor_table_tmp->next)
309             {
310               ipc_print_neigh_link( neighbor_table_tmp );
311             }
312         }
313
314       /* Topology */  
315       for(index=0;index<HASHSIZE;index++)
316         {
317           /* For all TC entries */
318           entry = tc_table[index].next;
319           while(entry != &tc_table[index])
320             {
321               /* For all destination entries of that TC entry */
322               dst_entry = entry->destinations.next;
323               while(dst_entry != &entry->destinations)
324                 {
325                   ipc_print_tc_link(entry, dst_entry);
326                   dst_entry = dst_entry->next;
327                 }
328               entry = entry->next;
329             }
330         }
331
332       /* HNA entries */
333       for(index=0;index<HASHSIZE;index++)
334         {
335           tmp_hna = hna_set[index].next;
336           /* Check all entrys */
337           while(tmp_hna != &hna_set[index])
338             {
339               /* Check all networks */
340               tmp_net = tmp_hna->networks.next;
341               
342               while(tmp_net != &tmp_hna->networks)
343                 {
344                   ipc_print_net(&tmp_hna->A_gateway_addr, 
345                                 &tmp_net->A_network_addr, 
346                                 &tmp_net->A_netmask);
347                   tmp_net = tmp_net->next;
348                 }
349               
350               tmp_hna = tmp_hna->next;
351             }
352         }
353
354
355       ipc_send("}\n\n", strlen("}\n\n"));
356
357       res = 1;
358     }
359
360
361   if(!ipc_socket_up)
362     plugin_ipc_init();
363
364   return res;
365 }
366
367
368 #define MIN_LINK_QUALITY 0.01
369 static double 
370 calc_etx(double loss, double neigh_loss) 
371 {
372   if (loss < MIN_LINK_QUALITY || neigh_loss < MIN_LINK_QUALITY)
373     return 0.0;
374   else
375     return 1.0 / (loss * neigh_loss);
376 }
377
378
379 static void inline
380 ipc_print_tc_link(struct tc_entry *entry, struct topo_dst *dst_entry)
381 {
382   char buf[256];
383   int len;
384   char* adr;
385   double etx = calc_etx( dst_entry->link_quality, dst_entry->inverse_link_quality );
386
387   adr = olsr_ip_to_string(&entry->T_last_addr);
388   len = sprintf( buf, "\"%s\" -> ", adr );
389   ipc_send(buf, len);
390   
391   adr = olsr_ip_to_string(&dst_entry->T_dest_addr);
392   len = sprintf( buf, "\"%s\"[label=\"%.2f\"];\n", adr, etx );
393   ipc_send(buf, len);
394 }
395
396
397 static void inline
398 ipc_print_net(union olsr_ip_addr *gw, union olsr_ip_addr *net, union hna_netmask *mask)
399 {
400   char *adr;
401
402   adr = olsr_ip_to_string(gw);
403   ipc_send("\"", 1);
404   ipc_send(adr, strlen(adr));
405   ipc_send("\" -> \"", strlen("\" -> \""));
406   adr = olsr_ip_to_string(net);
407   ipc_send(adr, strlen(adr));
408   ipc_send("/", 1);
409   adr = olsr_netmask_to_string(mask);
410   ipc_send(adr, strlen(adr));
411   ipc_send("\"[label=\"HNA\"];\n", strlen("\"[label=\"HNA\"];\n"));
412   ipc_send("\"", 1);
413   adr = olsr_ip_to_string(net);
414   ipc_send(adr, strlen(adr));
415   ipc_send("/", 1);
416   adr = olsr_netmask_to_string(mask);
417   ipc_send(adr, strlen(adr));
418   ipc_send("\"", 1);
419   ipc_send("[shape=diamond];\n", strlen("[shape=diamond];\n"));
420 }
421
422
423 static int
424 ipc_send(char *data, int size)
425 {
426   if(!ipc_open)
427     return 0;
428
429 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
430   if (send(ipc_connection, data, size, 0) < 0) 
431 #else
432   if (send(ipc_connection, data, size, MSG_NOSIGNAL) < 0) 
433 #endif
434     {
435       olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
436       close(ipc_connection);
437       ipc_open = 0;
438       return -1;
439     }
440
441   return 1;
442 }
443
444
445 static char netmask[5];
446
447 static char*
448 olsr_netmask_to_string(union hna_netmask *mask)
449 {
450   char *ret;
451   struct in_addr in;
452
453   if(olsr_cnf->ip_version == AF_INET)
454     {
455       in.s_addr = mask->v4;
456       ret = inet_ntoa(in);
457       return ret;
458
459     }
460   else
461     {
462       /* IPv6 */
463       sprintf(netmask, "%d", mask->v6);
464       return netmask;
465     }
466
467   return ret;
468 }