Plugin interface updates, topology is generated upon every connection
[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.6 2004/11/06 14:07:20 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(2004);
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) != INADDR_LOOPBACK)
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
252       /* HNA entries */
253       for(index=0;index<HASHSIZE;index++)
254         {
255           tmp_hna = hna_set[index].next;
256           /* Check all entrys */
257           while(tmp_hna != &hna_set[index])
258             {
259               /* Check all networks */
260               tmp_net = tmp_hna->networks.next;
261               
262               while(tmp_net != &tmp_hna->networks)
263                 {
264                   ipc_print_net(&tmp_hna->A_gateway_addr, 
265                                 &tmp_net->A_network_addr, 
266                                 &tmp_net->A_netmask);
267                   tmp_net = tmp_net->next;
268                 }
269               
270               tmp_hna = tmp_hna->next;
271             }
272         }
273
274
275       ipc_send("}\n\n", strlen("}\n\n"));
276
277       res = 1;
278     }
279
280
281   if(!ipc_socket_up)
282     plugin_ipc_init();
283
284   return res;
285 }
286
287
288
289
290 static void inline
291 ipc_print_neigh_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
292 {
293   char *adr;
294
295   adr = olsr_ip_to_string(from);
296   ipc_send("\"", 1);
297   ipc_send(adr, strlen(adr));
298   ipc_send("\" -> \"", strlen("\" -> \""));
299   adr = olsr_ip_to_string(to);
300   ipc_send(adr, strlen(adr));
301   ipc_send("\"[label=\"neigh\", style=dashed];\n", strlen("\"[label=\"neigh\", style=dashed];\n"));
302
303 }
304
305 static void inline
306 ipc_print_2h_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
307 {
308   char *adr;
309
310   adr = olsr_ip_to_string(from);
311   ipc_send("\"", 1);
312   ipc_send(adr, strlen(adr));
313   ipc_send("\" -> \"", strlen("\" -> \""));
314   adr = olsr_ip_to_string(to);
315   ipc_send(adr, strlen(adr));
316   ipc_send("\"[label=\"2 hop\"];\n", strlen("\"[label=\"2 hop\"];\n"));
317
318 }
319
320 static void inline
321 ipc_print_mpr_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
322 {
323   char *adr;
324
325   adr = olsr_ip_to_string(from);
326   ipc_send("\"", 1);
327   ipc_send(adr, strlen(adr));
328   ipc_send("\" -> \"", strlen("\" -> \""));
329   adr = olsr_ip_to_string(to);
330   ipc_send(adr, strlen(adr));
331   ipc_send("\"[label=\"MPR\", style=dashed];\n", strlen("\"[label=\"MPR\", style=dashed]];\n"));
332
333 }
334
335 static void inline
336 ipc_print_tc_link(union olsr_ip_addr *from, union olsr_ip_addr *to)
337 {
338   char *adr;
339
340   adr = olsr_ip_to_string(from);
341   ipc_send("\"", 1);
342   ipc_send(adr, strlen(adr));
343   ipc_send("\" -> \"", strlen("\" -> \""));
344   adr = olsr_ip_to_string(to);
345   ipc_send(adr, strlen(adr));
346   ipc_send("\"[label=\"TC\"];\n", strlen("\"[label=\"TC\"];\n"));
347
348 }
349
350 static void inline
351 ipc_print_net(union olsr_ip_addr *gw, union olsr_ip_addr *net, union hna_netmask *mask)
352 {
353   char *adr;
354
355   adr = olsr_ip_to_string(gw);
356   ipc_send("\"", 1);
357   ipc_send(adr, strlen(adr));
358   ipc_send("\" -> \"", strlen("\" -> \""));
359   adr = olsr_ip_to_string(net);
360   ipc_send(adr, strlen(adr));
361   ipc_send("/", 1);
362   adr = olsr_netmask_to_string(mask);
363   ipc_send(adr, strlen(adr));
364   ipc_send("\"[label=\"HNA\"];\n", strlen("\"[label=\"HNA\"];\n"));
365   ipc_send("\"", 1);
366   adr = olsr_ip_to_string(net);
367   ipc_send(adr, strlen(adr));
368   ipc_send("/", 1);
369   adr = olsr_netmask_to_string(mask);
370   ipc_send(adr, strlen(adr));
371   ipc_send("\"", 1);
372   ipc_send("[shape=diamond];\n", strlen("[shape=diamond];\n"));
373 }
374
375
376
377 int
378 ipc_send(char *data, int size)
379 {
380   if(!ipc_open)
381     return 0;
382
383   if (send(ipc_connection, data, size, MSG_NOSIGNAL) < 0) 
384     {
385       olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
386       close(ipc_connection);
387       ipc_open = 0;
388       return -1;
389     }
390
391   return 1;
392 }
393
394
395
396
397
398 /**
399  *Converts a olsr_ip_addr to a string
400  *Goes for both IPv4 and IPv6
401  *
402  *NON REENTRANT! If you need to use this
403  *function twice in e.g. the same printf
404  *it will not work.
405  *You must use it in different calls e.g.
406  *two different printfs
407  *
408  *@param the IP to convert
409  *@return a pointer to a static string buffer
410  *representing the address in "dots and numbers"
411  *
412  */
413 char *
414 olsr_ip_to_string(union olsr_ip_addr *addr)
415 {
416
417   char *ret;
418   struct in_addr in;
419   
420   if(ipversion == AF_INET)
421     {
422       in.s_addr=addr->v4;
423       ret = inet_ntoa(in);
424     }
425   else
426     {
427       /* IPv6 */
428       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
429     }
430
431   return ret;
432 }
433
434
435
436
437 /**
438  *This function is just as bad as the previous one :-(
439  */
440 char *
441 olsr_netmask_to_string(union hna_netmask *mask)
442 {
443   char *ret;
444   struct in_addr in;
445   
446   if(ipversion == AF_INET)
447     {
448       in.s_addr = mask->v4;
449       ret = inet_ntoa(in);
450       return ret;
451
452     }
453   else
454     {
455       /* IPv6 */
456       sprintf(netmask, "%d", mask->v6);
457       return netmask;
458     }
459
460   return ret;
461 }
462
463