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