4e4ba42e51986765653df6674a55638764cef001
[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.23 2007/04/20 14:06:18 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
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 static int ipc_socket;
81 static int ipc_open;
82 static int ipc_connection;
83 static int ipc_socket_up;
84
85
86
87 /* IPC initialization function */
88 static int
89 plugin_ipc_init(void);
90
91 static char*
92 olsr_netmask_to_string(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(struct neighbor_entry *neighbor);
103
104 static void
105 ipc_print_tc_link(struct tc_entry *entry, struct topo_dst *dst_entry);
106
107 static void
108 ipc_print_net(union olsr_ip_addr *, union olsr_ip_addr *, union hna_netmask *);
109
110 static int
111 ipc_send(const char *, int);
112
113 static int
114 ipc_send_str(const char *);
115
116 static double 
117 calc_etx(double, double);
118
119
120 /**
121  *Do initialization here
122  *
123  *This function is called by the my_init
124  *function in uolsrd_plugin.c
125  */
126 int
127 olsrd_plugin_init(void)
128 {
129   /* Initial IPC value */
130   ipc_open = 0;
131   ipc_socket_up = 0;
132   ipc_socket = -1;
133   ipc_connection = -1;
134
135   /* Register the "ProcessChanges" function */
136   register_pcf(&pcf_event);
137
138   plugin_ipc_init();
139
140   return 1;
141 }
142
143
144 /**
145  * destructor - called at unload
146  */
147 void
148 olsr_plugin_exit(void)
149 {
150   if(ipc_open)
151     close(ipc_socket);
152 }
153
154
155 static void
156 ipc_print_neigh_link(struct neighbor_entry *neighbor)
157 {
158   char buf[256];
159   const char* adr;
160   double etx = 0.0;
161   char* style = "solid";
162   struct link_entry* link;
163   adr = olsr_ip_to_string(&olsr_cnf->main_addr);
164   sprintf( buf, "\"%s\" -> ", adr );
165   ipc_send_str(buf);
166   
167   adr = olsr_ip_to_string(&neighbor->neighbor_main_addr);
168   
169   if (neighbor->status == 0) { // non SYM
170         style = "dashed";
171   }
172   else {   
173       link = get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
174       if (link) {
175         etx = calc_etx( link->loss_link_quality, link->neigh_link_quality);
176       }
177   }
178     
179   sprintf( buf, "\"%s\"[label=\"%.2f\", style=%s];\n", adr, etx, style );
180   ipc_send_str(buf);
181   
182    if (neighbor->is_mpr) {
183         sprintf( buf, "\"%s\"[shape=box];\n", adr );
184         ipc_send_str(buf);
185   }
186 }
187
188
189 static int
190 plugin_ipc_init(void)
191 {
192   struct sockaddr_in sin;
193   olsr_u32_t yes = 1;
194
195   /* Init ipc socket */
196   if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
197     {
198       olsr_printf(1, "(DOT DRAW)IPC socket %s\n", strerror(errno));
199       return 0;
200     }
201   else
202     {
203       if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
204       {
205         perror("SO_REUSEADDR failed");
206         return 0;
207       }
208
209 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
210       if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) 
211       {
212         perror("SO_REUSEADDR failed");
213         return 0;
214       }
215 #endif
216
217       /* Bind the socket */
218       
219       /* complete the socket structure */
220       memset(&sin, 0, sizeof(sin));
221       sin.sin_family = AF_INET;
222       sin.sin_addr.s_addr = INADDR_ANY;
223       sin.sin_port = htons(ipc_port);
224       
225       /* bind the socket to the port number */
226       if (bind(ipc_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
227         {
228           olsr_printf(1, "(DOT DRAW)IPC bind %s\n", strerror(errno));
229           return 0;
230         }
231       
232       /* show that we are willing to listen */
233       if (listen(ipc_socket, 1) == -1) 
234         {
235           olsr_printf(1, "(DOT DRAW)IPC listen %s\n", strerror(errno));
236           return 0;
237         }
238
239
240       /* Register with olsrd */
241       printf("Adding socket with olsrd\n");
242       add_olsr_socket(ipc_socket, &ipc_action);
243       ipc_socket_up = 1;
244     }
245
246   return 1;
247 }
248
249
250 static void
251 ipc_action(int fd __attribute__((unused)))
252 {
253   struct sockaddr_in pin;
254   socklen_t addrlen = sizeof(struct sockaddr_in);
255
256   if (ipc_open)
257     {
258       int rc;
259       do {
260         rc = close(ipc_connection);
261       } while (rc == -1 && (errno == EINTR || errno == EAGAIN));
262       if (rc == -1) {
263         olsr_printf(1, "(DOT DRAW) Error on closing previously active TCP connection on fd %d: %s\n", ipc_connection, strerror(errno));
264       }
265       ipc_open = 0;
266     }
267   
268   if ((ipc_connection = accept(ipc_socket, (struct sockaddr *)  &pin, &addrlen)) == -1)
269     {
270       olsr_printf(1, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
271     }
272   else
273     {
274       char *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           ipc_connection = -1;
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_str("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_str("}\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
393 ipc_print_tc_link(struct tc_entry *entry, struct topo_dst *dst_entry)
394 {
395   char buf[256];
396   const char* adr;
397   double etx = calc_etx( dst_entry->link_quality, dst_entry->inverse_link_quality );
398
399   adr = olsr_ip_to_string(&entry->T_last_addr);
400   sprintf( buf, "\"%s\" -> ", adr );
401   ipc_send_str(buf);
402   
403   adr = olsr_ip_to_string(&dst_entry->T_dest_addr);
404   sprintf( buf, "\"%s\"[label=\"%.2f\"];\n", adr, etx );
405   ipc_send_str(buf);
406 }
407
408
409 static void
410 ipc_print_net(union olsr_ip_addr *gw, union olsr_ip_addr *net, union hna_netmask *mask)
411 {
412   const char *adr;
413
414   adr = olsr_ip_to_string(gw);
415   ipc_send_str("\"");
416   ipc_send_str(adr);
417   ipc_send_str("\" -> \"");
418   adr = olsr_ip_to_string(net);
419   ipc_send_str(adr);
420   ipc_send_str("/");
421   adr = olsr_netmask_to_string(mask);
422   ipc_send_str(adr);
423   ipc_send_str("\"[label=\"HNA\"];\n");
424   ipc_send_str("\"");
425   adr = olsr_ip_to_string(net);
426   ipc_send_str(adr);
427   ipc_send_str("/");
428   adr = olsr_netmask_to_string(mask);
429   ipc_send_str(adr);
430   ipc_send_str("\"");
431   ipc_send_str("[shape=diamond];\n");
432 }
433
434 static int
435 ipc_send_str(const char *data)
436 {
437   if(!ipc_open)
438     return 0;
439   return ipc_send(data, strlen(data));
440 }
441
442
443 static int
444 ipc_send(const char *data, int size)
445 {
446   if(!ipc_open)
447     return 0;
448
449 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __MacOSX__
450 #define FLAGS 0
451 #else
452 #define FLAGS MSG_NOSIGNAL
453 #endif
454   if (send(ipc_connection, data, size, FLAGS) == -1)
455     {
456       olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
457       close(ipc_connection);
458       ipc_open = 0;
459       return -1;
460     }
461
462   return 1;
463 }
464
465 static char*
466 olsr_netmask_to_string(union hna_netmask *mask)
467 {
468   char *ret;
469   struct in_addr in;
470
471   if(olsr_cnf->ip_version == AF_INET)
472     {
473       in.s_addr = mask->v4;
474       ret = inet_ntoa(in);
475     }
476   else
477     {
478       /* IPv6 */
479       static char netmask[5];
480       sprintf(netmask, "%d", mask->v6);
481       ret = netmask;
482     }
483
484   return ret;
485 }