f59205a94d2d195b50439b7ae61d3ac08fe6239b
[olsrd.git] / lib / info / olsrd_info.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 #include <arpa/inet.h>
47 #include <unistd.h>
48 #include <assert.h>
49 #include <ctype.h>
50 #include <stdbool.h>
51
52 #include "olsrd_info.h"
53 #include "olsr.h"
54 #include "scheduler.h"
55 #include "ipcalc.h"
56 #include "http_headers.h"
57
58 #ifdef _WIN32
59 #define close(x) closesocket(x)
60 #endif /* _WIN32 */
61
62 #define MAX_CLIENTS 8
63
64 /*
65  * There is the problem that writing to a network socket can block,
66  * and the olsrd scheduler does not care about write events.
67  *
68  * There was a case that olsrd just froze for minutes when people used
69  * jsoninfo/txtinfo with large topologies over bad WiFi.
70  *
71  * This is the solution that was chosen at that time, unwilling to
72  * rewrite the whole scheduler:
73  * A timer was added and each time it expires each non-empty buffer
74  * in this structure will try to write data into a "non-blocking"
75  * socket until all data is sent, so that no blocking occurs.
76  */
77 typedef struct {
78   int socket[MAX_CLIENTS];
79   char *buffer[MAX_CLIENTS];
80   size_t size[MAX_CLIENTS];
81   size_t written[MAX_CLIENTS];
82   int count;
83 } info_plugin_outbuffer_t;
84
85 static const char * name;
86
87 static info_plugin_functions_t *functions = NULL;
88
89 static info_plugin_config_t *config = NULL;
90
91 static int ipc_socket = -1;
92
93 static info_plugin_outbuffer_t outbuffer;
94
95 static struct timer_entry *writetimer_entry = NULL;
96
97 static struct info_cache_t info_cache;
98
99 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
100
101 static char * skipMultipleSlashes(char * requ, size_t* len) {
102   char * r = requ;
103
104   if (!r // null pointer
105       || (len && !*len) // zero length
106       || (r[0] == '\0') // zero length
107       || (r[0] != '/') // does not start with a slash
108       || (r[1] != '/')) // does not have another slash
109   {
110     return r;
111   }
112
113   while (r[1] == '/') {
114     r++;
115     if (len) {
116       *len = *len - 1;
117     }
118   }
119   return r;
120 }
121
122 static unsigned long long SIW_ENTRIES_ALL[] = {
123 //
124     SIW_NEIGHBORS,//
125     SIW_LINKS, //
126     SIW_ROUTES, //
127     SIW_HNA, //
128     SIW_MID, //
129     SIW_TOPOLOGY, //
130     SIW_GATEWAYS, //
131     SIW_INTERFACES, //
132     SIW_2HOP, //
133     SIW_SGW, //
134     SIW_PUD_POSITION, //
135     SIW_RUNTIME_ALL,//
136     SIW_NEIGHBORS_FREIFUNK, //
137     //
138     SIW_VERSION,//
139     SIW_CONFIG, //
140     SIW_PLUGINS, //
141     SIW_STARTUP_ALL, //
142     //
143     SIW_ALL, //
144     //
145     SIW_OLSRD_CONF, //
146     //
147     SIW_NETJSON_NETWORK_ROUTES, //
148     SIW_NETJSON_NETWORK_GRAPH, //
149     SIW_NETJSON_DEVICE_CONFIGURATION, //
150     SIW_NETJSON_DEVICE_MONITORING, //
151     SIW_NETJSON_NETWORK_COLLECTION, //
152     //
153     SIW_POPROUTING_HELLO,
154     SIW_POPROUTING_TC, //
155     SIW_POPROUTING_HELLO_MULT,
156     SIW_POPROUTING_TC_MULT //
157     };
158
159 long cache_timeout_generic(info_plugin_config_t *plugin_config, unsigned long long siw) {
160   long timeout = !plugin_config ? 0 : plugin_config->cache_timeout;
161   if (timeout <= 0) {
162     return timeout;
163   }
164
165   switch (siw) {
166     case SIW_NEIGHBORS:
167     case SIW_LINKS:
168     case SIW_ROUTES:
169     case SIW_HNA:
170     case SIW_MID:
171     case SIW_TOPOLOGY:
172     case SIW_GATEWAYS:
173     case SIW_INTERFACES:
174     case SIW_2HOP:
175     case SIW_SGW:
176     case SIW_PUD_POSITION:
177
178     case SIW_NETJSON_NETWORK_ROUTES:
179     case SIW_NETJSON_NETWORK_GRAPH:
180     case SIW_NETJSON_DEVICE_CONFIGURATION:
181     case SIW_NETJSON_DEVICE_MONITORING:
182     case SIW_NETJSON_NETWORK_COLLECTION:
183       return timeout;
184
185     case SIW_VERSION:
186     case SIW_CONFIG:
187     case SIW_PLUGINS:
188       return LONG_MAX;
189
190     default:
191       /* not cached */
192       return false;
193   }
194 }
195
196 static void info_plugin_cache_init(bool init) {
197   unsigned int i;
198
199   if (!functions->cache_timeout) {
200     return;
201   }
202
203   for (i = 0; i < ARRAY_SIZE(SIW_ENTRIES_ALL); ++i) {
204     unsigned long long siw = SIW_ENTRIES_ALL[i];
205     struct info_cache_entry_t * entry = info_cache_get_entry(&info_cache, siw);
206     if (!entry) {
207       continue;
208     }
209
210     if (init) {
211       entry->timestamp = 0;
212       abuf_init(&entry->buf, 0);
213     } else {
214       abuf_free(&entry->buf);
215       entry->timestamp = 0;
216     }
217   }
218 }
219
220 static INLINE void info_plugin_cache_init_entry(struct info_cache_entry_t * entry) {
221   if (!entry->buf.buf) {
222     entry->timestamp = 0;
223     abuf_init(&entry->buf, AUTOBUFCHUNK);
224     assert(!entry->timestamp);
225     assert(!entry->buf.len);
226     assert(entry->buf.size == AUTOBUFCHUNK);
227     assert(entry->buf.buf);
228   } else {
229     assert(entry->timestamp >= 0);
230     assert(entry->buf.len >= 0);
231     assert(entry->buf.size >= AUTOBUFCHUNK);
232     assert(entry->buf.buf);
233   }
234 }
235
236 static unsigned int determine_single_action(char *requ) {
237   unsigned int i;
238   unsigned long long siw_mask = !functions->supported_commands_mask ? SIW_EVERYTHING : functions->supported_commands_mask();
239
240   if (!functions->is_command || !siw_mask)
241     return 0;
242
243   for (i = 0; i < ARRAY_SIZE(SIW_ENTRIES_ALL); ++i) {
244     unsigned long long siw = SIW_ENTRIES_ALL[i];
245     if ((siw & siw_mask) && functions->is_command(requ, siw))
246       return siw;
247   }
248
249   return 0;
250 }
251
252 static unsigned int determine_action(char *requ) {
253   if (!functions->is_command) {
254     return 0;
255   }
256
257   if (!requ || (requ[0] == '\0')) {
258     /* no more text */
259     return 0;
260   }
261
262   /* requ is guaranteed to be at least 1 character long */
263
264   if (!functions->supportsCompositeCommands) {
265     /* no support for composite commands */
266     return determine_single_action(requ);
267   }
268
269   /* composite commands */
270
271   {
272     unsigned int action = 0;
273
274     char * requestSegment = requ;
275     while (requestSegment) {
276       requestSegment = skipMultipleSlashes(requestSegment, NULL);
277       if (requestSegment[0] == '\0') {
278         /* there is no more text */
279         requestSegment = NULL;
280         continue;
281       }
282
283       /* there is more text */
284
285       {
286         unsigned int r = 0;
287         char * requestSegmentTail = strchr(&requestSegment[1], '/');
288
289         if (!requestSegmentTail) {
290           /* there isn't another slash, process everything that is left */
291           r = determine_single_action(requestSegment);
292         } else {
293           /* there is another slash, process everything before the slash */
294           char savedCharacter = *requestSegmentTail;
295           *requestSegmentTail = '\0';
296           r = determine_single_action(requestSegment);
297           *requestSegmentTail = savedCharacter;
298         }
299
300         if (!r) {
301           /* not found */
302           return 0;
303         }
304
305         action |= r;
306
307         /* process everything that is left in the next iteration */
308         requestSegment = requestSegmentTail;
309       }
310     }
311
312     return action;
313   }
314 }
315
316 static void send_status_no_retries(const char * req, bool add_headers, int the_socket, unsigned int status) {
317   struct autobuf abuf;
318
319   abuf_init(&abuf, AUTOBUFCHUNK);
320
321   if (add_headers) {
322     http_header_build_result(status, &abuf);
323   } else if (status != INFO_HTTP_OK) {
324     if (functions->output_error) {
325       functions->output_error(&abuf, status, req, add_headers);
326     } else if (status == INFO_HTTP_NOCONTENT) {
327       /* wget can't handle output of zero length */
328       abuf_puts(&abuf, "\n");
329     }
330   }
331
332   (void) send(the_socket, abuf.buf, abuf.len,
333 #ifdef _WIN32
334     0
335 #else
336     MSG_DONTWAIT
337 #endif
338   );
339   close(the_socket);
340   abuf_free(&abuf);
341 }
342
343 static void write_data(void *unused __attribute__((unused))) {
344   fd_set set;
345   int result, i, max;
346   struct timeval tv;
347
348   if (outbuffer.count <= 0) {
349     /* exit early if there is nothing to send */
350     return;
351   }
352
353   FD_ZERO(&set);
354   max = 0;
355   for (i = 0; i < MAX_CLIENTS; i++) {
356     if (outbuffer.socket[i] < 0) {
357       continue;
358     }
359
360     /* And we cast here since we get a warning on Win32 */
361     FD_SET((unsigned int ) (outbuffer.socket[i]), &set);
362
363     if (outbuffer.socket[i] > max) {
364       max = outbuffer.socket[i];
365     }
366   }
367
368   tv.tv_sec = 0;
369   tv.tv_usec = 0;
370
371   result = select(max + 1, NULL, &set, NULL, &tv);
372   if (result <= 0) {
373     /* exit early if any of the sockets is not ready for writing */
374     return;
375   }
376
377   for (i = 0; i < MAX_CLIENTS; i++) {
378     if (outbuffer.socket[i] < 0) {
379       continue;
380     }
381
382     result = send(outbuffer.socket[i], outbuffer.buffer[i] + outbuffer.written[i], outbuffer.size[i] - outbuffer.written[i],
383 #ifdef _WIN32
384     0
385 #else
386     MSG_DONTWAIT
387 #endif
388     );
389     if (result > 0) {
390       outbuffer.written[i] += result;
391     }
392
393 #if EWOULDBLOCK == EAGAIN
394     if ((result < 0) && (errno == EAGAIN)) {
395 #else
396     if ((result < 0) && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
397 #endif
398       continue;
399     }
400
401     if ((result < 0) || (outbuffer.written[i] >= outbuffer.size[i])) {
402       /* close this socket and cleanup*/
403       close(outbuffer.socket[i]);
404       outbuffer.socket[i] = -1;
405       free(outbuffer.buffer[i]);
406       outbuffer.buffer[i] = NULL;
407       outbuffer.size[i] = 0;
408       outbuffer.written[i] = 0;
409
410       outbuffer.count--;
411     }
412   }
413
414   if (!outbuffer.count) {
415     olsr_stop_timer(writetimer_entry);
416     writetimer_entry = NULL;
417   }
418 }
419
420 typedef struct {
421   unsigned long long siw;
422   printer_generic func;
423 } SiwLookupTableEntry;
424
425 static void send_info_from_table(struct autobuf *abuf, unsigned int send_what, SiwLookupTableEntry *funcs, unsigned int funcsSize, unsigned int *outputLength) {
426   unsigned int i;
427   unsigned int preLength;
428   unsigned int what = send_what;
429   cache_timeout_func cache_timeout_f = functions->cache_timeout;
430
431   if (functions->output_start) {
432     functions->output_start(abuf);
433   }
434
435   preLength = abuf->len;
436
437   for (i = 0; (i < funcsSize) && what; i++) {
438     unsigned long long siw = funcs[i].siw;
439     if (what & siw) {
440       printer_generic func = funcs[i].func;
441       if (func) {
442         long cache_timeout = 0;
443         struct info_cache_entry_t *cache_entry = NULL;
444
445         if (cache_timeout_f) {
446           cache_timeout = cache_timeout_f(config, siw);
447           cache_entry = (cache_timeout <= 0) ? NULL : info_cache_get_entry(&info_cache, siw);
448         }
449
450         if (!cache_entry) {
451             func(abuf);
452         } else {
453           long long now;
454           long long age;
455
456           info_plugin_cache_init_entry(cache_entry);
457
458           now = olsr_times();
459           age = llabs(now - cache_entry->timestamp);
460           if (!cache_entry->timestamp || (age >= cache_timeout)) {
461             /* cache is never used before or cache is too old */
462             cache_entry->buf.buf[0] = '\0';
463             cache_entry->buf.len = 0;
464             cache_entry->timestamp = now;
465             func(&cache_entry->buf);
466           }
467
468           abuf_concat(abuf, &cache_entry->buf);
469         }
470       }
471     }
472     what &= ~siw;
473   }
474
475   *outputLength = abuf->len - preLength;
476
477   if (functions->output_end) {
478     functions->output_end(abuf);
479   }
480 }
481
482 static void send_info(const char * req, bool add_headers, unsigned int send_what, int the_socket, unsigned int status) {
483   struct autobuf abuf;
484   unsigned int outputLength = 0;
485   unsigned int send_index = 0;
486   bool first_reply = false;
487
488   const char *content_type = functions->determine_mime_type ? functions->determine_mime_type(send_what) : "text/plain; charset=utf-8";
489   int contentLengthIndex = 0;
490   int headerLength = 0;
491
492   assert(outbuffer.count <= MAX_CLIENTS);
493
494   abuf_init(&abuf, AUTOBUFCHUNK);
495
496   if (add_headers) {
497     http_header_build(name, status, content_type, &abuf, &contentLengthIndex);
498     headerLength = abuf.len;
499   }
500
501   if (status == INFO_HTTP_OK) {
502     /* OK */
503
504     // only add if normal format
505     if (send_what & SIW_ALL) {
506       SiwLookupTableEntry funcs[] = {
507         { SIW_NEIGHBORS   , functions->neighbors   }, //
508         { SIW_LINKS       , functions->links       }, //
509         { SIW_ROUTES      , functions->routes      }, //
510         { SIW_HNA         , functions->hna         }, //
511         { SIW_MID         , functions->mid         }, //
512         { SIW_TOPOLOGY    , functions->topology    }, //
513         { SIW_GATEWAYS    , functions->gateways    }, //
514         { SIW_INTERFACES  , functions->interfaces  }, //
515         { SIW_2HOP        , functions->twohop      }, //
516         { SIW_SGW         , functions->sgw         }, //
517         { SIW_PUD_POSITION, functions->pudPosition }, //
518         //
519         { SIW_VERSION     , functions->version     }, //
520         { SIW_CONFIG      , functions->config      }, //
521         { SIW_PLUGINS     , functions->plugins     } //
522       };
523
524       send_info_from_table(&abuf, send_what, funcs, ARRAY_SIZE(funcs), &outputLength);
525     } else if (send_what & SIW_NETJSON) {
526       SiwLookupTableEntry funcs[] = {
527         { SIW_NETJSON_NETWORK_ROUTES      , functions->networkRoutes      }, //
528         { SIW_NETJSON_NETWORK_GRAPH       , functions->networkGraph       }, //
529         { SIW_NETJSON_DEVICE_CONFIGURATION, functions->deviceConfiguration}, //
530         { SIW_NETJSON_DEVICE_MONITORING   , functions->deviceMonitoring   }, //
531         { SIW_NETJSON_NETWORK_COLLECTION  , functions->networkCollection  } //
532       };
533
534       send_info_from_table(&abuf, send_what, funcs, ARRAY_SIZE(funcs), &outputLength);
535     } else if(send_what & SIW_POPROUTING){
536       SiwLookupTableEntry funcs[] = {
537         { SIW_POPROUTING_TC               , functions->tcTimer           }, //
538         { SIW_POPROUTING_HELLO            , functions->helloTimer        }, //
539         { SIW_POPROUTING_TC_MULT          , functions->tcTimerMult       }, //
540         { SIW_POPROUTING_HELLO_MULT       , functions->helloTimerMult    } //
541       };
542       
543       send_info_from_table(&abuf, send_what, funcs, ARRAY_SIZE(funcs), &outputLength);
544     } else if ((send_what & SIW_OLSRD_CONF) && functions->olsrd_conf) {
545       /* this outputs the olsrd.conf text directly, not normal format */
546       unsigned int preLength = abuf.len;
547       functions->olsrd_conf(&abuf);
548       outputLength = abuf.len - preLength;
549     }
550
551     if (!abuf.len || !outputLength) {
552       status = INFO_HTTP_NOCONTENT;
553       abuf.buf[0] = '\0';
554       abuf.len = 0;
555       if (add_headers) {
556         http_header_build(name, status, content_type, &abuf, &contentLengthIndex);
557         headerLength = abuf.len;
558       }
559     }
560   }
561
562   if (status != INFO_HTTP_OK) {
563     if (functions->output_error) {
564       functions->output_error(&abuf, status, req, add_headers);
565     } else if (status == INFO_HTTP_NOCONTENT) {
566       /* wget can't handle output of zero length */
567       abuf_puts(&abuf, "\n");
568     }
569   }
570
571   if (add_headers) {
572     http_header_adjust_content_length(&abuf, contentLengthIndex, abuf.len - headerLength);
573   }
574
575   /*
576    * Determine the last available outbuffer slot.
577    * Search from the end towards the start to avoid starvation of
578    * older replies that are still in-flight (since the send function
579    * iterates from the start towards the end).
580    */
581   send_index = MAX_CLIENTS;
582   while (send_index) {
583     send_index--;
584     if (!outbuffer.buffer[send_index]) {
585       break;
586     }
587   }
588   assert(send_index < MAX_CLIENTS);
589   assert(!outbuffer.buffer[send_index]);
590
591   /* avoid a memcpy: just move the abuf.buf pointer and clear abuf */
592   outbuffer.buffer[send_index] = abuf.buf;
593   outbuffer.size[send_index] = abuf.len;
594   outbuffer.written[send_index] = 0;
595   outbuffer.socket[send_index] = the_socket;
596   abuf.buf = NULL;
597   abuf.len = 0;
598   abuf.size = 0;
599
600   first_reply = !outbuffer.count;
601
602   outbuffer.count++;
603
604   write_data(NULL);
605
606   if (first_reply && outbuffer.buffer[send_index]) {
607     writetimer_entry = olsr_start_timer(10, 0, OLSR_TIMER_PERIODIC, &write_data, NULL, 0);
608   }
609 }
610
611 static char * skipLeadingWhitespace(char * requ, size_t *len) {
612   if (!requ || !len || !*len) {
613     return requ;
614   }
615
616   while (isspace(*requ) && (*requ != '\0')) {
617     *len = *len - 1;
618     requ++;
619   }
620   return requ;
621 }
622
623 static char * stripTrailingWhitespace(char * requ, size_t *len) {
624   if (!requ || !len || !*len) {
625     return requ;
626   }
627
628   while (isspace(requ[*len - 1]) && (requ[*len - 1] != '\0')) {
629     *len = *len - 1;
630     requ[*len] = '\0';
631   }
632   return requ;
633 }
634
635 static char * stripTrailingSlashes(char * requ, size_t *len) {
636   if (!requ || !len || !*len) {
637     return requ;
638   }
639
640   while ((requ[*len - 1] == '/') && (requ[*len - 1] != '\0')) {
641     *len = *len - 1;
642     requ[*len] = '\0';
643   }
644   return requ;
645 }
646
647 static char * cutAtFirstEOL(char * requ, size_t *len) {
648   char * s = requ;
649   size_t l = 0;
650
651   if (!requ || !len || !*len) {
652     return requ;
653   }
654
655   while (!((*s == '\n') || (*s == '\r')) && (*s != '\0')) {
656     s++;
657     l++;
658   }
659   if ((*s == '\n') || (*s == '\r')) {
660     *s = '\0';
661   }
662   *len = l;
663   return requ;
664 }
665
666 static char * parseRequest(char * req, size_t *len, bool *add_headers) {
667   if (!req || !len || !*len) {
668     return req;
669   }
670
671   /* HTTP request: GET whitespace URI whitespace HTTP/1.[01] */
672   if (*len < (3 + 1 + 1 + 1 + 8) //
673       || strncasecmp(req, "GET", 3) //
674       || !isspace(req[3]) //
675       || !isspace(req[*len - 9]) //
676       || strncasecmp(&req[*len - 8], "HTTP/1.", 7) //
677       || ((req[*len - 1] != '1') && (req[*len - 1] != '0'))) {
678     /* too short or does not start with 'GET ' nor ends with ' HTTP/1.[01]'*/
679     *add_headers = false;
680     return req;
681   }
682
683   /* skip 'GET ' */
684   *len = *len - 4;
685   req = &req[4];
686
687   /* strip ' HTTP/1.[01]' */
688   *len = *len - 9;
689   req[*len] = '\0';
690
691   *add_headers = true;
692
693   return req;
694 }
695
696 static char * checkCommandPrefixes(char * req, size_t *len, bool *add_headers) {
697   size_t l;
698
699   if (!req || !len || !*len || !add_headers) {
700     return req;
701   }
702
703   l = *len;
704
705   /* '/http/...' */
706
707   if ((l >= (SIW_PREFIX_HTTP_LEN + 1)) && !strncasecmp(req, SIW_PREFIX_HTTP "/", SIW_PREFIX_HTTP_LEN + 1)) {
708     *len = l - SIW_PREFIX_HTTP_LEN;
709     req = &req[SIW_PREFIX_HTTP_LEN];
710     *add_headers = true;
711     return req;
712   }
713
714   /* '/http' */
715
716   if ((l == SIW_PREFIX_HTTP_LEN) && !strcasecmp(req, SIW_PREFIX_HTTP)) {
717     *len = 0;
718     *req = '\0';
719     *add_headers = true;
720     return req;
721   }
722
723   /* '/plain/...' */
724
725   if ((l >= (SIW_PREFIX_PLAIN_LEN + 1)) && !strncasecmp(req, SIW_PREFIX_PLAIN "/", SIW_PREFIX_PLAIN_LEN + 1)) {
726     *len = l - SIW_PREFIX_PLAIN_LEN;
727     req = &req[SIW_PREFIX_PLAIN_LEN];
728     *add_headers = false;
729     return req;
730   }
731
732   /* '/plain' */
733
734   if ((l == SIW_PREFIX_PLAIN_LEN) && !strcasecmp(req, SIW_PREFIX_PLAIN)) {
735     *len = 0;
736     *req = '\0';
737     *add_headers = false;
738     return req;
739   }
740
741   /* no prefixes */
742
743   return req;
744 }
745
746 static void drain_request(int ipc_connection) {
747   static char drain_buffer[AUTOBUFCHUNK];
748
749   ssize_t r;
750   do {
751 #ifdef _WIN32
752     r = recv(ipc_connection, (void *) &drain_buffer, sizeof(drain_buffer), MSG_PEEK);
753     if (r > 0) {
754       r = recv(ipc_connection, (void *) &drain_buffer, sizeof(drain_buffer), 0);
755     }
756 #else
757     r = recv(ipc_connection, (void *) &drain_buffer, sizeof(drain_buffer), MSG_DONTWAIT);
758 #endif
759   } while ((r > 0) && (r <= (ssize_t) sizeof(drain_buffer)));
760 }
761
762 static void ipc_action(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
763 #ifndef NODEBUG
764   char addr[INET6_ADDRSTRLEN];
765 #endif /* NODEBUG */
766
767   int ipc_connection = -1;
768   union olsr_sockaddr sock_addr;
769   socklen_t sock_addr_len = sizeof(sock_addr);
770   bool hostDenied = false;
771   struct timeval timeout;
772   fd_set read_fds;
773   char req_buffer[1024]; /* maximum size is the size of an IP packet */
774   char * req = req_buffer;
775   ssize_t rx_count = 0;
776   unsigned int send_what = 0;
777   unsigned int http_status = INFO_HTTP_OK;
778   bool add_headers = config->http_headers;
779   int r = 0;
780
781   *req = '\0';
782
783   if ((ipc_connection = accept(fd, &sock_addr.in, &sock_addr_len)) < 0) {
784 #ifndef NODEBUG
785     olsr_printf(1, "(%s) accept()=%s\n", name, strerror(errno));
786 #endif /* NODEBUG */
787     /* the caller will retry later */
788     return;
789   }
790
791 #ifdef _WIN32
792   /* set the connection socket to non-blocking */
793   {
794     u_long iMode = 1;
795     ioctlsocket(ipc_connection, FIONBIO, &iMode);
796   }
797 #endif
798
799   /* Wait at most this much time for the request to arrive on the connection */
800   timeout.tv_sec = (outbuffer.count >= MAX_CLIENTS) ? 0 : config->request_timeout_sec;
801   timeout.tv_usec = (outbuffer.count >= MAX_CLIENTS) ? 0 : config->request_timeout_usec;
802
803   FD_ZERO(&read_fds);
804 #ifndef _WIN32
805   FD_SET(ipc_connection, &read_fds);
806 #else
807   FD_SET((unsigned int ) ipc_connection, &read_fds); /* Win32 needs the cast here */
808 #endif
809
810   /* On success, select() and pselect() return the number of file descriptors
811    * contained in the three returned descriptor sets (that is, the total number
812    * of bits that are set in readfds, writefds, exceptfds) which may be zero if
813    * the timeout expires before anything interesting happens. On error, -1 is
814    * returned, and errno is set to indicate the error; the file descriptor sets
815    * are unmodified, and timeout becomes undefined.
816    */
817
818   r = select(ipc_connection + 1, &read_fds, NULL, NULL, &timeout);
819   if (r < 0) {
820     /* ipc_connection is not ready for reading */
821 #ifndef NODEBUG
822     olsr_printf(1, "(%s) select()=%s\n", name, strerror(errno));
823 #endif /* NODEBUG */
824     drain_request(ipc_connection);
825     if (outbuffer.count >= MAX_CLIENTS) {
826       send_status_no_retries(req, add_headers, ipc_connection, INFO_HTTP_INTERNAL_SERVER_ERROR);
827     } else {
828       send_info(req, add_headers, send_what, ipc_connection, INFO_HTTP_INTERNAL_SERVER_ERROR);
829     }
830     return;
831   }
832
833   if (!r) {
834     /* ipc_connection is not ready for reading within the timeout */
835 #ifndef NODEBUG
836     olsr_printf(1, "(%s) select() timeout\n", name);
837 #endif /* NODEBUG */
838     drain_request(ipc_connection);
839     if (outbuffer.count >= MAX_CLIENTS) {
840       send_status_no_retries(req, add_headers, ipc_connection, INFO_HTTP_REQUEST_TIMEOUT);
841     } else {
842       send_info(req, add_headers, send_what, ipc_connection, INFO_HTTP_REQUEST_TIMEOUT);
843     }
844     return;
845   }
846
847 #ifdef _WIN32
848   rx_count = recv(ipc_connection, req, sizeof(req_buffer), MSG_PEEK);
849   if (rx_count > 0) {
850     rx_count = recv(ipc_connection, req, sizeof(req_buffer), 0);
851   }
852 #else
853   rx_count = recv(ipc_connection, req, sizeof(req_buffer), MSG_DONTWAIT);
854 #endif
855
856   /* Upon successful completion, recv() shall return the length of the message
857    * in bytes. If no messages are available to be received and the peer has
858    * performed an orderly shutdown, recv() shall return 0. Otherwise, −1 shall
859    * be returned and errno set to indicate the error.
860    */
861
862   /* ensure proper request termination */
863   if (rx_count <= 0) {
864     *req = '\0';
865   } else if (rx_count < (ssize_t) sizeof(req_buffer)) {
866     req[rx_count] = '\0';
867   } else {
868     req[sizeof(req_buffer) - 1] = '\0';
869   }
870
871   /* sanitise the request */
872   if (rx_count > 0) {
873     req = cutAtFirstEOL(req, (size_t*) &rx_count);
874
875     req = stripTrailingWhitespace(req, (size_t*) &rx_count);
876     req = skipLeadingWhitespace(req, (size_t*) &rx_count);
877
878     /* detect http requests */
879     req = parseRequest(req, (size_t*) &rx_count, &add_headers);
880
881     req = stripTrailingWhitespace(req, (size_t*) &rx_count);
882     req = stripTrailingSlashes(req, (size_t*) &rx_count);
883     req = skipLeadingWhitespace(req, (size_t*) &rx_count);
884     req = skipMultipleSlashes(req, (size_t*) &rx_count);
885
886     req = checkCommandPrefixes(req, (size_t*) &rx_count, &add_headers);
887
888     req = skipMultipleSlashes(req, (size_t*) &rx_count);
889   }
890
891   if (outbuffer.count >= MAX_CLIENTS) {
892     /* limit the number of replies that are in-flight */
893     drain_request(ipc_connection);
894     send_status_no_retries(req, add_headers, ipc_connection, INFO_HTTP_SERVICE_UNAVAILABLE);
895     return;
896   }
897
898   if (olsr_cnf->ip_version == AF_INET) {
899     hostDenied = //
900         (ntohl(config->accept_ip.v4.s_addr) != INADDR_ANY) //
901         && !ip4equal(&sock_addr.in4.sin_addr, &config->accept_ip.v4) //
902         && (!config->allow_localhost //
903             || (ntohl(sock_addr.in4.sin_addr.s_addr) != INADDR_LOOPBACK));
904   } else {
905     hostDenied = //
906         !ip6equal(&config->accept_ip.v6, &in6addr_any) //
907         && !ip6equal(&sock_addr.in6.sin6_addr, &config->accept_ip.v6) //
908         && (!config->allow_localhost //
909             || !ip6equal(&config->accept_ip.v6, &in6addr_loopback));
910   }
911
912 #ifndef NODEBUG
913   if (!inet_ntop( //
914       olsr_cnf->ip_version, //
915       (olsr_cnf->ip_version == AF_INET) ? (void *) &sock_addr.in4.sin_addr : (void *) &sock_addr.in6.sin6_addr, //
916       addr, //
917       sizeof(addr))) {
918     addr[0] = '\0';
919   }
920 #endif /* NODEBUG */
921
922   if (hostDenied) {
923 #ifndef NODEBUG
924     olsr_printf(1, "(%s) Connect from host %s is not allowed!\n", name, addr);
925 #endif /* NODEBUG */
926     drain_request(ipc_connection);
927     send_info(req, add_headers, send_what, ipc_connection, INFO_HTTP_FORBIDDEN);
928     return;
929   }
930
931 #ifndef NODEBUG
932   olsr_printf(1, "(%s) Connect from host %s is allowed\n", name, addr);
933 #endif /* NODEBUG */
934
935   if (rx_count < 0) {
936 #ifndef NODEBUG
937     olsr_printf(1, "(%s) rx_count < 0\n", name);
938 #endif /* NODEBUG */
939     drain_request(ipc_connection);
940     send_info(req, add_headers, send_what, ipc_connection, INFO_HTTP_INTERNAL_SERVER_ERROR);
941     return;
942   }
943
944   /* rx_count >= 0 */
945
946   if (!rx_count) {
947 #ifndef NODEBUG
948     olsr_printf(1, "(%s) rx_count == 0\n", name);
949 #endif /* NODEBUG */
950     drain_request(ipc_connection);
951     send_info(req, add_headers, SIW_EVERYTHING, ipc_connection, INFO_HTTP_OK);
952     return;
953   }
954
955   /* rx_count > 0 */
956
957   if (rx_count >= (ssize_t) sizeof(req_buffer)) {
958 #ifndef NODEBUG
959     olsr_printf(1, "(%s) rx_count > %ld\n", name, (long int) sizeof(req_buffer));
960 #endif /* NODEBUG */
961
962     /* input was much too long: read until the end for graceful connection termination
963      * because wget can't handle the premature connection termination that is allowed
964      * by the INFO_HTTP_REQUEST_ENTITY_TOO_LARGE HTTP status code
965      */
966     drain_request(ipc_connection);
967     send_info(req, add_headers, send_what, ipc_connection, INFO_HTTP_REQUEST_ENTITY_TOO_LARGE);
968     return;
969   }
970
971   /* 0 < rx_count < sizeof(requ) */
972
973   if (!rx_count //
974       || ((rx_count == 1) && (*req == '/'))) {
975     /* empty or '/' */
976     send_what = SIW_EVERYTHING;
977   } else {
978     send_what = determine_action(req);
979   }
980
981   if (!send_what) {
982     http_status = INFO_HTTP_NOTFOUND;
983   }
984
985   send_info(req, add_headers, send_what, ipc_connection, http_status);
986 }
987
988 static int plugin_ipc_init(void) {
989   union olsr_sockaddr sock_addr;
990   uint32_t yes = 1;
991   socklen_t sock_addr_len;
992
993   /* Init ipc socket */
994   if ((ipc_socket = socket(olsr_cnf->ip_version, SOCK_STREAM, 0)) == -1) {
995 #ifndef NODEBUG
996     olsr_printf(1, "(%s) socket()=%s\n", name, strerror(errno));
997 #endif /* NODEBUG */
998     goto error_out;
999   }
1000
1001   if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof(yes)) < 0) {
1002 #ifndef NODEBUG
1003     olsr_printf(1, "(%s) setsockopt()=%s\n", name, strerror(errno));
1004 #endif /* NODEBUG */
1005     goto error_out;
1006   }
1007
1008 #if (defined __FreeBSD__ || defined __FreeBSD_kernel__) && defined SO_NOSIGPIPE
1009   if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *) &yes, sizeof(yes)) < 0) {
1010     perror("SO_NOSIGPIPE failed");
1011     goto error_out;
1012   }
1013 #endif /* (defined __FreeBSD__ || defined __FreeBSD_kernel__) && defined SO_NOSIGPIPE */
1014
1015 #if defined __linux__ && defined IPV6_V6ONLY
1016   if (config->ipv6_only && (olsr_cnf->ip_version == AF_INET6) //
1017       && (setsockopt(ipc_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &yes, sizeof(yes)) < 0)) {
1018     perror("IPV6_V6ONLY failed");
1019     goto error_out;
1020   }
1021 #endif /* defined __linux__ && defined IPV6_V6ONLY */
1022
1023   /* complete the socket structure */
1024   memset(&sock_addr, 0, sizeof(sock_addr));
1025   if (olsr_cnf->ip_version == AF_INET) {
1026     sock_addr.in4.sin_family = AF_INET;
1027     sock_addr_len = sizeof(struct sockaddr_in);
1028 #ifdef SIN6_LEN
1029     sock_addr.in4.sin_len = sock_addr_len;
1030 #endif /* SIN6_LEN */
1031     sock_addr.in4.sin_addr.s_addr = config->listen_ip.v4.s_addr;
1032     sock_addr.in4.sin_port = htons(config->ipc_port);
1033   } else {
1034     sock_addr.in6.sin6_family = AF_INET6;
1035     sock_addr_len = sizeof(struct sockaddr_in6);
1036 #ifdef SIN6_LEN
1037     sock_addr.in6.sin6_len = sock_addr_len;
1038 #endif /* SIN6_LEN */
1039     sock_addr.in6.sin6_addr = config->listen_ip.v6;
1040     sock_addr.in6.sin6_port = htons(config->ipc_port);
1041   }
1042
1043   /* bind the socket to the port number */
1044   if (bind(ipc_socket, &sock_addr.in, sock_addr_len) == -1) {
1045 #ifndef NODEBUG
1046     olsr_printf(1, "(%s) bind()=%s\n", name, strerror(errno));
1047 #endif /* NODEBUG */
1048     goto error_out;
1049   }
1050
1051   /* show that we are willing to listen */
1052   if (listen(ipc_socket, 1) == -1) {
1053 #ifndef NODEBUG
1054     olsr_printf(1, "(%s) listen()=%s\n", name, strerror(errno));
1055 #endif /* NODEBUG */
1056     goto error_out;
1057   }
1058
1059   /* Register with olsrd */
1060   add_olsr_socket(ipc_socket, &ipc_action, NULL, NULL, SP_PR_READ);
1061
1062 #ifndef NODEBUG
1063   olsr_printf(1, "(%s) listening on port %d\n", name, config->ipc_port);
1064 #endif /* NODEBUG */
1065
1066   return 1;
1067
1068   error_out: //
1069   if (ipc_socket >= 0) {
1070     close(ipc_socket);
1071     ipc_socket = -1;
1072   }
1073   return 0;
1074 }
1075
1076 static void info_sanitise_config(info_plugin_config_t *cfg) {
1077   if (cfg->ipc_port < 1) {
1078     cfg->ipc_port = 1;
1079   }
1080
1081   if (cfg->request_timeout < 0) {
1082     cfg->request_timeout = 0;
1083   }
1084
1085   cfg->request_timeout_sec = cfg->request_timeout / 1000;
1086   cfg->request_timeout_usec = (cfg->request_timeout % 1000) * 1000;
1087 }
1088
1089 int info_plugin_init(const char * plugin_name, info_plugin_functions_t *plugin_functions, info_plugin_config_t *plugin_config) {
1090   int i;
1091
1092   assert(plugin_name);
1093   assert(plugin_functions);
1094   assert(plugin_config);
1095
1096   name = plugin_name;
1097   functions = plugin_functions;
1098   config = plugin_config;
1099
1100   info_sanitise_config(config);
1101
1102   memset(&outbuffer, 0, sizeof(outbuffer));
1103   for (i = 0; i < MAX_CLIENTS; ++i) {
1104     outbuffer.socket[i] = -1;
1105   }
1106
1107   ipc_socket = -1;
1108
1109   if (functions->init) {
1110     functions->init(name);
1111   }
1112
1113   info_plugin_cache_init(true);
1114
1115   return plugin_ipc_init();
1116 }
1117
1118 void info_plugin_exit(void) {
1119   int i;
1120
1121   if (ipc_socket != -1) {
1122     close(ipc_socket);
1123     ipc_socket = -1;
1124   }
1125   for (i = 0; i < MAX_CLIENTS; ++i) {
1126     if (outbuffer.buffer[i]) {
1127       free(outbuffer.buffer[i]);
1128       outbuffer.buffer[i] = NULL;
1129     }
1130     outbuffer.size[i] = 0;
1131     outbuffer.written[i] = 0;
1132     if (outbuffer.socket[i]) {
1133       close(outbuffer.socket[i]);
1134       outbuffer.socket[i] = -1;
1135     }
1136   }
1137   outbuffer.count = 0;
1138
1139   info_plugin_cache_init(false);
1140 }