Convert some plugins to new logger
[olsrd.git] / lib / dot_draw / src / olsrd_dot_draw.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in
14  *   the documentation and/or other materials provided with the
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  */
40
41 /*
42  * Dynamic linked library for the olsr.org olsr daemon
43  */
44
45 #include "olsrd_dot_draw.h"
46 #include "olsr.h"
47 #include "ipcalc.h"
48 #include "neighbor_table.h"
49 #include "tc_set.h"
50 #include "hna_set.h"
51 #include "link_set.h"
52 #include "olsr_ip_prefix_list.h"
53 #include "olsr_logging.h"
54
55 #ifdef _WRS_KERNEL
56 #include <vxWorks.h>
57 #include <sockLib.h>
58 #include <wrn/coreip/netinet/in.h>
59 #else
60 #include <unistd.h>
61 #include <errno.h>
62 #include <stdarg.h>
63 #endif
64
65 #ifdef _WRS_KERNEL
66 static int ipc_open;
67 static int ipc_socket_up;
68 #define DOT_DRAW_PORT 2004
69 #endif
70
71 static int ipc_socket;
72
73 /* IPC initialization function */
74 static int
75 plugin_ipc_init(void);
76
77 /* Event function to register with the sceduler */
78 static int
79 pcf_event(int, int, int, int);
80
81 static void
82 ipc_action(int, void *, unsigned int);
83
84 static void
85 ipc_print_neigh_link(int, const struct neighbor_entry *neighbor);
86
87 static void
88 ipc_print_tc_link(int, const struct tc_entry *, const struct tc_edge_entry *);
89
90 static void
91 ipc_print_net(int, const union olsr_ip_addr *, const struct olsr_ip_prefix *);
92
93 static void
94 ipc_send(int, const char *, int);
95
96 static void
97 ipc_send_fmt(int, const char *format, ...) __attribute__((format(printf,2,3)));
98
99 #define ipc_send_str(fd, data) ipc_send((fd), (data), strlen(data))
100
101
102 /**
103  *Do initialization here
104  *
105  *This function is called by the my_init
106  *function in uolsrd_plugin.c
107  */
108 #ifdef _WRS_KERNEL
109 int olsrd_dotdraw_init(void)
110 #else
111 int olsrd_plugin_init(void)
112 #endif
113 {
114   /* Initial IPC value */
115   ipc_socket = -1;
116
117   plugin_ipc_init();
118
119   return 1;
120 }
121
122
123 /**
124  * destructor - called at unload
125  */
126 #ifdef _WRS_KERNEL
127 void olsrd_dotdraw_exit(void)
128 #else
129 void olsr_plugin_exit(void)
130 #endif
131 {
132   if (ipc_socket != -1) {
133     CLOSESOCKET(ipc_socket);
134   }
135 }
136
137
138 static void
139 ipc_print_neigh_link(int ipc_connection, const struct neighbor_entry *neighbor)
140 {
141   struct ipaddr_str mainaddrstrbuf, strbuf;
142   olsr_linkcost etx = 0.0;
143   const char *style;
144   const char *adr = olsr_ip_to_string(&mainaddrstrbuf, &olsr_cnf->router_id);
145   struct lqtextbuffer lqbuffer;
146
147   if (neighbor->status == 0) { /* non SYM */
148     style = "dashed";
149   } else {
150     const struct link_entry* lnk = get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
151     if (lnk) {
152       etx = lnk->linkcost;
153     }
154     style = "solid";
155   }
156
157   ipc_send_fmt(ipc_connection,
158                "\"%s\" -> \"%s\"[label=\"%s\", style=%s];\n",
159                adr,
160                olsr_ip_to_string(&strbuf, &neighbor->neighbor_main_addr),
161                get_linkcost_text(etx, false, &lqbuffer),
162                style);
163
164   if (neighbor->is_mpr) {
165     ipc_send_fmt(ipc_connection, "\"%s\"[shape=box];\n", adr);
166   }
167 }
168
169
170 static int
171 plugin_ipc_init(void)
172 {
173   struct sockaddr_in addr;
174   uint32_t yes = 1;
175
176   if (ipc_socket != -1) {
177     CLOSESOCKET(ipc_socket);
178   }
179
180   /* Init ipc socket */
181   ipc_socket = socket(AF_INET, SOCK_STREAM, 0);
182   if (ipc_socket == -1) {
183     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC socket %s\n", strerror(errno));
184     return 0;
185   }
186
187   if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
188     OLSR_WARN(LOG_PLUGINS, "SO_REUSEADDR failed %s\n", strerror(errno));
189     CLOSESOCKET(ipc_socket);
190     return 0;
191   }
192
193 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
194   if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
195     OLSR_WARN(LOG_PLUGINS, "SO_REUSEADDR failed %s\n", strerror(errno));
196     CLOSESOCKET(ipc_socket);
197     return 0;
198   }
199 #endif
200
201   /* Bind the socket */
202
203   /* complete the socket structure */
204   memset(&addr, 0, sizeof(addr));
205   addr.sin_family = AF_INET;
206   addr.sin_addr.s_addr = INADDR_ANY;
207   addr.sin_port = htons(ipc_port);
208
209   /* bind the socket to the port number */
210   if (bind(ipc_socket, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
211     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC bind %s\n", strerror(errno));
212     CLOSESOCKET(ipc_socket);
213     return 0;
214   }
215
216   /* show that we are willing to listen */
217   if (listen(ipc_socket, 1) == -1) {
218     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC listen %s\n", strerror(errno));
219     CLOSESOCKET(ipc_socket);
220     return 0;
221   }
222
223   /* Register with olsrd */
224   add_olsr_socket(ipc_socket, &ipc_action, NULL, NULL, SP_PR_READ);
225
226   return 1;
227 }
228
229
230 static void
231 ipc_action(int fd __attribute__((unused)), void *data __attribute__((unused)), unsigned int flags __attribute__((unused)))
232 {
233   struct sockaddr_in pin;
234   socklen_t addrlen = sizeof(struct sockaddr_in);
235   int ipc_connection = accept(ipc_socket, (struct sockaddr *)&pin, &addrlen);
236   if (ipc_connection == -1) {
237     OLSR_WARN(LOG_PLUGINS, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
238     return;
239   }
240 #ifndef _WRS_KERNEL
241   if (ip4cmp(&pin.sin_addr, &ipc_accept_ip.v4) != 0) {
242     OLSR_WARN(LOG_PLUGINS, "Front end-connection from foreign host (%s) not allowed!\n", inet_ntoa(pin.sin_addr));
243     CLOSESOCKET(ipc_connection);
244     return;
245   }
246 #endif
247   OLSR_DEBUG(LOG_PLUGINS, "(DOT DRAW)IPC: Connection from %s\n", inet_ntoa(pin.sin_addr));
248   pcf_event(ipc_connection, 1, 1, 1);
249   CLOSESOCKET(ipc_connection); /* close connection after one output */
250 }
251
252
253 /**
254  *Scheduled event
255  */
256 static int
257 pcf_event(int ipc_connection,
258           int chgs_neighborhood,
259           int chgs_topology,
260           int chgs_hna)
261 {
262   int res = 0;
263
264   if (chgs_neighborhood || chgs_topology || chgs_hna) {
265     struct neighbor_entry *neighbor_table_tmp;
266     struct tc_entry *tc;
267     struct ip_prefix_entry *hna;
268
269     /* Print tables to IPC socket */
270     ipc_send_str(ipc_connection, "digraph topology\n{\n");
271
272     /* Neighbors */
273     OLSR_FOR_ALL_NBR_ENTRIES(neighbor_table_tmp) {
274       ipc_print_neigh_link(ipc_connection, neighbor_table_tmp );
275     } OLSR_FOR_ALL_NBR_ENTRIES_END(neighbor_table_tmp);
276
277     /* Topology */
278     OLSR_FOR_ALL_TC_ENTRIES(tc) {
279       struct tc_edge_entry *tc_edge;
280       OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
281         if (tc_edge->edge_inv) {
282           ipc_print_tc_link(ipc_connection, tc, tc_edge);
283         }
284       } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
285     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
286
287     /* HNA entries */
288     OLSR_FOR_ALL_TC_ENTRIES(tc) {
289       /* Check all networks */
290       struct hna_net *tmp_net;
291       OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, tmp_net) {
292         ipc_print_net(ipc_connection,
293                       &tc->addr,
294                       &tmp_net->hna_prefix);
295         }
296       } OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, tmp_hna);
297     OLSR_FOR_ALL_TC_ENTRIES_END(tc);
298
299     /* Local HNA entries */
300     OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, hna) {
301       ipc_print_net(ipc_connection,
302                     &olsr_cnf->router_id,
303                     &hna->net);
304     } OLSR_FOR_ALL_IPPREFIX_ENTRIES_END()
305     ipc_send_str(ipc_connection, "}\n\n");
306
307     res = 1;
308   }
309
310   if (ipc_socket == -1) {
311     plugin_ipc_init();
312   }
313   return res;
314 }
315
316 static void
317 ipc_print_tc_link(int ipc_connection, const struct tc_entry *entry, const struct tc_edge_entry *dst_entry)
318 {
319   struct ipaddr_str strbuf1, strbuf2;
320   struct lqtextbuffer lqbuffer;
321
322   ipc_send_fmt(ipc_connection,
323                "\"%s\" -> \"%s\"[label=\"%s\"];\n",
324                olsr_ip_to_string(&strbuf1, &entry->addr),
325                olsr_ip_to_string(&strbuf2, &dst_entry->T_dest_addr),
326                get_linkcost_text(dst_entry->cost, false, &lqbuffer));
327 }
328
329
330 static void
331 ipc_print_net(int ipc_connection, const union olsr_ip_addr *gw, const struct olsr_ip_prefix *net)
332 {
333   struct ipaddr_str gwbuf;
334   struct ipprefix_str netbuf;
335
336   ipc_send_fmt(ipc_connection,
337                "\"%s\" -> \"%s\"[label=\"HNA\"];\n",
338                olsr_ip_to_string(&gwbuf, gw),
339                olsr_ip_prefix_to_string(&netbuf, net));
340   ipc_send_fmt(ipc_connection,
341                "\"%s\"[shape=diamond];\n",
342                netbuf.buf);
343 }
344
345 static void
346 ipc_send(int ipc_connection, const char *data, int size)
347 {
348   if (ipc_connection != -1) {
349 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __MacOSX__ || \
350 defined _WRS_KERNEL
351 #define FLAGS 0
352 #else
353 #define FLAGS MSG_NOSIGNAL
354 #endif
355     if (send(ipc_connection, data, size, FLAGS) == -1) {
356       OLSR_PRINTF(1, "(DOT DRAW)IPC connection lost!\n");
357       CLOSESOCKET(ipc_connection);
358     }
359   }
360 }
361
362 static void
363 ipc_send_fmt(int ipc_connection, const char *format, ...)
364 {
365   if (ipc_connection != -1) {
366     char buf[4096];
367     int len;
368     va_list arg;
369     va_start(arg, format);
370     len = vsnprintf(buf, sizeof(buf), format, arg);
371     va_end(arg);
372     ipc_send(ipc_connection, buf, len);
373   }
374 }
375
376 /*
377  * Local Variables:
378  * c-basic-offset: 2
379  * indent-tabs-mode: nil
380  * End:
381  */