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