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