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