Updated license
[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.8 2004/12/03 20:52:27 kattemat 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 /**
63  *Do initialization here
64  *
65  *This function is called by the my_init
66  *function in uolsrd_plugin.c
67  */
68 int
69 olsr_plugin_init()
70 {
71
72   /* Initial IPC value */
73   ipc_open = 0;
74   ipc_socket_up = 0;
75
76   /* Register the "ProcessChanges" function */
77   register_pcf(&pcf_event);
78
79   return 1;
80 }
81
82 int
83 plugin_ipc_init()
84 {
85   struct sockaddr_in sin;
86   olsr_u32_t yes = 1;
87
88   /* Init ipc socket */
89   if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
90     {
91       olsr_printf(1, "(DOT DRAW)IPC socket %s\n", strerror(errno));
92       return 0;
93     }
94   else
95     {
96       if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
97       {
98         perror("SO_REUSEADDR failed");
99         return 0;
100       }
101
102       /* Bind the socket */
103       
104       /* complete the socket structure */
105       memset(&sin, 0, sizeof(sin));
106       sin.sin_family = AF_INET;
107       sin.sin_addr.s_addr = INADDR_ANY;
108       sin.sin_port = htons(ipc_port);
109       
110       /* bind the socket to the port number */
111       if (bind(ipc_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
112         {
113           olsr_printf(1, "(DOT DRAW)IPC bind %s\n", strerror(errno));
114           return 0;
115         }
116       
117       /* show that we are willing to listen */
118       if (listen(ipc_socket, 1) == -1) 
119         {
120           olsr_printf(1, "(DOT DRAW)IPC listen %s\n", strerror(errno));
121           return 0;
122         }
123
124
125       /* Register with olsrd */
126       add_olsr_socket(ipc_socket, &ipc_action);
127       ipc_socket_up = 1;
128     }
129
130   return 1;
131 }
132
133 void
134 ipc_action(int fd)
135 {
136   struct sockaddr_in pin;
137   socklen_t addrlen;
138   char *addr;  
139
140   addrlen = sizeof(struct sockaddr_in);
141
142   if ((ipc_connection = accept(ipc_socket, (struct sockaddr *)  &pin, &addrlen)) == -1)
143     {
144       olsr_printf(1, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
145       exit(1);
146     }
147   else
148     {
149       addr = inet_ntoa(pin.sin_addr);
150       if(ntohl(pin.sin_addr.s_addr) != ntohl(ipc_accept_ip.s_addr))
151         {
152           olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
153           close(ipc_connection);
154           return;
155         }
156       else
157         {
158           ipc_open = 1;
159           olsr_printf(1, "(DOT DRAW)IPC: Connection from %s\n",addr);
160           pcf_event(1, 1, 1);
161         }
162     }
163
164 }
165
166 /*
167  * destructor - called at unload
168  */
169 void
170 olsr_plugin_exit()
171 {
172   if(ipc_open)
173     close(ipc_socket);
174 }
175
176
177
178 /* Mulitpurpose funtion */
179 int
180 plugin_io(int cmd, void *data, size_t size)
181 {
182
183   switch(cmd)
184     {
185     default:
186       return 0;
187     }
188   
189   return 1;
190 }
191
192
193
194
195 /**
196  *Scheduled event
197  */
198 int
199 pcf_event(int changes_neighborhood,
200           int changes_topology,
201           int changes_hna)
202 {
203   int res;
204   olsr_u8_t index;
205   struct neighbor_entry *neighbor_table_tmp;
206   struct neighbor_2_list_entry *list_2;
207   struct tc_entry *entry;
208   struct topo_dst *dst_entry;
209   struct hna_entry *tmp_hna;
210   struct hna_net *tmp_net;
211
212   res = 0;
213
214   if(changes_neighborhood || changes_topology || changes_hna)
215     {
216       /* Print tables to IPC socket */
217
218       ipc_send("digraph topology\n{\n", strlen("digraph topology\n{\n"));
219
220       /* Neighbors */
221       for(index=0;index<HASHSIZE;index++)
222         {
223           
224           for(neighbor_table_tmp = neighbortable[index].next;
225               neighbor_table_tmp != &neighbortable[index];
226               neighbor_table_tmp = neighbor_table_tmp->next)
227             {
228               if(neighbor_table_tmp->is_mpr)
229                 {
230                   ipc_print_mpr_link(main_addr, &neighbor_table_tmp->neighbor_main_addr);                 
231                   ipc_print_mpr_link(&neighbor_table_tmp->neighbor_main_addr, main_addr);
232                 }
233               else
234                 {
235                   ipc_print_neigh_link(main_addr, &neighbor_table_tmp->neighbor_main_addr);               
236                   ipc_print_neigh_link(&neighbor_table_tmp->neighbor_main_addr, main_addr);
237                 }
238
239               for(list_2 = neighbor_table_tmp->neighbor_2_list.next;
240                   list_2 != &neighbor_table_tmp->neighbor_2_list;
241                   list_2 = list_2->next)
242                 {
243                   ipc_print_2h_link(&neighbor_table_tmp->neighbor_main_addr, 
244                                     &list_2->neighbor_2->neighbor_2_addr);
245                 }
246               
247             }
248         }
249
250       /* Topology */  
251       for(index=0;index<HASHSIZE;index++)
252         {
253           /* For all TC entries */
254           entry = tc_table[index].next;
255           while(entry != &tc_table[index])
256             {
257               /* For all destination entries of that TC entry */
258               dst_entry = entry->destinations.next;
259               while(dst_entry != &entry->destinations)
260                 {
261                   ipc_print_tc_link(&entry->T_last_addr, &dst_entry->T_dest_addr);
262                   dst_entry = dst_entry->next;
263                 }
264               entry = entry->next;
265             }
266         }
267
268       /* HNA entries */
269       for(index=0;index<HASHSIZE;index++)
270         {
271           tmp_hna = hna_set[index].next;
272           /* Check all entrys */
273           while(tmp_hna != &hna_set[index])
274             {
275               /* Check all networks */
276               tmp_net = tmp_hna->networks.next;
277               
278               while(tmp_net != &tmp_hna->networks)
279                 {
280                   ipc_print_net(&tmp_hna->A_gateway_addr, 
281                                 &tmp_net->A_network_addr, 
282                                 &tmp_net->A_netmask);
283                   tmp_net = tmp_net->next;
284                 }
285               
286               tmp_hna = tmp_hna->next;
287             }
288         }
289
290
291       ipc_send("}\n\n", strlen("}\n\n"));
292
293       res = 1;
294     }
295
296
297   if(!ipc_socket_up)
298     plugin_ipc_init();
299
300   return res;
301 }
302
303
304
305
306 static void inline
307 ipc_print_neigh_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
308 {
309   char *adr;
310
311   adr = olsr_ip_to_string(from);
312   ipc_send("\"", 1);
313   ipc_send(adr, strlen(adr));
314   ipc_send("\" -> \"", strlen("\" -> \""));
315   adr = olsr_ip_to_string(to);
316   ipc_send(adr, strlen(adr));
317   ipc_send("\"[label=\"neigh\", style=dashed];\n", strlen("\"[label=\"neigh\", style=dashed];\n"));
318
319 }
320
321 static void inline
322 ipc_print_2h_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
323 {
324   char *adr;
325
326   adr = olsr_ip_to_string(from);
327   ipc_send("\"", 1);
328   ipc_send(adr, strlen(adr));
329   ipc_send("\" -> \"", strlen("\" -> \""));
330   adr = olsr_ip_to_string(to);
331   ipc_send(adr, strlen(adr));
332   ipc_send("\"[label=\"2 hop\"];\n", strlen("\"[label=\"2 hop\"];\n"));
333
334 }
335
336 static void inline
337 ipc_print_mpr_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
338 {
339   char *adr;
340
341   adr = olsr_ip_to_string(from);
342   ipc_send("\"", 1);
343   ipc_send(adr, strlen(adr));
344   ipc_send("\" -> \"", strlen("\" -> \""));
345   adr = olsr_ip_to_string(to);
346   ipc_send(adr, strlen(adr));
347   ipc_send("\"[label=\"MPR\", style=dashed];\n", strlen("\"[label=\"MPR\", style=dashed]];\n"));
348
349 }
350
351 static void inline
352 ipc_print_tc_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
353 {
354   char *adr;
355
356   adr = olsr_ip_to_string(from);
357   ipc_send("\"", 1);
358   ipc_send(adr, strlen(adr));
359   ipc_send("\" -> \"", strlen("\" -> \""));
360   adr = olsr_ip_to_string(to);
361   ipc_send(adr, strlen(adr));
362   ipc_send("\"[label=\"TC\"];\n", strlen("\"[label=\"TC\"];\n"));
363
364 }
365
366 static void inline
367 ipc_print_net(union olsr_ip_addr *gw, union olsr_ip_addr *net, union hna_netmask *mask)
368 {
369   char *adr;
370
371   adr = olsr_ip_to_string(gw);
372   ipc_send("\"", 1);
373   ipc_send(adr, strlen(adr));
374   ipc_send("\" -> \"", strlen("\" -> \""));
375   adr = olsr_ip_to_string(net);
376   ipc_send(adr, strlen(adr));
377   ipc_send("/", 1);
378   adr = olsr_netmask_to_string(mask);
379   ipc_send(adr, strlen(adr));
380   ipc_send("\"[label=\"HNA\"];\n", strlen("\"[label=\"HNA\"];\n"));
381   ipc_send("\"", 1);
382   adr = olsr_ip_to_string(net);
383   ipc_send(adr, strlen(adr));
384   ipc_send("/", 1);
385   adr = olsr_netmask_to_string(mask);
386   ipc_send(adr, strlen(adr));
387   ipc_send("\"", 1);
388   ipc_send("[shape=diamond];\n", strlen("[shape=diamond];\n"));
389 }
390
391
392
393 int
394 ipc_send(char *data, int size)
395 {
396   if(!ipc_open)
397     return 0;
398
399   if (send(ipc_connection, data, size, MSG_NOSIGNAL) < 0) 
400     {
401       olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
402       close(ipc_connection);
403       ipc_open = 0;
404       return -1;
405     }
406
407   return 1;
408 }
409
410
411
412
413
414 /**
415  *Converts a olsr_ip_addr to a string
416  *Goes for both IPv4 and IPv6
417  *
418  *NON REENTRANT! If you need to use this
419  *function twice in e.g. the same printf
420  *it will not work.
421  *You must use it in different calls e.g.
422  *two different printfs
423  *
424  *@param the IP to convert
425  *@return a pointer to a static string buffer
426  *representing the address in "dots and numbers"
427  *
428  */
429 char *
430 olsr_ip_to_string(union olsr_ip_addr *addr)
431 {
432
433   char *ret;
434   struct in_addr in;
435   
436   if(ipversion == AF_INET)
437     {
438       in.s_addr=addr->v4;
439       ret = inet_ntoa(in);
440     }
441   else
442     {
443       /* IPv6 */
444       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
445     }
446
447   return ret;
448 }
449
450
451
452
453 /**
454  *This function is just as bad as the previous one :-(
455  */
456 char *
457 olsr_netmask_to_string(union hna_netmask *mask)
458 {
459   char *ret;
460   struct in_addr in;
461   
462   if(ipversion == AF_INET)
463     {
464       in.s_addr = mask->v4;
465       ret = inet_ntoa(in);
466       return ret;
467
468     }
469   else
470     {
471       /* IPv6 */
472       sprintf(netmask, "%d", mask->v6);
473       return netmask;
474     }
475
476   return ret;
477 }
478
479