NetBSD compile fixes
[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.12 2005/05/25 16:00:42 br1 Exp $
41  */
42
43 /*
44  * Dynamic linked library for the olsr.org olsr daemon
45  */
46
47 #include "olsrd_dot_draw.h"
48 #include <stdio.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <errno.h>
53 #ifdef WIN32
54 #define close(x) closesocket(x)
55 #endif
56
57 int ipc_socket;
58 int ipc_open;
59 int ipc_connection;
60 int ipc_socket_up;
61
62 static double 
63 calc_etx(double, double);
64
65 static void inline
66 ipc_print_neigh_link(struct neighbor_entry *);
67
68
69
70
71 static void inline
72 ipc_print_neigh_link(struct neighbor_entry *neighbor)
73 {
74   char buf[256];
75   int len;
76   char* adr;
77   double etx=0.0;
78   char* style = "solid";
79   struct link_entry* link;
80   adr = olsr_ip_to_string(main_addr);
81   len = sprintf( buf, "\"%s\" -> ", adr );
82   ipc_send(buf, len);
83   
84   adr = olsr_ip_to_string(&neighbor->neighbor_main_addr);
85   
86   if (neighbor->status == 0) { // non SYM
87         style = "dashed";
88   }
89   else {
90     /* find best link to neighbor for the ETX */
91     //? why cant i just get it one time at fetch_olsrd_data??? (br1)
92     if(olsr_plugin_io(GETD__LINK_SET, &link, sizeof(link)) && link)
93     {
94       link_set = link; // for olsr_neighbor_best_link    
95       link = olsr_neighbor_best_link(&neighbor->neighbor_main_addr);
96       if (link) {
97         etx = calc_etx( link->loss_link_quality, link->neigh_link_quality);
98       }
99     }
100   }
101     
102   len = sprintf( buf, "\"%s\"[label=\"%.2f\", style=%s];\n", adr, etx, style );
103   ipc_send(buf, len);
104   
105    if (neighbor->is_mpr) {
106         len = sprintf( buf, "\"%s\"[shape=box];\n", adr );
107         ipc_send(buf, len);
108   }
109 }
110
111 /**
112  *Do initialization here
113  *
114  *This function is called by the my_init
115  *function in uolsrd_plugin.c
116  */
117 int
118 olsr_plugin_init()
119 {
120
121   /* Initial IPC value */
122   ipc_open = 0;
123   ipc_socket_up = 0;
124
125   /* Register the "ProcessChanges" function */
126   register_pcf(&pcf_event);
127
128   return 1;
129 }
130
131 int
132 plugin_ipc_init()
133 {
134   struct sockaddr_in sin;
135   olsr_u32_t yes = 1;
136
137   /* Init ipc socket */
138   if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
139     {
140       olsr_printf(1, "(DOT DRAW)IPC socket %s\n", strerror(errno));
141       return 0;
142     }
143   else
144     {
145       if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
146       {
147         perror("SO_REUSEADDR failed");
148         return 0;
149       }
150
151 #ifdef __FreeBSD__
152       if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) 
153       {
154         perror("SO_REUSEADDR failed");
155         return 0;
156       }
157 #endif
158
159       /* Bind the socket */
160       
161       /* complete the socket structure */
162       memset(&sin, 0, sizeof(sin));
163       sin.sin_family = AF_INET;
164       sin.sin_addr.s_addr = INADDR_ANY;
165       sin.sin_port = htons(ipc_port);
166       
167       /* bind the socket to the port number */
168       if (bind(ipc_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
169         {
170           olsr_printf(1, "(DOT DRAW)IPC bind %s\n", strerror(errno));
171           return 0;
172         }
173       
174       /* show that we are willing to listen */
175       if (listen(ipc_socket, 1) == -1) 
176         {
177           olsr_printf(1, "(DOT DRAW)IPC listen %s\n", strerror(errno));
178           return 0;
179         }
180
181
182       /* Register with olsrd */
183       add_olsr_socket(ipc_socket, &ipc_action);
184       ipc_socket_up = 1;
185     }
186
187   return 1;
188 }
189
190 void
191 ipc_action(int fd)
192 {
193   struct sockaddr_in pin;
194   socklen_t addrlen;
195   char *addr;  
196
197   addrlen = sizeof(struct sockaddr_in);
198
199   if ((ipc_connection = accept(ipc_socket, (struct sockaddr *)  &pin, &addrlen)) == -1)
200     {
201       olsr_printf(1, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
202       exit(1);
203     }
204   else
205     {
206       addr = inet_ntoa(pin.sin_addr);
207       if(ntohl(pin.sin_addr.s_addr) != ntohl(ipc_accept_ip.s_addr))
208         {
209           olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
210           close(ipc_connection);
211           return;
212         }
213       else
214         {
215           ipc_open = 1;
216           olsr_printf(1, "(DOT DRAW)IPC: Connection from %s\n",addr);
217           pcf_event(1, 1, 1);
218         }
219     }
220
221 }
222
223 /*
224  * destructor - called at unload
225  */
226 void
227 olsr_plugin_exit()
228 {
229   if(ipc_open)
230     close(ipc_socket);
231 }
232
233
234
235 /* Mulitpurpose funtion */
236 int
237 plugin_io(int cmd, void *data, size_t size)
238 {
239
240   switch(cmd)
241     {
242     default:
243       return 0;
244     }
245   
246   return 1;
247 }
248
249
250
251
252 /**
253  *Scheduled event
254  */
255 int
256 pcf_event(int changes_neighborhood,
257           int changes_topology,
258           int changes_hna)
259 {
260   int res;
261   olsr_u8_t index;
262   struct neighbor_entry *neighbor_table_tmp;
263   struct tc_entry *entry;
264   struct topo_dst *dst_entry;
265   struct hna_entry *tmp_hna;
266   struct hna_net *tmp_net;
267
268   res = 0;
269
270   if(changes_neighborhood || changes_topology || changes_hna)
271     {
272       /* Print tables to IPC socket */
273
274       ipc_send("digraph topology\n{\n", strlen("digraph topology\n{\n"));
275
276       /* Neighbors */
277       for(index=0;index<HASHSIZE;index++)
278         {
279           
280           for(neighbor_table_tmp = neighbortable[index].next;
281               neighbor_table_tmp != &neighbortable[index];
282               neighbor_table_tmp = neighbor_table_tmp->next)
283             {
284               ipc_print_neigh_link( neighbor_table_tmp );
285             }
286         }
287
288       /* Topology */  
289       for(index=0;index<HASHSIZE;index++)
290         {
291           /* For all TC entries */
292           entry = tc_table[index].next;
293           while(entry != &tc_table[index])
294             {
295               /* For all destination entries of that TC entry */
296               dst_entry = entry->destinations.next;
297               while(dst_entry != &entry->destinations)
298                 {
299                   ipc_print_tc_link(entry, dst_entry);
300                   dst_entry = dst_entry->next;
301                 }
302               entry = entry->next;
303             }
304         }
305
306       /* HNA entries */
307       for(index=0;index<HASHSIZE;index++)
308         {
309           tmp_hna = hna_set[index].next;
310           /* Check all entrys */
311           while(tmp_hna != &hna_set[index])
312             {
313               /* Check all networks */
314               tmp_net = tmp_hna->networks.next;
315               
316               while(tmp_net != &tmp_hna->networks)
317                 {
318                   ipc_print_net(&tmp_hna->A_gateway_addr, 
319                                 &tmp_net->A_network_addr, 
320                                 &tmp_net->A_netmask);
321                   tmp_net = tmp_net->next;
322                 }
323               
324               tmp_hna = tmp_hna->next;
325             }
326         }
327
328
329       ipc_send("}\n\n", strlen("}\n\n"));
330
331       res = 1;
332     }
333
334
335   if(!ipc_socket_up)
336     plugin_ipc_init();
337
338   return res;
339 }
340
341 #define MIN_LINK_QUALITY 0.01
342 static double 
343 calc_etx(double loss, double neigh_loss) 
344 {
345   if (loss < MIN_LINK_QUALITY || neigh_loss < MIN_LINK_QUALITY)
346     return 0.0;
347   else
348     return 1.0 / (loss * neigh_loss);
349 }
350
351
352 static void inline
353 ipc_print_tc_link(struct tc_entry *entry, struct topo_dst *dst_entry)
354 {
355   char buf[256];
356   int len;
357   char* adr;
358   double etx = calc_etx( dst_entry->link_quality, dst_entry->inverse_link_quality );
359
360   adr = olsr_ip_to_string(&entry->T_last_addr);
361   len = sprintf( buf, "\"%s\" -> ", adr );
362   ipc_send(buf, len);
363   
364   adr = olsr_ip_to_string(&dst_entry->T_dest_addr);
365   len = sprintf( buf, "\"%s\"[label=\"%.2f\"];\n", adr, etx );
366   ipc_send(buf, len);
367 }
368
369 static void inline
370 ipc_print_net(union olsr_ip_addr *gw, union olsr_ip_addr *net, union hna_netmask *mask)
371 {
372   char *adr;
373
374   adr = olsr_ip_to_string(gw);
375   ipc_send("\"", 1);
376   ipc_send(adr, strlen(adr));
377   ipc_send("\" -> \"", strlen("\" -> \""));
378   adr = olsr_ip_to_string(net);
379   ipc_send(adr, strlen(adr));
380   ipc_send("/", 1);
381   adr = olsr_netmask_to_string(mask);
382   ipc_send(adr, strlen(adr));
383   ipc_send("\"[label=\"HNA\"];\n", strlen("\"[label=\"HNA\"];\n"));
384   ipc_send("\"", 1);
385   adr = olsr_ip_to_string(net);
386   ipc_send(adr, strlen(adr));
387   ipc_send("/", 1);
388   adr = olsr_netmask_to_string(mask);
389   ipc_send(adr, strlen(adr));
390   ipc_send("\"", 1);
391   ipc_send("[shape=diamond];\n", strlen("[shape=diamond];\n"));
392 }
393
394
395
396 int
397 ipc_send(char *data, int size)
398 {
399   if(!ipc_open)
400     return 0;
401
402 #if defined __FreeBSD__ || defined __NetBSD__
403   if (send(ipc_connection, data, size, 0) < 0) 
404 #else
405   if (send(ipc_connection, data, size, MSG_NOSIGNAL) < 0) 
406 #endif
407     {
408       olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
409       close(ipc_connection);
410       ipc_open = 0;
411       return -1;
412     }
413
414   return 1;
415 }
416
417
418
419
420
421 /**
422  *Converts a olsr_ip_addr to a string
423  *Goes for both IPv4 and IPv6
424  *
425  *@param the IP to convert
426  *@return a pointer to a static string buffer
427  *representing the address in "dots and numbers"
428  *
429  */
430 char *
431 olsr_ip_to_string(union olsr_ip_addr *addr)
432 {
433   static int index = 0;
434   static char buff[4][100];
435   char *ret;
436   struct in_addr in;
437  
438   if(ipversion == AF_INET)
439     {
440       in.s_addr=addr->v4;
441       ret = inet_ntoa(in);
442     }
443   else
444     {
445       /* IPv6 */
446       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
447     }
448
449   strncpy(buff[index], ret, 100);
450
451   ret = buff[index];
452
453   index = (index + 1) & 3;
454
455   return ret;
456 }
457
458
459 /**
460  *This function is just as bad as the previous one :-(
461  */
462 char *
463 olsr_netmask_to_string(union hna_netmask *mask)
464 {
465   char *ret;
466   struct in_addr in;
467   
468   if(ipversion == AF_INET)
469     {
470       in.s_addr = mask->v4;
471       ret = inet_ntoa(in);
472       return ret;
473
474     }
475   else
476     {
477       /* IPv6 */
478       sprintf(netmask, "%d", mask->v6);
479       return netmask;
480     }
481
482   return ret;
483 }
484
485 #define COMP_IP(ip1, ip2) (!memcmp(ip1, ip2, ipsize))
486 struct link_entry *olsr_neighbor_best_link(union olsr_ip_addr *main)
487 {
488   struct link_entry *walker;
489   double best = 0.0;
490   double curr;
491   struct link_entry *res = NULL;
492
493   // loop through all links
494
495   for (walker = link_set; walker != NULL; walker = walker->next)
496   {
497     // check whether it's a link to the requested neighbor and
498     // whether the link's quality is better than what we have
499     if(COMP_IP(main, &walker->neighbor->neighbor_main_addr))
500     {
501       curr = walker->loss_link_quality * walker->neigh_link_quality;
502
503       if (curr >= best)
504       {
505         best = curr;
506         res = walker;
507       }
508     }
509   }
510
511   return res;
512 }
513