6a94d2300bcc5350ce23d25df3ce64228b1e90f2
[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.28 2007/11/02 20:58:07 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
302   res = 0;
303
304   if(changes_neighborhood || changes_topology || changes_hna)
305     {
306       /* Print tables to IPC socket */
307
308       ipc_send_str("digraph topology\n{\n");
309
310       /* Neighbors */
311       for(index=0;index<HASHSIZE;index++)
312         {
313           
314           for(neighbor_table_tmp = neighbortable[index].next;
315               neighbor_table_tmp != &neighbortable[index];
316               neighbor_table_tmp = neighbor_table_tmp->next)
317             {
318               ipc_print_neigh_link( neighbor_table_tmp );
319             }
320         }
321
322       /* Topology */  
323       OLSR_FOR_ALL_TC_ENTRIES(tc) {
324           OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
325               ipc_print_tc_link(tc, tc_edge);
326           } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
327       } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
328
329       /* HNA entries */
330       for(index=0;index<HASHSIZE;index++)
331         {
332           tmp_hna = hna_set[index].next;
333           /* Check all entrys */
334           while(tmp_hna != &hna_set[index])
335             {
336               /* Check all networks */
337               tmp_net = tmp_hna->networks.next;
338               
339               while(tmp_net != &tmp_hna->networks)
340                 {
341                   ipc_print_net(&tmp_hna->A_gateway_addr, 
342                                 &tmp_net->A_network_addr, 
343                                 &tmp_net->A_netmask);
344                   tmp_net = tmp_net->next;
345                 }
346               
347               tmp_hna = tmp_hna->next;
348             }
349         }
350
351
352       ipc_send_str("}\n\n");
353
354       res = 1;
355     }
356
357
358   if(!ipc_socket_up)
359     plugin_ipc_init();
360
361   return res;
362 }
363
364
365 static void
366 ipc_print_tc_link(struct tc_entry *entry, struct tc_edge_entry *dst_entry)
367 {
368   char buf[256];
369
370   sprintf( buf, "\"%s\" -> ", olsr_ip_to_string(&entry->addr));
371   ipc_send_str(buf);
372   
373   sprintf( buf, "\"%s\"[label=\"%.2f\"];\n", olsr_ip_to_string(&dst_entry->T_dest_addr), olsr_calc_tc_etx(dst_entry));
374   ipc_send_str(buf);
375 }
376
377
378 static void
379 ipc_print_net(union olsr_ip_addr *gw, union olsr_ip_addr *net, union hna_netmask *mask)
380 {
381   const char *adr;
382
383   adr = olsr_ip_to_string(gw);
384   ipc_send_str("\"");
385   ipc_send_str(adr);
386   ipc_send_str("\" -> \"");
387   adr = olsr_ip_to_string(net);
388   ipc_send_str(adr);
389   ipc_send_str("/");
390   adr = olsr_netmask_to_string(mask);
391   ipc_send_str(adr);
392   ipc_send_str("\"[label=\"HNA\"];\n");
393   ipc_send_str("\"");
394   adr = olsr_ip_to_string(net);
395   ipc_send_str(adr);
396   ipc_send_str("/");
397   adr = olsr_netmask_to_string(mask);
398   ipc_send_str(adr);
399   ipc_send_str("\"");
400   ipc_send_str("[shape=diamond];\n");
401 }
402
403 static int
404 ipc_send_str(const char *data)
405 {
406   if(!ipc_open)
407     return 0;
408   return ipc_send(data, strlen(data));
409 }
410
411
412 static int
413 ipc_send(const char *data, int size)
414 {
415   if(!ipc_open)
416     return 0;
417
418 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __MacOSX__
419 #define FLAGS 0
420 #else
421 #define FLAGS MSG_NOSIGNAL
422 #endif
423   if (send(ipc_connection, data, size, FLAGS) == -1)
424     {
425       olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
426       close(ipc_connection);
427       ipc_open = 0;
428       return -1;
429     }
430
431   return 1;
432 }
433
434 static char*
435 olsr_netmask_to_string(union hna_netmask *mask)
436 {
437   char *ret;
438   struct in_addr in;
439
440   if(olsr_cnf->ip_version == AF_INET)
441     {
442       in.s_addr = mask->v4;
443       ret = inet_ntoa(in);
444     }
445   else
446     {
447       /* IPv6 */
448       static char netmask[5];
449       sprintf(netmask, "%d", mask->v6);
450       ret = netmask;
451     }
452
453   return ret;
454 }