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.
42 #include <arpa/inet.h>
46 #include "olsrd_info.h"
48 #include "scheduler.h"
50 #include "http_headers.h"
53 #define close(x) closesocket(x)
59 int socket[MAX_CLIENTS];
60 char *buffer[MAX_CLIENTS];
61 size_t size[MAX_CLIENTS];
62 size_t written[MAX_CLIENTS];
64 } info_plugin_outbuffer_t;
66 static char sink_buffer[4096];
68 static const char * name = NULL;
70 static info_plugin_functions_t *functions = NULL;
72 static info_plugin_config_t *config = NULL;
74 static int ipc_socket = -1;
76 static info_plugin_outbuffer_t outbuffer;
78 static struct timer_entry *writetimer_entry = NULL;
80 static unsigned int determine_action(char *requ) {
81 static unsigned int SIW_ENTRIES[] = {
86 // these are the two overarching categories
90 // these are the individual sections
108 SIW_NEIGHBORS_FREIFUNK //
113 if (!functions->is_command)
116 for (i = 0; i < (sizeof(SIW_ENTRIES) / sizeof(SIW_ENTRIES[0])); ++i) {
117 unsigned int siw = SIW_ENTRIES[i];
118 if (functions->is_command(requ, siw))
125 static void write_data(void *foo __attribute__ ((unused))) {
130 if (outbuffer.count <= 0) {
131 /* exit early if there is nothing to send */
137 for (i = 0; i < outbuffer.count; i++) {
138 if (outbuffer.socket[i] < 0) {
142 /* And we cast here since we get a warning on Win32 */
143 FD_SET((unsigned int ) (outbuffer.socket[i]), &set);
145 if (outbuffer.socket[i] > max) {
146 max = outbuffer.socket[i];
153 result = select(max + 1, NULL, &set, NULL, &tv);
155 /* exit early if any of the sockets is not ready for writing */
159 for (i = 0; i < MAX_CLIENTS; i++) {
160 if (outbuffer.socket[i] < 0) {
164 result = send(outbuffer.socket[i], outbuffer.buffer[i] + outbuffer.written[i], outbuffer.size[i] - outbuffer.written[i], 0);
166 outbuffer.written[i] += result;
169 if ((result <= 0) || (outbuffer.written[i] >= outbuffer.size[i])) {
170 /* close this socket and cleanup*/
171 close(outbuffer.socket[i]);
172 outbuffer.socket[i] = -1;
173 free(outbuffer.buffer[i]);
174 outbuffer.buffer[i] = NULL;
175 outbuffer.size[i] = 0;
176 outbuffer.written[i] = 0;
182 if (!outbuffer.count) {
183 olsr_stop_timer(writetimer_entry);
187 static void send_info(unsigned int send_what, int the_socket) {
190 const char *content_type = functions->determine_mime_type ? functions->determine_mime_type(send_what) : "text/plain; charset=utf-8";
191 int contentLengthIndex = 0;
192 int headerLength = 0;
194 abuf_init(&abuf, 2 * 4096);
196 if (config->http_headers) {
197 http_header_build(name, HTTP_200, content_type, &abuf, &contentLengthIndex);
198 headerLength = abuf.len;
201 // only add if normal format
202 if (send_what & SIW_ALL) {
203 if (functions->output_start)
204 functions->output_start(&abuf);
206 if ((send_what & SIW_NEIGHBORS) && functions->neighbors)
207 functions->neighbors(&abuf);
208 if ((send_what & SIW_LINKS) && functions->links)
209 functions->links(&abuf);
210 if ((send_what & SIW_ROUTES) && functions->routes)
211 functions->routes(&abuf);
212 if ((send_what & SIW_HNA) && functions->hna)
213 functions->hna(&abuf);
214 if ((send_what & SIW_MID) && functions->mid)
215 functions->mid(&abuf);
216 if ((send_what & SIW_TOPOLOGY) && functions->topology)
217 functions->topology(&abuf);
218 if ((send_what & SIW_GATEWAYS) && functions->gateways)
219 functions->gateways(&abuf);
220 if ((send_what & SIW_INTERFACES) && functions->interfaces)
221 functions->interfaces(&abuf);
222 if ((send_what & SIW_2HOP) && functions->twohop)
223 functions->twohop(&abuf);
224 if ((send_what & SIW_SGW) && functions->sgw)
225 functions->sgw(&abuf);
227 if ((send_what & SIW_VERSION) && functions->version)
228 functions->version(&abuf);
229 if ((send_what & SIW_CONFIG) && functions->config)
230 functions->config(&abuf);
231 if ((send_what & SIW_PLUGINS) && functions->plugins)
232 functions->plugins(&abuf);
234 if (functions->output_end)
235 functions->output_end(&abuf);
236 } else if ((send_what & SIW_OLSRD_CONF) && functions->olsrd_conf) {
237 /* this outputs the olsrd.conf text directly, not normal format */
238 functions->olsrd_conf(&abuf);
241 if (config->http_headers) {
242 http_header_adjust_content_length(&abuf, contentLengthIndex, abuf.len - headerLength);
245 /* avoid a memcpy: just move the abuf.buf pointer and clear abuf */
246 outbuffer.buffer[outbuffer.count] = abuf.buf;
247 outbuffer.size[outbuffer.count] = abuf.len;
248 outbuffer.written[outbuffer.count] = 0;
249 outbuffer.socket[outbuffer.count] = the_socket;
256 if (outbuffer.count == 1) {
257 writetimer_entry = olsr_start_timer(100, 0, OLSR_TIMER_PERIODIC, &write_data, NULL, 0);
263 static void stripEOLs(char * requ) {
265 size_t index = strlen(requ);
272 while (c == '\n' || c == '\r') {
277 requ[index + 1] = '\0';
280 static void ipc_action(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
282 char addr[INET6_ADDRSTRLEN];
285 union olsr_sockaddr sock_addr;
286 socklen_t sock_addr_len = sizeof(sock_addr);
289 unsigned int send_what = 0;
290 int ipc_connection = -1;
292 if (outbuffer.count >= MAX_CLIENTS) {
296 if ((ipc_connection = accept(fd, &sock_addr.in, &sock_addr_len)) == -1) {
298 olsr_printf(1, "(%s) accept()=%s\n", name, strerror(errno));
305 olsr_cnf->ip_version, //
306 (olsr_cnf->ip_version == AF_INET) ? (void *) &sock_addr.in4.sin_addr : (void *) &sock_addr.in6.sin6_addr, //
313 tv.tv_sec = tv.tv_usec = 0;
314 if (olsr_cnf->ip_version == AF_INET) {
315 if (!ip4equal(&sock_addr.in4.sin_addr, &config->accept_ip.v4) && (config->accept_ip.v4.s_addr != INADDR_ANY) //
316 && (!config->allow_localhost || (ntohl(sock_addr.in4.sin_addr.s_addr) != INADDR_LOOPBACK))) {
318 olsr_printf(1, "(%s) From host(%s) not allowed!\n", name, addr);
320 close(ipc_connection);
324 /* Use in6addr_any (::) in olsr.conf to allow anybody. */
325 if (!ip6equal(&sock_addr.in6.sin6_addr, &config->accept_ip.v6) && !ip6equal(&config->accept_ip.v6, &in6addr_any)) {
327 olsr_printf(1, "(%s) From host(%s) not allowed!\n", name, addr);
329 close(ipc_connection);
335 olsr_printf(2, "(%s) Connect from %s\n", name, addr);
338 /* purge read buffer to prevent blocking on linux */
340 FD_SET((unsigned int ) ipc_connection, &rfds); /* Win32 needs the cast here */
341 if (0 <= select(ipc_connection + 1, &rfds, NULL, NULL, &tv)) {
343 ssize_t s = recv(ipc_connection, (void *) &requ, sizeof(requ) - 1, 0); /* Win32 needs the cast here */
345 if (s >= (ssize_t) (sizeof(requ) - 1)) {
346 /* input was much too long, just skip the rest */
347 while (recv(ipc_connection, (void *) &sink_buffer, sizeof(sink_buffer), 0) == sizeof(sink_buffer))
355 send_what = determine_action(requ);
362 send_info(send_what, ipc_connection);
365 static int plugin_ipc_init(void) {
366 union olsr_sockaddr sock_addr;
368 socklen_t sock_addr_len;
370 /* Init ipc socket */
371 if ((ipc_socket = socket(olsr_cnf->ip_version, SOCK_STREAM, 0)) == -1) {
373 olsr_printf(1, "(%s) socket()=%s\n", name, strerror(errno));
378 if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof(yes)) < 0) {
380 olsr_printf(1, "(%s) setsockopt()=%s\n", name, strerror(errno));
385 #if (defined __FreeBSD__ || defined __FreeBSD_kernel__) && defined SO_NOSIGPIPE
386 if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *) &yes, sizeof(yes)) < 0) {
387 perror("SO_NOSIGPIPE failed");
390 #endif /* (defined __FreeBSD__ || defined __FreeBSD_kernel__) && defined SO_NOSIGPIPE */
392 #if defined __linux__ && defined IPV6_V6ONLY
393 if (config->ipv6_only && (olsr_cnf->ip_version == AF_INET6) //
394 && (setsockopt(ipc_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &yes, sizeof(yes)) < 0)) {
395 perror("IPV6_V6ONLY failed");
398 #endif /* defined __linux__ && defined IPV6_V6ONLY */
400 /* complete the socket structure */
401 memset(&sock_addr, 0, sizeof(sock_addr));
402 if (olsr_cnf->ip_version == AF_INET) {
403 sock_addr.in4.sin_family = AF_INET;
404 sock_addr_len = sizeof(struct sockaddr_in);
406 sock_addr.in4.sin_len = sock_addr_len;
407 #endif /* SIN6_LEN */
408 sock_addr.in4.sin_addr.s_addr = config->listen_ip.v4.s_addr;
409 sock_addr.in4.sin_port = htons(config->ipc_port);
411 sock_addr.in6.sin6_family = AF_INET6;
412 sock_addr_len = sizeof(struct sockaddr_in6);
414 sock_addr.in6.sin6_len = sock_addr_len;
415 #endif /* SIN6_LEN */
416 sock_addr.in6.sin6_addr = config->listen_ip.v6;
417 sock_addr.in6.sin6_port = htons(config->ipc_port);
420 /* bind the socket to the port number */
421 if (bind(ipc_socket, &sock_addr.in, sock_addr_len) == -1) {
423 olsr_printf(1, "(%s) bind()=%s\n", name, strerror(errno));
428 /* show that we are willing to listen */
429 if (listen(ipc_socket, 1) == -1) {
431 olsr_printf(1, "(%s) listen()=%s\n", name, strerror(errno));
436 /* Register with olsrd */
437 add_olsr_socket(ipc_socket, &ipc_action, NULL, NULL, SP_PR_READ);
440 olsr_printf(2, "(%s) listening on port %d\n", name, config->ipc_port);
446 if (ipc_socket >= 0) {
453 int info_plugin_init(const char * plugin_name, info_plugin_functions_t *plugin_functions, info_plugin_config_t *plugin_config) {
457 assert(plugin_functions);
458 assert(plugin_config);
461 functions = plugin_functions;
462 config = plugin_config;
464 memset(&outbuffer, 0, sizeof(outbuffer));
465 for (i = 0; i < MAX_CLIENTS; ++i) {
466 outbuffer.socket[i] = -1;
471 if (functions->init) {
472 functions->init(name);
479 void info_plugin_exit(void) {
482 if (ipc_socket != -1) {
486 for (i = 0; i < MAX_CLIENTS; ++i) {
487 if (outbuffer.buffer[i]) {
488 free(outbuffer.buffer[i]);
489 outbuffer.buffer[i] = NULL;
491 outbuffer.size[i] = 0;
492 outbuffer.written[i] = 0;
493 if (outbuffer.socket[i]) {
494 close(outbuffer.socket[i]);
495 outbuffer.socket[i] = -1;