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