9175b4f04a02577d59efbb52902d79ffda94cfa1
[olsrd.git] / lib / pgraph / src / olsrd_pgraph.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
5  *                     includes code by Bruno Randolf
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  *   notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  * * Neither the name of olsr.org, olsrd nor the names of its
19  *   contributors may be used to endorse or promote products derived
20  *   from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Visit http://www.olsr.org for more information.
36  *
37  * If you find this software useful feel free to make a donation
38  * to the project. For more information see the website or contact
39  * the copyright holders.
40  *
41  */
42
43 /*
44  * Dynamic linked library for the olsr.org olsr daemon
45  */
46
47 #include "olsrd_pgraph.h"
48 #include "ipcalc.h"
49 #include "socket_parser.h"
50 #include "olsrd_plugin.h"
51 #include "plugin_util.h"
52 #include "net_olsr.h"
53
54 #include <stdio.h>
55 #include <string.h>
56 #include <stdlib.h>
57 #include <unistd.h>
58 #include <errno.h>
59 #ifdef WIN32
60 #define close(x) closesocket(x)
61 #endif
62
63 #define PLUGIN_NAME    "OLSRD pgraph plugin"
64 #define PLUGIN_VERSION "0.1"
65 #define PLUGIN_AUTHOR   "Richard Gopaul"
66 #define MOD_DESC PLUGIN_NAME " " PLUGIN_VERSION " by " PLUGIN_AUTHOR
67 #define PLUGIN_INTERFACE_VERSION 5
68
69 static union olsr_ip_addr ipc_accept_ip;
70 static int ipc_port;
71
72 static int ipc_socket;
73 static int ipc_connection;
74
75 void my_init(void) __attribute__ ((constructor));
76
77 void my_fini(void) __attribute__ ((destructor));
78
79 /*
80  * Defines the version of the plugin interface that is used
81  * THIS IS NOT THE VERSION OF YOUR PLUGIN!
82  * Do not alter unless you know what you are doing!
83  */
84 int
85 olsrd_plugin_interface_version(void)
86 {
87   return PLUGIN_INTERFACE_VERSION;
88 }
89
90 /**
91  *Constructor
92  */
93 void
94 my_init(void)
95 {
96   /* Print plugin info to stdout */
97   printf("%s\n", MOD_DESC);
98
99   /* defaults for parameters */
100   ipc_port = 2004;
101   if (olsr_cnf->ip_version == AF_INET) {
102     ipc_accept_ip.v4.s_addr = htonl(INADDR_LOOPBACK);
103   } else {
104     ipc_accept_ip.v6 = in6addr_loopback;
105   }
106   ipc_socket = -1;
107   ipc_connection = -1;
108 }
109
110 /**
111  *Destructor
112  */
113 void
114 my_fini(void)
115 {
116   if (ipc_socket >= 0) {
117     close(ipc_socket);
118     ipc_socket = -1;
119   }
120   if (ipc_connection >= 0) {
121     close(ipc_connection);
122     ipc_connection = -1;
123   }
124
125 }
126
127 static const struct olsrd_plugin_parameters plugin_parameters[] = {
128   {.name = "port",.set_plugin_parameter = &set_plugin_port,.data = &ipc_port},
129   {.name = "accept",.set_plugin_parameter = &set_plugin_ipaddress,.data = &ipc_accept_ip},
130 };
131
132 void
133 olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
134 {
135   *params = plugin_parameters;
136   *size = sizeof(plugin_parameters) / sizeof(*plugin_parameters);
137 }
138
139 /* Event function to register with the sceduler */
140 static int pcf_event(int, int, int);
141
142 static void ipc_action(int);
143
144 static void ipc_print_neigh_link(struct neighbor_entry *neighbor);
145
146 static void ipc_print_tc_link(struct tc_entry *entry, struct tc_edge_entry *dst_entry);
147
148 static int ipc_send(const char *, int);
149
150 static void ipc_print_neigh_link(struct neighbor_entry *);
151
152 static int plugin_ipc_init(void);
153
154 static void
155 ipc_print_neigh_link(struct neighbor_entry *neighbor)
156 {
157   char buf[256];
158   int len;
159   struct ipaddr_str main_adr, adr;
160 //  double etx=0.0;
161 //  char* style = "solid";
162 //  struct link_entry* link;
163
164   len =
165     sprintf(buf, "add link %s %s\n", olsr_ip_to_string(&main_adr, &olsr_cnf->main_addr),
166             olsr_ip_to_string(&adr, &neighbor->neighbor_main_addr));
167   ipc_send(buf, len);
168
169 //  if (neighbor->status == 0) { // non SYM
170 //      style = "dashed";
171 //  }
172 //  else {
173   /* find best link to neighbor for the ETX */
174   //? why cant i just get it one time at fetch_olsrd_data??? (br1)
175 //    if(olsr_plugin_io(GETD__LINK_SET, &link, sizeof(link)) && link)
176 //    {
177 //      link_set = link; // for olsr_neighbor_best_link
178 //      link = olsr_neighbor_best_link(&neighbor->neighbor_main_addr);
179 //      if (link) {
180 //        etx = olsr_calc_etx(link);
181 //      }
182 //    }
183 //  }
184
185   //len = sprintf( buf, "\"%s\"[label=\"%.2f\", style=%s];\n", adr, etx, style );
186   //len = sprintf( buf, "%s\n", adr );
187   //ipc_send(buf, len);
188
189   //if (neighbor->is_mpr) {
190   //   len = sprintf( buf, "\"%s\"[shape=box];\n", adr );
191   //   ipc_send(buf, len);
192   //}
193 }
194
195 /**
196  *Do initialization here
197  *
198  *This function is called by the my_init
199  *function in uolsrd_plugin.c
200  */
201 int
202 olsrd_plugin_init(void)
203 {
204
205   /* Initial IPC value */
206   ipc_socket = -1;
207
208   /* Register the "ProcessChanges" function */
209   register_pcf(&pcf_event);
210
211   return 1;
212 }
213
214 static int
215 plugin_ipc_init(void)
216 {
217   struct sockaddr_in sin;
218   uint32_t yes = 1;
219
220   /* Init ipc socket */
221   if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
222     olsr_printf(1, "(DOT DRAW)IPC socket %s\n", strerror(errno));
223     return 0;
224   } else {
225     if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
226       perror("SO_REUSEADDR failed");
227       return 0;
228     }
229 #ifdef __FreeBSD__
230     if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
231       perror("SO_NOSIGPIPE failed");
232       return 0;
233     }
234 #endif
235
236     /* Bind the socket */
237
238     /* complete the socket structure */
239     memset(&sin, 0, sizeof(sin));
240     sin.sin_family = AF_INET;
241     sin.sin_addr.s_addr = INADDR_ANY;
242     sin.sin_port = htons(ipc_port);
243
244     /* bind the socket to the port number */
245     if (bind(ipc_socket, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
246       olsr_printf(1, "(DOT DRAW)IPC bind %s\n", strerror(errno));
247       return 0;
248     }
249
250     /* show that we are willing to listen */
251     if (listen(ipc_socket, 1) == -1) {
252       olsr_printf(1, "(DOT DRAW)IPC listen %s\n", strerror(errno));
253       return 0;
254     }
255
256     /* Register with olsrd */
257     add_olsr_socket(ipc_socket, &ipc_action);
258   }
259
260   return 1;
261 }
262
263 static void
264 ipc_action(int fd __attribute__ ((unused)))
265 {
266   struct sockaddr_in pin;
267   socklen_t addrlen;
268   char *addr;
269   char buf[256];
270   int len;
271
272   addrlen = sizeof(struct sockaddr_in);
273
274   if ((ipc_connection = accept(ipc_socket, (struct sockaddr *)&pin, &addrlen)) == -1) {
275     olsr_printf(1, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
276     exit(1);
277   } else {
278     struct ipaddr_str main_addr;
279     addr = inet_ntoa(pin.sin_addr);
280
281 /*
282       if(ntohl(pin.sin_addr.s_addr) != ntohl(ipc_accept_ip.s_addr))
283         {
284           olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
285           close(ipc_connection);
286           return;
287         }
288       else
289         {
290 */
291     olsr_printf(1, "(DOT DRAW)IPC: Connection from %s\n", addr);
292     len = sprintf(buf, "add node %s\n", olsr_ip_to_string(&main_addr, &olsr_cnf->main_addr));
293     ipc_send(buf, len);
294     pcf_event(1, 1, 1);
295 //      }
296   }
297
298 }
299
300 /**
301  *Scheduled event
302  */
303 static int
304 pcf_event(int my_changes_neighborhood, int my_changes_topology, int my_changes_hna __attribute__ ((unused)))
305 {
306   int res;
307   struct neighbor_entry *neighbor_table_tmp;
308   struct tc_entry *tc;
309   struct tc_edge_entry *tc_edge;
310
311   res = 0;
312
313   if (my_changes_neighborhood || my_changes_topology) {
314     /* Print tables to IPC socket */
315
316     //ipc_send("start ", strlen("start "));
317
318     /* Neighbors */
319     OLSR_FOR_ALL_NBR_ENTRIES(neighbor_table_tmp) {
320       ipc_print_neigh_link(neighbor_table_tmp);
321     }
322     OLSR_FOR_ALL_NBR_ENTRIES_END(neighbor_table_tmp);
323
324     /* Topology */
325     OLSR_FOR_ALL_TC_ENTRIES(tc) {
326       OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
327         ipc_print_tc_link(tc, tc_edge);
328       }
329       OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
330     }
331     OLSR_FOR_ALL_TC_ENTRIES_END(tc);
332
333     ipc_send(" end ", strlen(" end "));
334
335     /* HNA entries */
336 //      for(index=0;index<HASHSIZE;index++)
337 //      {
338 //        tmp_hna = hna_set[index].next;
339 //        /* Check all entrys */
340 //        while(tmp_hna != &hna_set[index])
341 //          {
342 //            /* Check all networks */
343 //            tmp_net = tmp_hna->networks.next;
344 //
345 //            while(tmp_net != &tmp_hna->networks)
346 //              {
347 //                ipc_print_net(&tmp_hna->A_gateway_addr,
348 //                              &tmp_net->A_network_addr,
349 //                              &tmp_net->A_netmask);
350 //                tmp_net = tmp_net->next;
351 //              }
352 //
353 //            tmp_hna = tmp_hna->next;
354 //          }
355 //      }
356
357 //      ipc_send("}\n\n", strlen("}\n\n"));
358
359     res = 1;
360   }
361
362   if (ipc_socket == -1) {
363     plugin_ipc_init();
364   }
365
366   return res;
367 }
368
369 static void
370 ipc_print_tc_link(struct tc_entry *entry, struct tc_edge_entry *dst_entry)
371 {
372   char buf[256];
373   int len;
374   struct ipaddr_str main_adr, adr;
375 //  double etx = olsr_calc_tc_etx(dst_entry);
376
377   len =
378     sprintf(buf, "add link %s %s\n", olsr_ip_to_string(&main_adr, &entry->addr), olsr_ip_to_string(&adr, &dst_entry->T_dest_addr));
379   ipc_send(buf, len);
380 }
381
382 static int
383 ipc_send(const char *data, int size)
384 {
385   if (ipc_connection == -1)
386     return 0;
387
388 #if defined __FreeBSD__ || defined __MacOSX__ || __OpenBSD__
389 #define FLAG 0
390 #else
391 #define FLAG MSG_NOSIGNAL
392 #endif
393   if (send(ipc_connection, data, size, FLAG) < 0) {
394     olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
395     close(ipc_connection);
396     ipc_connection = -1;
397     return -1;
398   }
399
400   return 1;
401 }
402
403 /*
404  * Local Variables:
405  * c-basic-offset: 2
406  * indent-tabs-mode: nil
407  * End:
408  */