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