2 * The olsr.org Optimized Link-State Routing daemon(olsrd)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
34 * Visit http://www.olsr.org for more information.
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.
43 * Dynamic linked library for the olsr.org olsr daemon
46 #include <arpa/inet.h>
53 #include "scheduler.h"
54 #include "../../info/http_headers.h"
55 #include "../../info/info_types.h"
56 #include "jsoninfo_printers.h"
57 #include "olsrd_jsoninfo_helpers.h"
58 #include "olsrd_jsoninfo.h"
61 #define close(x) closesocket(x)
64 /* defines to make txtinfo and jsoninfo look alike */
65 #define PLUGIN_NAME "JSONINFO"
66 #define info_accept_ip jsoninfo_accept_ip
67 #define info_listen_ip jsoninfo_listen_ip
68 #define info_ipv6_only jsoninfo_ipv6_only
69 #ifdef JSONINFO_ALLOW_LOCALHOST
70 #define INFO_ALLOW_LOCALHOST JSONINFO_ALLOW_LOCALHOST
73 static int ipc_socket;
75 /* IPC initialization function */
76 static int plugin_ipc_init(void);
78 static void send_info(unsigned int /*send_what*/, int /*socket*/);
80 static void ipc_action(int, void *, unsigned int);
82 #define TXT_IPC_BUFSIZE 256
84 static outbuffer_t outbuffer;
86 static struct timer_entry *writetimer_entry;
88 static printer_functions_t printer_functions = { //
90 .neighbors = &ipc_print_neighbors, //
91 .links = &ipc_print_links, //
92 .routes = &ipc_print_routes, //
93 .topology = &ipc_print_topology, //
94 .hna = &ipc_print_hna, //
95 .mid = &ipc_print_mid, //
96 .gateways = &ipc_print_gateways, //
97 .sgw = &ipc_print_sgw, //
98 .version = &ipc_print_version, //
99 .olsrd_conf = &ipc_print_olsrd_conf, //
100 .interfaces = &ipc_print_interfaces, //
101 .config = &ipc_print_config, //
102 .plugins = &ipc_print_plugins //
105 static void determine_action(unsigned int *send_what, char *requ) {
106 if (strstr(requ, "/olsrd.conf"))
107 *send_what |= SIW_OLSRD_CONF;
108 else if (strstr(requ, "/all"))
109 *send_what = SIW_ALL;
111 // these are the two overarching categories
112 if (strstr(requ, "/runtime"))
113 *send_what |= SIW_RUNTIME_ALL;
114 if (strstr(requ, "/startup"))
115 *send_what |= SIW_STARTUP_ALL;
117 // these are the individual sections
118 if (strstr(requ, "/neighbors"))
119 *send_what |= SIW_NEIGHBORS;
120 if (strstr(requ, "/links"))
121 *send_what |= SIW_LINKS;
122 if (strstr(requ, "/routes"))
123 *send_what |= SIW_ROUTES;
124 if (strstr(requ, "/hna"))
125 *send_what |= SIW_HNA;
126 if (strstr(requ, "/mid"))
127 *send_what |= SIW_MID;
128 if (strstr(requ, "/topology"))
129 *send_what |= SIW_TOPOLOGY;
130 if (strstr(requ, "/gateways"))
131 *send_what |= SIW_GATEWAYS;
132 if (strstr(requ, "/interfaces"))
133 *send_what |= SIW_INTERFACES;
134 if (strstr(requ, "/2hop"))
135 *send_what |= SIW_2HOP;
136 if (strstr(requ, "/sgw"))
137 *send_what |= SIW_SGW;
140 if (strstr(requ, "/version"))
141 *send_what |= SIW_VERSION;
142 if (strstr(requ, "/config"))
143 *send_what |= SIW_CONFIG;
144 if (strstr(requ, "/plugins"))
145 *send_what |= SIW_PLUGINS;
147 /* To print out neighbours only on the Freifunk Status
148 * page the normal output is somewhat lengthy. The
149 * header parsing is sufficient for standard wget.
151 if (strstr(requ, "/neighbours"))
152 *send_what = SIW_NEIGHBORS | SIW_LINKS;
157 *Do initialization here
159 *This function is called by the my_init
160 *function in uolsrd_plugin.c
162 int olsrd_plugin_init(void) {
163 /* Initial IPC value */
165 memset(&outbuffer, 0, sizeof(outbuffer));
167 plugin_init(PLUGIN_NAME);
174 * destructor - called at unload
176 void olsr_plugin_exit(void) {
177 if (ipc_socket != -1)
181 static int plugin_ipc_init(void) {
182 union olsr_sockaddr sst;
186 /* Init ipc socket */
187 if ((ipc_socket = socket(olsr_cnf->ip_version, SOCK_STREAM, 0)) == -1) {
189 olsr_printf(1, "("PLUGIN_NAME") socket()=%s\n", strerror(errno));
193 if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof(yes)) < 0) {
195 olsr_printf(1, "("PLUGIN_NAME") setsockopt()=%s\n", strerror(errno));
199 #if (defined __FreeBSD__ || defined __FreeBSD_kernel__) && defined SO_NOSIGPIPE
200 if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *) &yes, sizeof(yes)) < 0) {
201 perror("SO_REUSEADDR failed");
204 #endif /* (defined __FreeBSD__ || defined __FreeBSD_kernel__) && defined SO_NOSIGPIPE */
205 #if defined linux && defined IPV6_V6ONLY
206 if (info_ipv6_only && olsr_cnf->ip_version == AF_INET6) {
207 if (setsockopt(ipc_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &yes, sizeof(yes)) < 0) {
208 perror("IPV6_V6ONLY failed");
212 #endif /* defined linux && defined IPV6_V6ONLY */
213 /* Bind the socket */
215 /* complete the socket structure */
216 memset(&sst, 0, sizeof(sst));
217 if (olsr_cnf->ip_version == AF_INET) {
218 sst.in4.sin_family = AF_INET;
219 addrlen = sizeof(struct sockaddr_in);
221 sst.in4.sin_len = addrlen;
222 #endif /* SIN6_LEN */
223 sst.in4.sin_addr.s_addr = info_listen_ip.v4.s_addr;
224 sst.in4.sin_port = htons(ipc_port);
226 sst.in6.sin6_family = AF_INET6;
227 addrlen = sizeof(struct sockaddr_in6);
229 sst.in6.sin6_len = addrlen;
230 #endif /* SIN6_LEN */
231 sst.in6.sin6_addr = info_listen_ip.v6;
232 sst.in6.sin6_port = htons(ipc_port);
235 /* bind the socket to the port number */
236 if (bind(ipc_socket, &sst.in, addrlen) == -1) {
238 olsr_printf(1, "("PLUGIN_NAME") bind()=%s\n", strerror(errno));
243 /* show that we are willing to listen */
244 if (listen(ipc_socket, 1) == -1) {
246 olsr_printf(1, "("PLUGIN_NAME") listen()=%s\n", strerror(errno));
251 /* Register with olsrd */
252 add_olsr_socket(ipc_socket, &ipc_action, NULL, NULL, SP_PR_READ);
255 olsr_printf(2, "("PLUGIN_NAME") listening on port %d\n", ipc_port);
261 static void ipc_action(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
262 union olsr_sockaddr pin;
264 char addr[INET6_ADDRSTRLEN];
267 unsigned int send_what = 0;
270 socklen_t addrlen = sizeof(pin);
272 if (outbuffer.count >= MAX_CLIENTS) {
276 if ((ipc_connection = accept(fd, &pin.in, &addrlen)) == -1) {
278 olsr_printf(1, "("PLUGIN_NAME") accept()=%s\n", strerror(errno));
283 tv.tv_sec = tv.tv_usec = 0;
284 if (olsr_cnf->ip_version == AF_INET) {
285 if (inet_ntop(olsr_cnf->ip_version, &pin.in4.sin_addr, addr, INET6_ADDRSTRLEN) == NULL)
287 if (!ip4equal(&pin.in4.sin_addr, &info_accept_ip.v4) && info_accept_ip.v4.s_addr != INADDR_ANY) {
288 #ifdef INFO_ALLOW_LOCALHOST
289 if (ntohl(pin.in4.sin_addr.s_addr) != INADDR_LOOPBACK) {
290 #endif /* INFO_ALLOW_LOCALHOST */
291 olsr_printf(1, "("PLUGIN_NAME") From host(%s) not allowed!\n", addr);
292 close(ipc_connection);
294 #ifdef INFO_ALLOW_LOCALHOST
296 #endif /* INFO_ALLOW_LOCALHOST */
299 if (inet_ntop(olsr_cnf->ip_version, &pin.in6.sin6_addr, addr, INET6_ADDRSTRLEN) == NULL)
301 /* Use in6addr_any (::) in olsr.conf to allow anybody. */
302 if (!ip6equal(&in6addr_any, &info_accept_ip.v6) && !ip6equal(&pin.in6.sin6_addr, &info_accept_ip.v6)) {
303 olsr_printf(1, "("PLUGIN_NAME") From host(%s) not allowed!\n", addr);
304 close(ipc_connection);
310 olsr_printf(2, "("PLUGIN_NAME") Connect from %s\n", addr);
313 /* purge read buffer to prevent blocking on linux */
315 FD_SET((unsigned int )ipc_connection, &rfds); /* Win32 needs the cast here */
316 if (0 <= select(ipc_connection + 1, &rfds, NULL, NULL, &tv)) {
318 ssize_t s = recv(ipc_connection, (void *) &requ, sizeof(requ) - 1, 0); /* Win32 needs the cast here */
320 if (s == sizeof(requ) - 1) {
321 /* input was much too long, just skip the rest */
324 while (recv(ipc_connection, (void *) &dummy, sizeof(dummy), 0) == sizeof(dummy))
330 determine_action(&send_what, requ);
337 send_info(send_what, ipc_connection);
340 static void info_write_data(void *foo __attribute__ ((unused))) {
342 int result, i, j, max;
347 for (i = 0; i < outbuffer.count; i++) {
348 /* And we cast here since we get a warning on Win32 */
349 FD_SET((unsigned int )(outbuffer.socket[i]), &set);
351 if (outbuffer.socket[i] > max) {
352 max = outbuffer.socket[i];
359 result = select(max + 1, NULL, &set, NULL, &tv);
364 for (i = 0; i < outbuffer.count; i++) {
365 if (FD_ISSET(outbuffer.socket[i], &set)) {
366 result = send(outbuffer.socket[i], outbuffer.buffer[i] + outbuffer.written[i], outbuffer.size[i] - outbuffer.written[i], 0);
368 outbuffer.written[i] += result;
371 if (result <= 0 || outbuffer.written[i] == outbuffer.size[i]) {
372 /* close this socket and cleanup*/
373 close(outbuffer.socket[i]);
374 free(outbuffer.buffer[i]);
375 outbuffer.buffer[i] = NULL;
377 for (j = i + 1; j < outbuffer.count; j++) {
378 outbuffer.buffer[j - 1] = outbuffer.buffer[j];
379 outbuffer.size[j - 1] = outbuffer.size[j];
380 outbuffer.socket[j - 1] = outbuffer.socket[j];
381 outbuffer.written[j - 1] = outbuffer.written[j];
387 if (!outbuffer.count) {
388 olsr_stop_timer(writetimer_entry);
392 static void send_info(unsigned int send_what, int the_socket) {
395 const char *content_type = (send_what & SIW_ALL) ? "application/json; charset=utf-8" : "text/plain; charset=utf-8";
396 int contentLengthPlaceholderStart = 0;
397 int headerLength = 0;
399 /* global variables for tracking when to put a comma in for JSON */
400 abuf_json_reset_entry_number_and_depth();
402 abuf_init(&abuf, 2 * 4096);
405 build_http_header(PLUGIN_NAME, HTTP_200, content_type, &abuf, &contentLengthPlaceholderStart);
406 headerLength = abuf.len;
409 // only add if normal format
410 if (send_what & SIW_ALL) {
411 abuf_json_mark_output(true, &abuf);
413 abuf_json_int(&abuf, "systemTime", time(NULL));
414 abuf_json_int(&abuf, "timeSinceStartup", now_times);
416 abuf_json_string(&abuf, "uuid", uuid);
418 if ((send_what & SIW_LINKS) && printer_functions.links)
419 (*printer_functions.links)(&abuf);
420 if ((send_what & SIW_NEIGHBORS) && printer_functions.neighbors)
421 (*printer_functions.neighbors)(&abuf, false);
422 if ((send_what & SIW_TOPOLOGY) && printer_functions.topology)
423 (*printer_functions.topology)(&abuf);
424 if ((send_what & SIW_HNA) && printer_functions.hna)
425 (*printer_functions.hna)(&abuf);
426 if ((send_what & SIW_SGW) && printer_functions.sgw)
427 (*printer_functions.sgw)(&abuf);
428 if ((send_what & SIW_MID) && printer_functions.mid)
429 (*printer_functions.mid)(&abuf);
430 if ((send_what & SIW_ROUTES) && printer_functions.routes)
431 (*printer_functions.routes)(&abuf);
432 if ((send_what & SIW_GATEWAYS) && printer_functions.gateways)
433 (*printer_functions.gateways)(&abuf);
434 if ((send_what & SIW_CONFIG) && printer_functions.config)
435 (*printer_functions.config)(&abuf);
436 if ((send_what & SIW_INTERFACES) && printer_functions.interfaces)
437 (*printer_functions.interfaces)(&abuf);
438 if ((send_what & SIW_2HOP) && printer_functions.neighbors)
439 (*printer_functions.neighbors)(&abuf, true);
440 if ((send_what & SIW_VERSION) && printer_functions.version)
441 (*printer_functions.version)(&abuf);
442 if ((send_what & SIW_PLUGINS) && printer_functions.plugins)
443 (*printer_functions.plugins)(&abuf);
445 abuf_json_mark_output(false, &abuf);
446 abuf_puts(&abuf, "\n");
447 } else if ((send_what & SIW_OLSRD_CONF) && printer_functions.olsrd_conf) {
448 /* this outputs the olsrd.conf text directly, not normal format */
449 (*printer_functions.olsrd_conf)(&abuf);
453 http_header_adjust_content_length(&abuf, contentLengthPlaceholderStart, abuf.len - headerLength);
456 /* avoid a memcpy: just move the abuf.buf pointer and clear abuf */
457 outbuffer.buffer[outbuffer.count] = abuf.buf;
458 outbuffer.size[outbuffer.count] = abuf.len;
459 outbuffer.written[outbuffer.count] = 0;
460 outbuffer.socket[outbuffer.count] = the_socket;
467 if (outbuffer.count == 1) {
468 writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &info_write_data, NULL, 0);
479 * indent-tabs-mode: nil