Added Brunos patch
[olsrd.git] / lib / dot_draw / src / olsrd_dot_draw.c
1 /*
2  * OLSR plugin
3  * Copyright (C) 2004 Andreas T√łnnesen (andreto@olsr.org)
4  *
5  * This file is part of the olsrd dynamic gateway detection.
6  *
7  * This is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This plugin is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with olsrd-unik; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  * 
21  * 
22  * $Id: olsrd_dot_draw.c,v 1.7 2004/11/30 09:45:16 kattemat Exp $
23  *
24  */
25
26 /*
27  * Dynamic linked library for UniK OLSRd
28  */
29
30 #include "olsrd_dot_draw.h"
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #ifdef WIN32
37 #define close(x) closesocket(x)
38 #endif
39
40 int ipc_socket;
41 int ipc_open;
42 int ipc_connection;
43 int ipc_socket_up;
44
45 /**
46  *Do initialization here
47  *
48  *This function is called by the my_init
49  *function in uolsrd_plugin.c
50  */
51 int
52 olsr_plugin_init()
53 {
54
55   /* Initial IPC value */
56   ipc_open = 0;
57   ipc_socket_up = 0;
58
59   /* Register the "ProcessChanges" function */
60   register_pcf(&pcf_event);
61
62   return 1;
63 }
64
65 int
66 plugin_ipc_init()
67 {
68   struct sockaddr_in sin;
69   olsr_u32_t yes = 1;
70
71   /* Init ipc socket */
72   if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
73     {
74       olsr_printf(1, "(DOT DRAW)IPC socket %s\n", strerror(errno));
75       return 0;
76     }
77   else
78     {
79       if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
80       {
81         perror("SO_REUSEADDR failed");
82         return 0;
83       }
84
85       /* Bind the socket */
86       
87       /* complete the socket structure */
88       memset(&sin, 0, sizeof(sin));
89       sin.sin_family = AF_INET;
90       sin.sin_addr.s_addr = INADDR_ANY;
91       sin.sin_port = htons(ipc_port);
92       
93       /* bind the socket to the port number */
94       if (bind(ipc_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
95         {
96           olsr_printf(1, "(DOT DRAW)IPC bind %s\n", strerror(errno));
97           return 0;
98         }
99       
100       /* show that we are willing to listen */
101       if (listen(ipc_socket, 1) == -1) 
102         {
103           olsr_printf(1, "(DOT DRAW)IPC listen %s\n", strerror(errno));
104           return 0;
105         }
106
107
108       /* Register with olsrd */
109       add_olsr_socket(ipc_socket, &ipc_action);
110       ipc_socket_up = 1;
111     }
112
113   return 1;
114 }
115
116 void
117 ipc_action(int fd)
118 {
119   struct sockaddr_in pin;
120   socklen_t addrlen;
121   char *addr;  
122
123   addrlen = sizeof(struct sockaddr_in);
124
125   if ((ipc_connection = accept(ipc_socket, (struct sockaddr *)  &pin, &addrlen)) == -1)
126     {
127       olsr_printf(1, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
128       exit(1);
129     }
130   else
131     {
132       addr = inet_ntoa(pin.sin_addr);
133       if(ntohl(pin.sin_addr.s_addr) != ntohl(ipc_accept_ip.s_addr))
134         {
135           olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
136           close(ipc_connection);
137           return;
138         }
139       else
140         {
141           ipc_open = 1;
142           olsr_printf(1, "(DOT DRAW)IPC: Connection from %s\n",addr);
143           pcf_event(1, 1, 1);
144         }
145     }
146
147 }
148
149 /*
150  * destructor - called at unload
151  */
152 void
153 olsr_plugin_exit()
154 {
155   if(ipc_open)
156     close(ipc_socket);
157 }
158
159
160
161 /* Mulitpurpose funtion */
162 int
163 plugin_io(int cmd, void *data, size_t size)
164 {
165
166   switch(cmd)
167     {
168     default:
169       return 0;
170     }
171   
172   return 1;
173 }
174
175
176
177
178 /**
179  *Scheduled event
180  */
181 int
182 pcf_event(int changes_neighborhood,
183           int changes_topology,
184           int changes_hna)
185 {
186   int res;
187   olsr_u8_t index;
188   struct neighbor_entry *neighbor_table_tmp;
189   struct neighbor_2_list_entry *list_2;
190   struct tc_entry *entry;
191   struct topo_dst *dst_entry;
192   struct hna_entry *tmp_hna;
193   struct hna_net *tmp_net;
194
195   res = 0;
196
197   if(changes_neighborhood || changes_topology || changes_hna)
198     {
199       /* Print tables to IPC socket */
200
201       ipc_send("digraph topology\n{\n", strlen("digraph topology\n{\n"));
202
203       /* Neighbors */
204       for(index=0;index<HASHSIZE;index++)
205         {
206           
207           for(neighbor_table_tmp = neighbortable[index].next;
208               neighbor_table_tmp != &neighbortable[index];
209               neighbor_table_tmp = neighbor_table_tmp->next)
210             {
211               if(neighbor_table_tmp->is_mpr)
212                 {
213                   ipc_print_mpr_link(main_addr, &neighbor_table_tmp->neighbor_main_addr);                 
214                   ipc_print_mpr_link(&neighbor_table_tmp->neighbor_main_addr, main_addr);
215                 }
216               else
217                 {
218                   ipc_print_neigh_link(main_addr, &neighbor_table_tmp->neighbor_main_addr);               
219                   ipc_print_neigh_link(&neighbor_table_tmp->neighbor_main_addr, main_addr);
220                 }
221
222               for(list_2 = neighbor_table_tmp->neighbor_2_list.next;
223                   list_2 != &neighbor_table_tmp->neighbor_2_list;
224                   list_2 = list_2->next)
225                 {
226                   ipc_print_2h_link(&neighbor_table_tmp->neighbor_main_addr, 
227                                     &list_2->neighbor_2->neighbor_2_addr);
228                 }
229               
230             }
231         }
232
233       /* Topology */  
234       for(index=0;index<HASHSIZE;index++)
235         {
236           /* For all TC entries */
237           entry = tc_table[index].next;
238           while(entry != &tc_table[index])
239             {
240               /* For all destination entries of that TC entry */
241               dst_entry = entry->destinations.next;
242               while(dst_entry != &entry->destinations)
243                 {
244                   ipc_print_tc_link(&entry->T_last_addr, &dst_entry->T_dest_addr);
245                   dst_entry = dst_entry->next;
246                 }
247               entry = entry->next;
248             }
249         }
250
251       /* HNA entries */
252       for(index=0;index<HASHSIZE;index++)
253         {
254           tmp_hna = hna_set[index].next;
255           /* Check all entrys */
256           while(tmp_hna != &hna_set[index])
257             {
258               /* Check all networks */
259               tmp_net = tmp_hna->networks.next;
260               
261               while(tmp_net != &tmp_hna->networks)
262                 {
263                   ipc_print_net(&tmp_hna->A_gateway_addr, 
264                                 &tmp_net->A_network_addr, 
265                                 &tmp_net->A_netmask);
266                   tmp_net = tmp_net->next;
267                 }
268               
269               tmp_hna = tmp_hna->next;
270             }
271         }
272
273
274       ipc_send("}\n\n", strlen("}\n\n"));
275
276       res = 1;
277     }
278
279
280   if(!ipc_socket_up)
281     plugin_ipc_init();
282
283   return res;
284 }
285
286
287
288
289 static void inline
290 ipc_print_neigh_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
291 {
292   char *adr;
293
294   adr = olsr_ip_to_string(from);
295   ipc_send("\"", 1);
296   ipc_send(adr, strlen(adr));
297   ipc_send("\" -> \"", strlen("\" -> \""));
298   adr = olsr_ip_to_string(to);
299   ipc_send(adr, strlen(adr));
300   ipc_send("\"[label=\"neigh\", style=dashed];\n", strlen("\"[label=\"neigh\", style=dashed];\n"));
301
302 }
303
304 static void inline
305 ipc_print_2h_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
306 {
307   char *adr;
308
309   adr = olsr_ip_to_string(from);
310   ipc_send("\"", 1);
311   ipc_send(adr, strlen(adr));
312   ipc_send("\" -> \"", strlen("\" -> \""));
313   adr = olsr_ip_to_string(to);
314   ipc_send(adr, strlen(adr));
315   ipc_send("\"[label=\"2 hop\"];\n", strlen("\"[label=\"2 hop\"];\n"));
316
317 }
318
319 static void inline
320 ipc_print_mpr_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
321 {
322   char *adr;
323
324   adr = olsr_ip_to_string(from);
325   ipc_send("\"", 1);
326   ipc_send(adr, strlen(adr));
327   ipc_send("\" -> \"", strlen("\" -> \""));
328   adr = olsr_ip_to_string(to);
329   ipc_send(adr, strlen(adr));
330   ipc_send("\"[label=\"MPR\", style=dashed];\n", strlen("\"[label=\"MPR\", style=dashed]];\n"));
331
332 }
333
334 static void inline
335 ipc_print_tc_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
336 {
337   char *adr;
338
339   adr = olsr_ip_to_string(from);
340   ipc_send("\"", 1);
341   ipc_send(adr, strlen(adr));
342   ipc_send("\" -> \"", strlen("\" -> \""));
343   adr = olsr_ip_to_string(to);
344   ipc_send(adr, strlen(adr));
345   ipc_send("\"[label=\"TC\"];\n", strlen("\"[label=\"TC\"];\n"));
346
347 }
348
349 static void inline
350 ipc_print_net(union olsr_ip_addr *gw, union olsr_ip_addr *net, union hna_netmask *mask)
351 {
352   char *adr;
353
354   adr = olsr_ip_to_string(gw);
355   ipc_send("\"", 1);
356   ipc_send(adr, strlen(adr));
357   ipc_send("\" -> \"", strlen("\" -> \""));
358   adr = olsr_ip_to_string(net);
359   ipc_send(adr, strlen(adr));
360   ipc_send("/", 1);
361   adr = olsr_netmask_to_string(mask);
362   ipc_send(adr, strlen(adr));
363   ipc_send("\"[label=\"HNA\"];\n", strlen("\"[label=\"HNA\"];\n"));
364   ipc_send("\"", 1);
365   adr = olsr_ip_to_string(net);
366   ipc_send(adr, strlen(adr));
367   ipc_send("/", 1);
368   adr = olsr_netmask_to_string(mask);
369   ipc_send(adr, strlen(adr));
370   ipc_send("\"", 1);
371   ipc_send("[shape=diamond];\n", strlen("[shape=diamond];\n"));
372 }
373
374
375
376 int
377 ipc_send(char *data, int size)
378 {
379   if(!ipc_open)
380     return 0;
381
382   if (send(ipc_connection, data, size, MSG_NOSIGNAL) < 0) 
383     {
384       olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
385       close(ipc_connection);
386       ipc_open = 0;
387       return -1;
388     }
389
390   return 1;
391 }
392
393
394
395
396
397 /**
398  *Converts a olsr_ip_addr to a string
399  *Goes for both IPv4 and IPv6
400  *
401  *NON REENTRANT! If you need to use this
402  *function twice in e.g. the same printf
403  *it will not work.
404  *You must use it in different calls e.g.
405  *two different printfs
406  *
407  *@param the IP to convert
408  *@return a pointer to a static string buffer
409  *representing the address in "dots and numbers"
410  *
411  */
412 char *
413 olsr_ip_to_string(union olsr_ip_addr *addr)
414 {
415
416   char *ret;
417   struct in_addr in;
418   
419   if(ipversion == AF_INET)
420     {
421       in.s_addr=addr->v4;
422       ret = inet_ntoa(in);
423     }
424   else
425     {
426       /* IPv6 */
427       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
428     }
429
430   return ret;
431 }
432
433
434
435
436 /**
437  *This function is just as bad as the previous one :-(
438  */
439 char *
440 olsr_netmask_to_string(union hna_netmask *mask)
441 {
442   char *ret;
443   struct in_addr in;
444   
445   if(ipversion == AF_INET)
446     {
447       in.s_addr = mask->v4;
448       ret = inet_ntoa(in);
449       return ret;
450
451     }
452   else
453     {
454       /* IPv6 */
455       sprintf(netmask, "%d", mask->v6);
456       return netmask;
457     }
458
459   return ret;
460 }
461
462