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