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
skipMultipleSlashes(char * requ,size_t * len)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
cache_timeout_generic(info_plugin_config_t * plugin_config,unsigned long long siw)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
info_plugin_cache_init(bool init)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
info_plugin_cache_init_entry(struct info_cache_entry_t * entry)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
determine_single_action(char * requ)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
determine_action(char * requ)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
send_status_no_retries(const char * req,bool add_headers,int the_socket,unsigned int status)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
write_data(void * unused)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 }
1141