Win32 fixes: use CLOSESOCKET to close sockets
[olsrd.git] / lib / pgraph / src / olsrd_pgraph.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas Tonnesen(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  */
41
42 /*
43  * Dynamic linked library for the olsr.org olsr daemon
44  */
45
46 #include "olsrd_pgraph.h"
47 #include "ipcalc.h"
48 #include "olsrd_plugin.h"
49 #include "plugin_util.h"
50 #include "net_olsr.h"
51
52 #include <stdio.h>
53 #include <string.h>
54 #include <stdlib.h>
55 #include <unistd.h>
56 #include <errno.h>
57
58 #define PLUGIN_NAME    "OLSRD pgraph plugin"
59 #define PLUGIN_VERSION "0.1"
60 #define PLUGIN_AUTHOR   "Richard Gopaul"
61 #define MOD_DESC PLUGIN_NAME " " PLUGIN_VERSION " by " PLUGIN_AUTHOR
62 #define PLUGIN_INTERFACE_VERSION 5
63
64 static union olsr_ip_addr ipc_accept_ip;
65 static int ipc_port;
66
67 static int ipc_socket;
68 static int ipc_connection;
69
70 void my_init(void) __attribute__((constructor));
71
72 void my_fini(void) __attribute__((destructor));
73
74 /*
75  * Defines the version of the plugin interface that is used
76  * THIS IS NOT THE VERSION OF YOUR PLUGIN!
77  * Do not alter unless you know what you are doing!
78  */
79 int
80 olsrd_plugin_interface_version(void)
81 {
82    return PLUGIN_INTERFACE_VERSION;
83 }
84
85
86 /**
87  *Constructor
88  */
89 void
90 my_init(void)
91 {
92   /* Print plugin info to stdout */
93   printf("%s\n", MOD_DESC);
94
95   /* defaults for parameters */
96   ipc_port = 2004;
97   if (olsr_cnf->ip_version == AF_INET) {
98     ipc_accept_ip.v4.s_addr = htonl(INADDR_LOOPBACK);
99   } else {
100     ipc_accept_ip.v6 = in6addr_loopback;
101   }
102   ipc_socket = -1;
103   ipc_connection = -1;
104 }
105
106 /**
107  *Destructor
108  */
109 void
110 my_fini(void)
111 {
112   if(ipc_socket >= 0) {
113     CLOSESOCKET(ipc_socket);
114     ipc_socket = -1;
115   }
116   if(ipc_connection >= 0) {
117     CLOSESOCKET(ipc_connection);
118     ipc_connection = -1;
119   }
120
121 }
122
123 static const struct olsrd_plugin_parameters plugin_parameters[] = {
124     { .name = "port",   .set_plugin_parameter = &set_plugin_port,      .data = &ipc_port },
125     { .name = "accept", .set_plugin_parameter = &set_plugin_ipaddress, .data = &ipc_accept_ip },
126 };
127
128 void olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
129 {
130     *params = plugin_parameters;
131     *size = ARRAYSIZE(plugin_parameters);
132 }
133
134 /* Event function to register with the sceduler */
135 static int pcf_event(int, int, int);
136
137 static void ipc_action(int, void *, unsigned int);
138
139 static void ipc_print_neigh_link(struct neighbor_entry *neighbor);
140
141 static void ipc_print_tc_link(struct tc_entry *entry, struct tc_edge_entry *dst_entry);
142
143 static int ipc_send(const char *, int);
144
145 static void ipc_print_neigh_link(struct neighbor_entry *);
146
147 static int plugin_ipc_init(void);
148
149
150 static void ipc_print_neigh_link(struct neighbor_entry *neighbor)
151 {
152   char buf[256];
153   int len;
154   struct ipaddr_str main_adr, adr;
155 //  double etx=0.0;
156 //  char* style = "solid";
157 //  struct link_entry* link;
158
159   len = sprintf(buf,
160                 "add link %s %s\n",
161                 olsr_ip_to_string(&main_adr, &olsr_cnf->main_addr),
162                 olsr_ip_to_string(&adr, &neighbor->neighbor_main_addr));
163   ipc_send(buf, len);
164
165 //  if (neighbor->status == 0) { // non SYM
166 //      style = "dashed";
167 //  }
168 //  else {
169     /* find best link to neighbor for the ETX */
170     //? why cant i just get it one time at fetch_olsrd_data??? (br1)
171 //    if(olsr_plugin_io(GETD__LINK_SET, &link, sizeof(link)) && link)
172 //    {
173 //      link_set = link; // for olsr_neighbor_best_link
174 //      link = olsr_neighbor_best_link(&neighbor->neighbor_main_addr);
175 //      if (link) {
176 //        etx = olsr_calc_etx(link);
177 //      }
178 //    }
179 //  }
180
181   //len = sprintf( buf, "\"%s\"[label=\"%.2f\", style=%s];\n", adr, etx, style );
182   //len = sprintf( buf, "%s\n", adr );
183   //ipc_send(buf, len);
184
185    //if (neighbor->is_mpr) {
186    //   len = sprintf( buf, "\"%s\"[shape=box];\n", adr );
187    //   ipc_send(buf, len);
188    //}
189 }
190
191 /**
192  *Do initialization here
193  *
194  *This function is called by the my_init
195  *function in uolsrd_plugin.c
196  */
197 int olsrd_plugin_init(void)
198 {
199
200   /* Initial IPC value */
201   ipc_socket = -1;
202
203   /* Register the "ProcessChanges" function */
204   register_pcf(&pcf_event);
205
206   return 1;
207 }
208
209 static int plugin_ipc_init(void)
210 {
211   struct sockaddr_in sin4;
212   uint32_t yes = 1;
213
214   /* Init ipc socket */
215   if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
216     {
217       olsr_printf(1, "(DOT DRAW)IPC socket %s\n", strerror(errno));
218       return 0;
219     }
220   else
221     {
222       if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0)
223       {
224         perror("SO_REUSEADDR failed");
225         return 0;
226       }
227
228 #ifdef __FreeBSD__
229       if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0)
230       {
231         perror("SO_NOSIGPIPE failed");
232         return 0;
233       }
234 #endif
235
236       /* Bind the socket */
237
238       /* complete the socket structure */
239       memset(&sin4, 0, sizeof(sin4));
240       sin4.sin_family = AF_INET;
241       sin4.sin_addr.s_addr = INADDR_ANY;
242       sin4.sin_port = htons(ipc_port);
243
244       /* bind the socket to the port number */
245       if (bind(ipc_socket, (struct sockaddr *) &sin4, sizeof(sin4)) == -1)
246         {
247           olsr_printf(1, "(DOT DRAW)IPC bind %s\n", strerror(errno));
248           return 0;
249         }
250
251       /* show that we are willing to listen */
252       if (listen(ipc_socket, 1) == -1)
253         {
254           olsr_printf(1, "(DOT DRAW)IPC listen %s\n", strerror(errno));
255           return 0;
256         }
257
258
259       /* Register with olsrd */
260       add_olsr_socket(ipc_socket, &ipc_action, NULL, NULL, SP_PR_READ);
261     }
262
263   return 1;
264 }
265
266 static void ipc_action(int fd __attribute__((unused)), void *data __attribute__((unused)), unsigned int flags __attribute__((unused)))
267 {
268   struct sockaddr_in pin;
269   socklen_t addrlen;
270   char *addr;
271   char buf[256] ;
272   int len ;
273
274   addrlen = sizeof(struct sockaddr_in);
275
276   if ((ipc_connection = accept(ipc_socket, (struct sockaddr *)  &pin, &addrlen)) == -1)
277     {
278       olsr_printf(1, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
279       exit(1);
280     }
281   else
282     {
283       struct ipaddr_str main_addr;
284       addr = inet_ntoa(pin.sin_addr);
285 /*
286       if(ntohl(pin.sin_addr.s_addr) != ntohl(ipc_accept_ip.s_addr))
287         {
288           olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
289           CLOSESOCKET(ipc_connection);
290           return;
291         }
292       else
293         {
294 */
295           olsr_printf(1, "(DOT DRAW)IPC: Connection from %s\n",addr);
296           len = sprintf(buf, "add node %s\n", olsr_ip_to_string(&main_addr, &olsr_cnf->main_addr));
297           ipc_send(buf, len);
298           pcf_event(1, 1, 1);
299 //      }
300     }
301
302 }
303
304 /**
305  *Scheduled event
306  */
307 static int pcf_event(int chgs_neighborhood,
308                      int chgs_topology,
309                      int chgs_hna __attribute__((unused)))
310 {
311   int res;
312   struct neighbor_entry *neighbor_table_tmp;
313   struct tc_entry *tc;
314   struct tc_edge_entry *tc_edge;
315
316   res = 0;
317
318   if (chgs_neighborhood || chgs_topology) {
319     /* Print tables to IPC socket */
320
321     //ipc_send("start ", strlen("start "));
322
323     /* Neighbors */
324     OLSR_FOR_ALL_NBR_ENTRIES(neighbor_table_tmp) {
325       ipc_print_neigh_link( neighbor_table_tmp );
326     } OLSR_FOR_ALL_NBR_ENTRIES_END(neighbor_table_tmp);
327
328     /* Topology */
329     OLSR_FOR_ALL_TC_ENTRIES(tc) {
330       OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
331         ipc_print_tc_link(tc, tc_edge);
332       } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
333     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
334
335     ipc_send(" end ", strlen(" end "));
336
337     /* HNA entries */
338 //      for(index=0;index<HASHSIZE;index++)
339 //      {
340 //        tmp_hna = hna_set[index].next;
341 //        /* Check all entrys */
342 //        while(tmp_hna != &hna_set[index])
343 //          {
344 //            /* Check all networks */
345 //            tmp_net = tmp_hna->networks.next;
346 //
347 //            while(tmp_net != &tmp_hna->networks)
348 //              {
349 //                ipc_print_net(&tmp_hna->A_gateway_addr,
350 //                              &tmp_net->A_network_addr,
351 //                              &tmp_net->A_netmask);
352 //                tmp_net = tmp_net->next;
353 //              }
354 //
355 //            tmp_hna = tmp_hna->next;
356 //          }
357 //      }
358
359 //      ipc_send("}\n\n", strlen("}\n\n"));
360
361     res = 1;
362   }
363
364   if (ipc_socket == -1) {
365     plugin_ipc_init();
366   }
367
368   return res;
369 }
370
371 static void ipc_print_tc_link(struct tc_entry *entry, struct tc_edge_entry *dst_entry)
372 {
373   char buf[256];
374   int len;
375   struct ipaddr_str main_adr, adr;
376 //  double etx = olsr_calc_tc_etx(dst_entry);
377
378   len = sprintf( buf, "add link %s %s\n",
379                  olsr_ip_to_string(&main_adr, &entry->addr),
380                  olsr_ip_to_string(&adr, &dst_entry->T_dest_addr));
381   ipc_send(buf, len);
382 }
383
384 static int ipc_send(const char *data, int size)
385 {
386   if(ipc_connection == -1)
387     return 0;
388
389 #if defined __FreeBSD__ || defined __MacOSX__
390 #define FLAG 0
391 #else
392 #define FLAG MSG_NOSIGNAL
393 #endif
394   if (send(ipc_connection, data, size, FLAG) < 0)
395     {
396       olsr_printf(1, "(DOT DRAW)IPC connection lost!\n");
397       CLOSESOCKET(ipc_connection);
398       ipc_connection = -1;
399       return -1;
400     }
401
402   return 1;
403 }
404
405 /*
406  * Local Variables:
407  * c-basic-offset: 2
408  * indent-tabs-mode: nil
409  * End:
410  */