zapped olsr_printf
[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, 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_dot_draw.h"
47 #include "olsr.h"
48 #include "ipcalc.h"
49 #include "neighbor_table.h"
50 #include "tc_set.h"
51 #include "hna_set.h"
52 #include "link_set.h"
53
54 #ifdef _WRS_KERNEL
55 #include <vxWorks.h>
56 #include <sockLib.h>
57 #include <wrn/coreip/netinet/in.h>
58 #else
59 #include <unistd.h>
60 #include <errno.h>
61 #include <stdarg.h>
62 #endif
63
64 #ifdef _WRS_KERNEL
65 static int ipc_open;
66 static int ipc_socket_up;
67 #define DOT_DRAW_PORT 2004
68 #endif
69
70 static int ipc_socket;
71
72 /* IPC initialization function */
73 static int
74 plugin_ipc_init(void);
75
76 /* Event function to register with the sceduler */
77 static int
78 pcf_event(int, int, int, int);
79
80 static void
81 ipc_action(int, void *, unsigned int);
82
83 static void
84 ipc_print_neigh_link(int, const struct neighbor_entry *neighbor);
85
86 static void
87 ipc_print_tc_link(int, const struct tc_entry *, const struct tc_edge_entry *);
88
89 static void
90 ipc_print_net(int, const union olsr_ip_addr *, const struct olsr_ip_prefix *);
91
92 static void
93 ipc_send(int, const char *, int);
94
95 static void
96 ipc_send_fmt(int, const char *format, ...) __attribute__((format(printf,2,3)));
97
98 #define ipc_send_str(fd, data) ipc_send((fd), (data), strlen(data))
99
100
101 /**
102  *Do initialization here
103  *
104  *This function is called by the my_init
105  *function in uolsrd_plugin.c
106  */
107 #ifdef _WRS_KERNEL
108 int olsrd_dotdraw_init(void)
109 #else
110 int olsrd_plugin_init(void)
111 #endif
112 {
113   /* Initial IPC value */
114   ipc_socket = -1;
115
116   plugin_ipc_init();
117
118   return 1;
119 }
120
121
122 /**
123  * destructor - called at unload
124  */
125 #ifdef _WRS_KERNEL
126 void olsrd_dotdraw_exit(void)
127 #else
128 void olsr_plugin_exit(void)
129 #endif
130 {
131   if (ipc_socket != -1) {
132     CLOSESOCKET(ipc_socket);
133   }
134 }
135
136
137 static void
138 ipc_print_neigh_link(int ipc_connection, const struct neighbor_entry *neighbor)
139 {
140   struct ipaddr_str mainaddrstrbuf, strbuf;
141   olsr_linkcost etx = 0.0;
142   const char *style;
143   const char *adr = olsr_ip_to_string(&mainaddrstrbuf, &olsr_cnf->main_addr);
144   struct lqtextbuffer lqbuffer;
145
146   if (neighbor->status == 0) { /* non SYM */
147     style = "dashed";
148   } else {
149     const struct link_entry* lnk = get_best_link_to_neighbor(&neighbor->neighbor_main_addr);
150     if (lnk) {
151       etx = lnk->linkcost;
152     }
153     style = "solid";
154   }
155
156   ipc_send_fmt(ipc_connection,
157                "\"%s\" -> \"%s\"[label=\"%s\", style=%s];\n",
158                adr,
159                olsr_ip_to_string(&strbuf, &neighbor->neighbor_main_addr),
160                get_linkcost_text(etx, false, &lqbuffer),
161                style);
162
163   if (neighbor->is_mpr) {
164     ipc_send_fmt(ipc_connection, "\"%s\"[shape=box];\n", adr);
165   }
166 }
167
168
169 static int
170 plugin_ipc_init(void)
171 {
172   struct sockaddr_in addr;
173   uint32_t yes = 1;
174
175   if (ipc_socket != -1) {
176     CLOSESOCKET(ipc_socket);
177   }
178
179   /* Init ipc socket */
180   ipc_socket = socket(AF_INET, SOCK_STREAM, 0);
181   if (ipc_socket == -1) {
182     OLSR_PRINTF(1, "(DOT DRAW)IPC socket %s\n", strerror(errno));
183     return 0;
184   }
185
186   if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) {
187     perror("SO_REUSEADDR failed");
188     CLOSESOCKET(ipc_socket);
189     return 0;
190   }
191
192 #if defined __FreeBSD__ && defined SO_NOSIGPIPE
193   if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) {
194     perror("SO_REUSEADDR failed");
195     CLOSESOCKET(ipc_socket);
196     return 0;
197   }
198 #endif
199
200   /* Bind the socket */
201
202   /* complete the socket structure */
203   memset(&addr, 0, sizeof(addr));
204   addr.sin_family = AF_INET;
205   addr.sin_addr.s_addr = INADDR_ANY;
206   addr.sin_port = htons(ipc_port);
207
208   /* bind the socket to the port number */
209   if (bind(ipc_socket, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
210     OLSR_PRINTF(1, "(DOT DRAW)IPC bind %s\n", strerror(errno));
211     CLOSESOCKET(ipc_socket);
212     return 0;
213   }
214
215   /* show that we are willing to listen */
216   if (listen(ipc_socket, 1) == -1) {
217     OLSR_PRINTF(1, "(DOT DRAW)IPC listen %s\n", strerror(errno));
218     CLOSESOCKET(ipc_socket);
219     return 0;
220   }
221
222   /* Register with olsrd */
223 #if 0
224   printf("Adding socket with olsrd\n");
225 #endif
226   add_olsr_socket(ipc_socket, &ipc_action, NULL, NULL, SP_PR_READ);
227
228   return 1;
229 }
230
231
232 static void
233 ipc_action(int fd __attribute__((unused)), void *data __attribute__((unused)), unsigned int flags __attribute__((unused)))
234 {
235   struct sockaddr_in pin;
236   socklen_t addrlen = sizeof(struct sockaddr_in);
237   int ipc_connection = accept(ipc_socket, (struct sockaddr *)&pin, &addrlen);
238   if (ipc_connection == -1) {
239     OLSR_PRINTF(1, "(DOT DRAW)IPC accept: %s\n", strerror(errno));
240     return;
241   }
242 #ifndef _WRS_KERNEL
243   if (!ip4equal(&pin.sin_addr, &ipc_accept_ip.v4)) {
244     OLSR_PRINTF(0, "Front end-connection from foreign host (%s) not allowed!\n", inet_ntoa(pin.sin_addr));
245     CLOSESOCKET(ipc_connection);
246     return;
247   }
248 #endif
249   OLSR_PRINTF(1, "(DOT DRAW)IPC: Connection from %s\n", inet_ntoa(pin.sin_addr));
250   pcf_event(ipc_connection, 1, 1, 1);
251   CLOSESOCKET(ipc_connection); /* close connection after one output */
252 }
253
254
255 /**
256  *Scheduled event
257  */
258 static int
259 pcf_event(int ipc_connection,
260           int chgs_neighborhood,
261           int chgs_topology,
262           int chgs_hna)
263 {
264   int res = 0;
265
266   if (chgs_neighborhood || chgs_topology || chgs_hna) {
267     struct neighbor_entry *neighbor_table_tmp;
268     struct tc_entry *tc;
269     struct ip_prefix_list *hna;
270
271     /* Print tables to IPC socket */
272     ipc_send_str(ipc_connection, "digraph topology\n{\n");
273
274     /* Neighbors */
275     OLSR_FOR_ALL_NBR_ENTRIES(neighbor_table_tmp) {
276       ipc_print_neigh_link(ipc_connection, neighbor_table_tmp );
277     } OLSR_FOR_ALL_NBR_ENTRIES_END(neighbor_table_tmp);
278
279     /* Topology */
280     OLSR_FOR_ALL_TC_ENTRIES(tc) {
281       struct tc_edge_entry *tc_edge;
282       OLSR_FOR_ALL_TC_EDGE_ENTRIES(tc, tc_edge) {
283         if (tc_edge->edge_inv) {
284           ipc_print_tc_link(ipc_connection, tc, tc_edge);
285         }
286       } OLSR_FOR_ALL_TC_EDGE_ENTRIES_END(tc, tc_edge);
287     } OLSR_FOR_ALL_TC_ENTRIES_END(tc);
288
289     /* HNA entries */
290     OLSR_FOR_ALL_TC_ENTRIES(tc) {
291       /* Check all networks */
292       struct hna_net *tmp_net;
293       OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, tmp_net) {
294         ipc_print_net(ipc_connection,
295                       &tc->addr,
296                       &tmp_net->hna_prefix);
297         }
298       } OLSR_FOR_ALL_TC_HNA_ENTRIES_END(tc, tmp_hna);
299     OLSR_FOR_ALL_TC_ENTRIES_END(tc);
300
301     /* Local HNA entries */
302     for (hna = olsr_cnf->hna_entries; hna != NULL; hna = hna->next) {
303       ipc_print_net(ipc_connection,
304                     &olsr_cnf->main_addr,
305                     &hna->net);
306     }
307     ipc_send_str(ipc_connection, "}\n\n");
308
309     res = 1;
310   }
311
312   if (ipc_socket == -1) {
313     plugin_ipc_init();
314   }
315   return res;
316 }
317
318 static void
319 ipc_print_tc_link(int ipc_connection, const struct tc_entry *entry, const struct tc_edge_entry *dst_entry)
320 {
321   struct ipaddr_str strbuf1, strbuf2;
322   struct lqtextbuffer lqbuffer;
323
324   ipc_send_fmt(ipc_connection,
325                "\"%s\" -> \"%s\"[label=\"%s\"];\n",
326                olsr_ip_to_string(&strbuf1, &entry->addr),
327                olsr_ip_to_string(&strbuf2, &dst_entry->T_dest_addr),
328                get_linkcost_text(dst_entry->cost, false, &lqbuffer));
329 }
330
331
332 static void
333 ipc_print_net(int ipc_connection, const union olsr_ip_addr *gw, const struct olsr_ip_prefix *net)
334 {
335   struct ipaddr_str gwbuf;
336   struct ipprefix_str netbuf;
337
338   ipc_send_fmt(ipc_connection,
339                "\"%s\" -> \"%s\"[label=\"HNA\"];\n",
340                olsr_ip_to_string(&gwbuf, gw),
341                olsr_ip_prefix_to_string(&netbuf, net));
342   ipc_send_fmt(ipc_connection,
343                "\"%s\"[shape=diamond];\n",
344                netbuf.buf);
345 }
346
347 static void
348 ipc_send(int ipc_connection, const char *data, int size)
349 {
350   if (ipc_connection != -1) {
351 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __MacOSX__ || \
352 defined _WRS_KERNEL
353 #define FLAGS 0
354 #else
355 #define FLAGS MSG_NOSIGNAL
356 #endif
357     if (send(ipc_connection, data, size, FLAGS) == -1) {
358       OLSR_PRINTF(1, "(DOT DRAW)IPC connection lost!\n");
359       CLOSESOCKET(ipc_connection);
360     }
361   }
362 }
363
364 static void
365 ipc_send_fmt(int ipc_connection, const char *format, ...)
366 {
367   if (ipc_connection != -1) {
368     char buf[4096];
369     int len;
370     va_list arg;
371     va_start(arg, format);
372     len = vsnprintf(buf, sizeof(buf), format, arg);
373     va_end(arg);
374     ipc_send(ipc_connection, buf, len);
375   }
376 }
377
378 /*
379  * Local Variables:
380  * c-basic-offset: 2
381  * indent-tabs-mode: nil
382  * End:
383  */