4feb46eb0f039dcd9dc5051a011a54a828464aa9
[olsrd.git] / lib / httpinfo / src / olsrd_httpinfo.c
1 /*
2  * HTTP Info plugin for the olsr.org OLSR daemon
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright 
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright 
13  *   notice, this list of conditions and the following disclaimer in 
14  *   the documentation and/or other materials provided with the 
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  * $Id: olsrd_httpinfo.c,v 1.19 2004/12/19 20:21:24 kattemat Exp $
40  */
41
42 /*
43  * Dynamic linked library for the olsr.org olsr daemon
44  */
45
46 #include "olsrd_httpinfo.h"
47 #include "olsr_cfg.h"
48 #include <stdio.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <errno.h>
53
54 #define MAX_CLIENTS 3
55
56 #define MAX_HTTPREQ_SIZE 1024 * 10
57
58 #define DEFAULT_TCP_PORT 8080
59
60 #define HTML_BUFSIZE 1024*50
61
62 #define FRAMEWIDTH 800
63
64 static int
65 get_http_socket(int);
66
67 void
68 parse_http_request(int);
69
70 int
71 build_http_header(http_header_type, olsr_u32_t, char *, olsr_u32_t);
72
73 static int
74 build_frame(char *, char *, int, char *, olsr_u32_t, int(*frame_body_cb)(char *, olsr_u32_t));
75
76 int
77 build_routes_body(char *, olsr_u32_t);
78
79 int
80 build_status_body(char *, olsr_u32_t);
81
82 int
83 build_neigh_body(char *, olsr_u32_t);
84
85 int
86 build_topo_body(char *, olsr_u32_t);
87
88 int
89 build_hna_body(char *, olsr_u32_t);
90
91 int
92 build_mid_body(char *, olsr_u32_t);
93
94 char *
95 sockaddr_to_string(struct sockaddr *);
96
97 static struct timeval start_time;
98 static int client_sockets[MAX_CLIENTS];
99 static int curr_clients;
100 static int http_socket;
101
102 /**
103  *Do initialization here
104  *
105  *This function is called by the my_init
106  *function in uolsrd_plugin.c
107  */
108 int
109 olsr_plugin_init()
110 {
111   /* Get start time */
112   gettimeofday(&start_time, NULL);
113
114   curr_clients = 0;
115   /* set up HTTP socket */
116   http_socket = get_http_socket(http_port != 0 ? http_port :  DEFAULT_TCP_PORT);
117
118   if(http_socket < 0)
119     {
120       fprintf(stderr, "(HTTPINFO) could not initialize HTTP socket\n");
121       exit(0);
122     }
123
124   /* Register socket */
125   add_olsr_socket(http_socket, &parse_http_request);
126
127   return 1;
128 }
129
130 static int
131 get_http_socket(int port)
132 {
133   struct sockaddr_in sin;
134   olsr_u32_t yes = 1;
135   int s;
136
137   /* Init ipc socket */
138   if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
139     {
140       olsr_printf(1, "(HTTPINFO)socket %s\n", strerror(errno));
141       return -1;
142     }
143
144   if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
145     {
146       perror("SO_REUSEADDR failed");
147       close(s);
148       return -1;
149     }
150
151   /* Bind the socket */
152   
153   /* complete the socket structure */
154   memset(&sin, 0, sizeof(sin));
155   sin.sin_family = AF_INET;
156   sin.sin_addr.s_addr = INADDR_ANY;
157   sin.sin_port = htons(port);
158   
159   /* bind the socket to the port number */
160   if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
161     {
162       olsr_printf(1, "(HTTPINFO) bind failed %s\n", strerror(errno));
163       return -1;
164     }
165       
166   /* show that we are willing to listen */
167   if (listen(s, 1) == -1) 
168     {
169       olsr_printf(1, "(HTTPINFO) listen failed %s\n", strerror(errno));
170       return -1;
171     }
172
173   return s;
174 }
175
176
177 /* Non reentrant - but we are not multithreaded anyway */
178 void
179 parse_http_request(int fd)
180 {
181   struct sockaddr_in pin;
182   socklen_t addrlen;
183   char *addr;  
184   char req[MAX_HTTPREQ_SIZE];
185   static char body[HTML_BUFSIZE];
186   char req_type[11];
187   char filename[251];
188   char http_version[11];
189   int c = 0, r = 1, size = 0;
190
191   addrlen = sizeof(struct sockaddr_in);
192
193   if(curr_clients >= MAX_CLIENTS)
194     return;
195
196   curr_clients++;
197
198   if ((client_sockets[curr_clients] = accept(fd, (struct sockaddr *)  &pin, &addrlen)) == -1)
199     {
200       olsr_printf(1, "(HTTPINFO) accept: %s\n", strerror(errno));
201       goto close_connection;
202     }
203
204   addr = inet_ntoa(pin.sin_addr);
205
206
207   memset(req, 0, MAX_HTTPREQ_SIZE);
208   memset(body, 0, 1024*10);
209
210   while((r = recv(client_sockets[curr_clients], &req[c], 1, 0)) > 0 && (c < (MAX_HTTPREQ_SIZE-1)))
211     {
212       c++;
213
214       if((c > 3 && !strcmp(&req[c-4], "\r\n\r\n")) ||
215          (c > 1 && !strcmp(&req[c-2], "\n\n")))
216         break;
217     }
218   
219   if(r < 0)
220     {
221       printf("(HTTPINFO) Failed to recieve data from client!\n");
222       goto close_connection;
223     }
224   
225   /* Get the request */
226   if(sscanf(req, "%10s %250s %10s\n", req_type, filename, http_version) != 3)
227     {
228       /* Try without HTTP version */
229       if(sscanf(req, "%10s %250s\n", req_type, filename) != 2)
230         {
231           printf("(HTTPINFO) Error parsing request %s!\n", req);
232           goto close_connection;
233         }
234     }
235   
236   
237   printf("Request: %s\nfile: %s\nVersion: %s\n\n", req_type, filename, http_version);
238
239   if(strcmp(req_type, "GET"))
240     {
241       /* We only support GET */
242       strcpy(body, HTTP_400_MSG);
243       c = build_http_header(HTTP_BAD_REQ, strlen(body), req, MAX_HTTPREQ_SIZE);
244     }
245   else if(strlen(filename) > 1)
246     {
247       /* We only support request for / */
248       strcpy(body, HTTP_404_MSG);
249       c = build_http_header(HTTP_BAD_FILE, strlen(body), req, MAX_HTTPREQ_SIZE);
250     }
251   else
252     {
253       int i = 0;
254       while(http_ok_head[i])
255           {
256               size += sprintf(&body[size], http_ok_head[i]);
257               i++;
258           }
259       printf("\n\n");
260       /* All is good */
261
262       size += build_frame("Status", 
263                           "status", 
264                           FRAMEWIDTH, 
265                           &body[size], 
266                           HTML_BUFSIZE - size, 
267                           &build_status_body);
268       size += build_frame("Current Routes", 
269                           "routes", 
270                           FRAMEWIDTH, 
271                           &body[size], 
272                           HTML_BUFSIZE - size, 
273                           &build_routes_body);
274       size += build_frame("Links and Neighbors", 
275                           "neighbors", 
276                           FRAMEWIDTH, 
277                           &body[size], 
278                           HTML_BUFSIZE - size, 
279                           &build_neigh_body);
280       size += build_frame("Topology", 
281                           "topology", 
282                           FRAMEWIDTH, 
283                           &body[size], 
284                           HTML_BUFSIZE - size, 
285                           &build_topo_body);
286       size += build_frame("HNA", 
287                           "hna", 
288                           FRAMEWIDTH, 
289                           &body[size], 
290                           HTML_BUFSIZE - size, 
291                           &build_hna_body);
292       size += build_frame("MID", 
293                           "mid", 
294                           FRAMEWIDTH, 
295                           &body[size], 
296                           HTML_BUFSIZE - size, 
297                           &build_mid_body);
298
299
300       i = 0;
301       while(http_ok_tail[i])
302           {
303               size += sprintf(&body[size], http_ok_tail[i]);
304               i++;
305           }
306
307
308       c = build_http_header(HTTP_OK, size, req, MAX_HTTPREQ_SIZE);
309     }
310   
311   r = send(client_sockets[curr_clients], req, c, 0);   
312   if(r < 0)
313     {
314       printf("(HTTPINFO) Failed sending data to client!\n");
315       goto close_connection;
316     }
317
318   r = send(client_sockets[curr_clients], body, size, 0);
319   if(r < 0)
320     {
321       printf("(HTTPINFO) Failed sending data to client!\n");
322       goto close_connection;
323     }
324
325  close_connection:
326   close(client_sockets[curr_clients]);
327   curr_clients--;
328
329 }
330
331
332 int
333 build_http_header(http_header_type type, olsr_u32_t size, char *buf, olsr_u32_t bufsize)
334 {
335   time_t currtime;
336   char timestr[45];
337   char tmp[30];
338
339   memset(buf, 0, bufsize);
340
341   switch(type)
342     {
343     case(HTTP_BAD_REQ):
344       memcpy(buf, HTTP_400, strlen(HTTP_400));
345       break;
346     case(HTTP_BAD_FILE):
347       memcpy(buf, HTTP_404, strlen(HTTP_404));
348       break;
349     default:
350       /* Defaults to OK */
351       memcpy(buf, HTTP_200, strlen(HTTP_200));
352       break;
353     }
354
355
356   /* Date */
357   if(time(&currtime))
358     {
359       strftime(timestr, 45, "Date: %a, %d %b %Y %H:%M:%S GMT\r\n", gmtime(&currtime));
360       strcat(buf, timestr);
361     }
362   
363   /* Server version */
364   strcat(buf, "Server: " PLUGIN_NAME " " PLUGIN_VERSION " " HTTP_VERSION "\r\n");
365
366   /* connection-type */
367   strcat(buf,"Connection: closed\r\n");
368
369   /* MIME type */
370   strcat(buf, "Content-type: text/html\r\n");
371
372   /* Content length */
373   if(size > 0)
374     {
375       sprintf(tmp, "Content-length: %i\r\n", size);
376       strcat(buf, tmp);
377     }
378
379
380   /* Cache-control 
381    * No caching dynamic pages
382    */
383   strcat(buf, "Cache-Control: no-cache\r\n");
384
385
386   /* End header */
387   strcat(buf, "\r\n");
388   
389   printf("HEADER:\n%s", buf);
390
391   return strlen(buf);
392
393 }
394
395 /*
396  * destructor - called at unload
397  */
398 void
399 olsr_plugin_exit()
400 {
401   if(http_socket)
402     close(http_socket);
403 }
404
405
406 /* Mulitpurpose funtion */
407 int
408 plugin_io(int cmd, void *data, size_t size)
409 {
410
411   switch(cmd)
412     {
413     default:
414       return 0;
415     }
416   
417   return 1;
418
419 }
420
421
422 static int
423 build_frame(char *title, 
424             char *link, 
425             int width,
426             char *buf,
427             olsr_u32_t bufsize, 
428             int(*frame_body_cb)(char *, olsr_u32_t))
429 {
430   int i = 0, size = 0;
431
432   size += sprintf(&buf[size], http_frame[i++], width);
433   size += sprintf(&buf[size], http_frame[i++], link, title);
434
435   while(http_frame[i])
436     {
437       if(!strcmp(http_frame[i], "<!-- BODY -->"))
438         size += frame_body_cb(&buf[size], bufsize - size);
439       else
440         size += sprintf(&buf[size], http_frame[i]);      
441
442       i++;
443     }
444
445   return size;
446 }
447
448
449
450 int
451 build_routes_body(char *buf, olsr_u32_t bufsize)
452 {
453   int size = 0, index;
454   struct rt_entry *routes;
455
456   size += sprintf(&buf[size], "OLSR host routes in kernel\n");
457   size += sprintf(&buf[size], "<hr><table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Destination</th><th>Gateway</th><th>Metric</th><th>Interface</th></tr>\n");
458
459   /* Neighbors */
460   for(index = 0;index < HASHSIZE;index++)
461     {
462       for(routes = host_routes[index].next;
463           routes != &host_routes[index];
464           routes = routes->next)
465         {
466           size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td><td>%d</td><td>%s</td></tr>\n",
467                           olsr_ip_to_string(&routes->rt_dst),
468                           olsr_ip_to_string(&routes->rt_router),
469                           routes->rt_metric,
470                           routes->rt_if->int_name);
471         }
472     }
473
474   size += sprintf(&buf[size], "</table><hr>\n");
475
476   size += sprintf(&buf[size], "OLSR HNA routes in kernel\n");
477   size += sprintf(&buf[size], "<hr><table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Destination</th><th>Gateway</th><th>Metric</th><th>Interface</th></tr>\n");
478
479   /* Neighbors */
480   for(index = 0;index < HASHSIZE;index++)
481     {
482       for(routes = hna_routes[index].next;
483           routes != &hna_routes[index];
484           routes = routes->next)
485         {
486           size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td><td>%d</td><td>%s</td></tr>\n",
487                           olsr_ip_to_string(&routes->rt_dst),
488                           olsr_ip_to_string(&routes->rt_router),
489                           routes->rt_metric,
490                           routes->rt_if->int_name);
491         }
492     }
493
494   size += sprintf(&buf[size], "</table><hr>\n");
495
496   return size;
497 }
498
499 int
500 build_status_body(char *buf, olsr_u32_t bufsize)
501 {
502     char systime[100];
503     time_t currtime;
504     int size = 0;
505     struct olsr_if *ifs;
506     struct plugin_entry *pentry;
507     struct plugin_param *pparam;
508     struct timeval now, uptime;
509     int hours, mins, days;
510
511     gettimeofday(&now, NULL);
512     timersub(&now, &start_time, &uptime);
513     days = uptime.tv_sec/86400;
514     uptime.tv_sec -= days*86400;
515     hours = uptime.tv_sec/3600;
516     uptime.tv_sec -= hours*3600;
517     mins = uptime.tv_sec/60;
518     uptime.tv_sec -= mins*60;
519
520     time(&currtime);
521     strftime(systime, 100, "System time: <i>%a, %d %b %Y %H:%M:%S</i><br>", gmtime(&currtime));
522
523
524     size += sprintf(&buf[size], "%s\n", systime);
525
526     if(days)
527       size += sprintf(&buf[size], "Olsrd uptime: <i>%d day(s) %02d hours %02d minutes %02d seconds</i>\n", days, hours, mins, (int)uptime.tv_sec);
528     else
529       size += sprintf(&buf[size], "Olsrd uptime: <i>%02d hours %02d minutes %02d seconds</i>\n", hours, mins, (int)uptime.tv_sec);
530
531     size += sprintf(&buf[size], "<hr><table width=790 border=0>\n<tr>");
532
533     size += sprintf(&buf[size], "<td>Main address: <b>%s</b></td>\n", olsr_ip_to_string(main_addr));
534     
535     size += sprintf(&buf[size], "<td>IP version: %d</td>\n", cfg->ip_version == AF_INET ? 4 : 6);
536
537     size += sprintf(&buf[size], "<td>Debug level: %d</td>\n", cfg->debug_level);
538
539     size += sprintf(&buf[size], "</tr>\n<tr>\n");
540
541     size += sprintf(&buf[size], "<td>Pollrate: %0.2f</td>\n", cfg->pollrate);
542     size += sprintf(&buf[size], "<td>TC redundancy: %d</td>\n", cfg->tc_redundancy);
543     size += sprintf(&buf[size], "<td>MPR coverage: %d</td>\n", cfg->mpr_coverage);
544
545
546     size += sprintf(&buf[size], "</tr>\n<tr>\n");
547
548     size += sprintf(&buf[size], "<td>TOS: 0x%04x</td>\n", cfg->tos);
549
550     size += sprintf(&buf[size], "<td>Willingness: %d %s</td>\n", cfg->willingness, cfg->willingness_auto ? "(auto)" : "");
551     
552     size += sprintf(&buf[size], "</tr>\n<tr>\n");
553
554     size += sprintf(&buf[size], "<td>Hysteresis: %s</td>\n", cfg->use_hysteresis ? "Enabled" : "Disabled");
555         
556     size += sprintf(&buf[size], "<td>Hyst scaling: %0.2f</td>\n", cfg->hysteresis_param.scaling);
557     size += sprintf(&buf[size], "<td>Hyst lower/upper: %0.2f/%0.2f</td>\n", cfg->hysteresis_param.thr_low, cfg->hysteresis_param.thr_high);
558
559     size += sprintf(&buf[size], "</tr>\n<tr>\n");
560
561     size += sprintf(&buf[size], "<td>LQ extention: %s</td>\n", cfg->lq_level ? "Enabled" : "Disabled");
562     size += sprintf(&buf[size], "<td>LQ level: %d</td>\n", cfg->lq_level);
563     size += sprintf(&buf[size], "<td>LQ winsize: %d</td>\n", cfg->lq_wsize);
564     size += sprintf(&buf[size], "<td></td>\n");
565
566     size += sprintf(&buf[size], "</tr></table>\n");
567
568     size += sprintf(&buf[size], "<hr>\n");
569
570     size += sprintf(&buf[size], "Interfaces:<br>\n");
571
572
573     size += sprintf(&buf[size], "<table width=790 border=0>\n");
574
575
576     for(ifs = cfg->interfaces; ifs; ifs = ifs->next)
577       {
578         struct interface *rifs = ifs->interf;
579
580         size += sprintf(&buf[size], "<tr><th colspan=3>%s</th>\n", ifs->name);
581         if(!rifs)
582           {
583             size += sprintf(&buf[size], "<tr><td colspan=3>Status: DOWN</td></tr>\n");
584             continue;
585           }
586         
587         if(cfg->ip_version == AF_INET)
588           {
589             size += sprintf(&buf[size], "<tr><td>IP: %s</td>\n", 
590                             sockaddr_to_string(&rifs->int_addr));
591             size += sprintf(&buf[size], "<td>MASK: %s</td>\n", 
592                             sockaddr_to_string(&rifs->int_netmask));
593             size += sprintf(&buf[size], "<td>BCAST: %s</td></tr>\n",
594                             sockaddr_to_string(&rifs->int_broadaddr));
595             size += sprintf(&buf[size], "<tr><td>MTU: %d</td>\n", rifs->int_mtu);
596             size += sprintf(&buf[size], "<td>WLAN: %s</td>\n", rifs->is_wireless ? "Yes" : "No");
597             size += sprintf(&buf[size], "<td>STATUS: UP</td></tr>\n");
598           }
599         else
600           {
601             size += sprintf(&buf[size], "<tr><td>IP: TBD</td>\n");
602             size += sprintf(&buf[size], "<td>MASK: TBD</td>\n");
603             size += sprintf(&buf[size], "<td>BCAST: TBD</td></tr>\n");
604             size += sprintf(&buf[size], "<tr><td>MTU: TBD</td>\n");
605             size += sprintf(&buf[size], "<td>WLAN: TBD</td>\n");
606             size += sprintf(&buf[size], "<td>STATUS: TBD</td></tr>\n");
607           }         
608
609       }
610
611     size += sprintf(&buf[size], "</table>\n");
612
613     if(cfg->allow_no_interfaces)
614       size += sprintf(&buf[size], "<i>Olsrd is configured to run even if no interfaces are available</i><br>\n");
615     else
616       size += sprintf(&buf[size], "<i>Olsrd is configured to halt if no interfaces are available</i><br>\n");
617
618     size += sprintf(&buf[size], "<hr>Plugins:<br>\n");
619
620     size += sprintf(&buf[size], "<table width=790 border=0><tr><th>Name</th><th>Parameters</th></tr>\n");
621
622     for(pentry = cfg->plugins; pentry; pentry = pentry->next)
623       {
624         size += sprintf(&buf[size], "<tr><td>%s</td>\n", pentry->name);
625
626         size += sprintf(&buf[size], "<td><select>\n");
627         size += sprintf(&buf[size], "<option>KEY, VALUE</option>\n");
628
629         for(pparam = pentry->params; pparam; pparam = pparam->next)
630           {
631             size += sprintf(&buf[size], "<option>\"%s\", \"%s\"</option>\n",
632                             pparam->key,
633                             pparam->value);
634           }
635         size += sprintf(&buf[size], "</select></td></tr>\n");
636
637       }
638
639     size += sprintf(&buf[size], "</table>\n");
640
641     return size;
642 }
643
644
645
646 int
647 build_neigh_body(char *buf, olsr_u32_t bufsize)
648 {
649   struct neighbor_entry *neigh;
650   struct neighbor_2_list_entry *list_2;
651   struct link_entry *link = NULL;
652   int size = 0, index, thop_cnt;
653
654   size += sprintf(&buf[size], "Links\n");
655   size += sprintf(&buf[size], "<hr><table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Local IP</th><th>remote IP</th><th>Hysteresis</th><th>LinkQuality</th><th>lost</th><th>total</th><th>NLQ</th><th>ETX</th></tr>\n");
656
657   /* Link set */
658   if(olsr_plugin_io(GETD__LINK_SET, &link, sizeof(link)) && link)
659   {
660     while(link)
661       {
662         size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td><td>%0.2f</td><td>%0.2f</td><td>%d</td><td>%d</td><td>%0.2f</td><td>%0.2f</td></tr>\n",
663                         olsr_ip_to_string(&link->local_iface_addr),
664                         olsr_ip_to_string(&link->neighbor_iface_addr),
665                         link->L_link_quality, 
666                         link->loss_link_quality,
667                         link->lost_packets, 
668                         link->total_packets,
669                         link->neigh_link_quality, 
670                         (link->loss_link_quality * link->neigh_link_quality) ? 1.0 / (link->loss_link_quality * link->neigh_link_quality) : 0.0);
671
672         link = link->next;
673       }
674   }
675   else
676     {
677       size += sprintf(&buf[size], "<tr><td colspan=8>Link set not available in the olsrd version you are running!</td></tr>\n");
678     }
679   size += sprintf(&buf[size], "</table><hr>\n");
680
681   size += sprintf(&buf[size], "Neighbors\n");
682   size += sprintf(&buf[size], "<hr><table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>IP address</th><th>SYM</th><th>MPR</th><th>MPRS</th><th>Willingness</th><th>2 Hop Neighbors</th></tr>\n");
683   /* Neighbors */
684   for(index=0;index<HASHSIZE;index++)
685     {
686       for(neigh = neighbortable[index].next;
687           neigh != &neighbortable[index];
688           neigh = neigh->next)
689         {
690           printf("Size: %d IP: %s\n", size, olsr_ip_to_string(&neigh->neighbor_main_addr));
691
692           size += sprintf(&buf[size], 
693                           "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%d</td>", 
694                           olsr_ip_to_string(&neigh->neighbor_main_addr),
695                           (neigh->status == SYM) ? "YES" : "NO",
696                           neigh->is_mpr ? "YES" : "NO",
697                           olsr_lookup_mprs_set ? 
698                           (olsr_lookup_mprs_set(&neigh->neighbor_main_addr) ? "YES" : "NO") 
699                           : "UNAVAILABLE",
700                           neigh->willingness);
701
702           size += sprintf(&buf[size], "<td><select>\n");
703           size += sprintf(&buf[size], "<option>IP ADDRESS</option>\n");
704
705           thop_cnt = 0;
706
707           for(list_2 = neigh->neighbor_2_list.next;
708               list_2 != &neigh->neighbor_2_list;
709               list_2 = list_2->next)
710             {
711               size += sprintf(&buf[size], "<option>%s</option>\n", olsr_ip_to_string(&list_2->neighbor_2->neighbor_2_addr));
712               thop_cnt ++;
713             }
714           size += sprintf(&buf[size], "</select> (%d)</td></tr>\n", thop_cnt);
715
716         }
717     }
718
719   size += sprintf(&buf[size], "</table><hr>\n");
720
721   return size;
722 }
723
724
725
726 int
727 build_topo_body(char *buf, olsr_u32_t bufsize)
728 {
729   int size = 0;
730   olsr_u8_t index;
731   struct tc_entry *entry;
732   struct topo_dst *dst_entry;
733
734
735   size += sprintf(&buf[size], "<hr><table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Source IP addr</th><th>Dest IP addr</th><th>LQ</th><th>ILQ</th><th>ETX</th></tr>\n");
736
737
738   /* Topology */  
739   for(index=0;index<HASHSIZE;index++)
740     {
741       /* For all TC entries */
742       entry = tc_table[index].next;
743       while(entry != &tc_table[index])
744         {
745           /* For all destination entries of that TC entry */
746           dst_entry = entry->destinations.next;
747           while(dst_entry != &entry->destinations)
748             {
749               size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td><td>%0.2f</td><td>%0.2f</td><td>%0.2f</td></tr>\n", 
750                               olsr_ip_to_string(&entry->T_last_addr), 
751                               olsr_ip_to_string(&dst_entry->T_dest_addr),
752                               dst_entry->link_quality,
753                               dst_entry->inverse_link_quality,
754                               (dst_entry->link_quality * dst_entry->inverse_link_quality) ? 1.0 / (dst_entry->link_quality * dst_entry->inverse_link_quality) : 0.0);
755
756               dst_entry = dst_entry->next;
757             }
758           entry = entry->next;
759         }
760     }
761
762   size += sprintf(&buf[size], "</table><hr>\n");
763
764   return size;
765 }
766
767
768
769 int
770 build_hna_body(char *buf, olsr_u32_t bufsize)
771 {
772   int size;
773   olsr_u8_t index;
774   struct hna_entry *tmp_hna;
775   struct hna_net *tmp_net;
776   struct hna4_entry *hna4;
777
778   size = 0;
779
780   size += sprintf(&buf[size], "Remote HNA entries\n");
781   size += sprintf(&buf[size], "<hr><table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Network</th><th>Netmask</th><th>Gateway</th></tr>\n");
782
783   /* HNA entries */
784   for(index=0;index<HASHSIZE;index++)
785     {
786       tmp_hna = hna_set[index].next;
787       /* Check all entrys */
788       while(tmp_hna != &hna_set[index])
789         {
790           /* Check all networks */
791           tmp_net = tmp_hna->networks.next;
792               
793           while(tmp_net != &tmp_hna->networks)
794             {
795               size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td><td>%s</td></tr>\n", 
796                               olsr_ip_to_string(&tmp_net->A_network_addr),
797                               olsr_netmask_to_string(&tmp_net->A_netmask),
798                               olsr_ip_to_string(&tmp_hna->A_gateway_addr));
799               tmp_net = tmp_net->next;
800             }
801               
802           tmp_hna = tmp_hna->next;
803         }
804     }
805
806   size += sprintf(&buf[size], "</table><hr>\n");
807   size += sprintf(&buf[size], "Local(announced) HNA entries\n");
808   size += sprintf(&buf[size], "<hr><table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Network</th><th>Netmask</th></tr>\n");
809
810   for(hna4 = cfg->hna4_entries; hna4; hna4 = hna4->next)
811     {
812       size += sprintf(&buf[size], "<tr><td>%s</td><td>%s</td></tr>\n", 
813                       olsr_ip_to_string((union olsr_ip_addr *)&hna4->net),
814                       olsr_ip_to_string((union olsr_ip_addr *)&hna4->netmask));
815     }
816
817   size += sprintf(&buf[size], "</table><hr>\n");
818
819
820   return size;
821 }
822
823
824 int
825 build_mid_body(char *buf, olsr_u32_t bufsize)
826 {
827   int size = 0;
828   olsr_u8_t index;
829   struct mid_entry *entry;
830   struct addresses *alias;
831
832   size += sprintf(&buf[size], "<hr><table width=\"100%%\" BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=center><tr><th>Main Address</th><th>Aliases</th></tr>\n");
833   
834   /* MID */  
835   for(index=0;index<HASHSIZE;index++)
836     {
837       entry = mid_set[index].next;
838       while(entry != &mid_set[index])
839         {
840           size += sprintf(&buf[size], "<tr><td>%s</td>\n", olsr_ip_to_string(&entry->main_addr));
841           size += sprintf(&buf[size], "<td><select>\n<option>IP ADDRESS</option>\n");
842
843           alias = entry->aliases;
844           while(alias)
845             {
846               size += sprintf(&buf[size], "<option>%s</option>\n", olsr_ip_to_string(&alias->address));
847               alias = alias->next;
848             }
849           size += sprintf(&buf[size], "</select>\n");
850
851           size += sprintf(&buf[size], "</tr>\n");
852           entry = entry->next;
853         }
854     }
855
856   size += sprintf(&buf[size], "</table><hr>\n");
857
858
859
860   return size;
861 }
862
863 /**
864  *Converts a olsr_ip_addr to a string
865  *Goes for both IPv4 and IPv6
866  *
867  *NON REENTRANT! If you need to use this
868  *function twice in e.g. the same printf
869  *it will not work.
870  *You must use it in different calls e.g.
871  *two different printfs
872  *
873  *@param the IP to convert
874  *@return a pointer to a static string buffer
875  *representing the address in "dots and numbers"
876  *
877  */
878 char *
879 olsr_ip_to_string(union olsr_ip_addr *addr)
880 {
881   static int index = 0;
882   static char buff[4][100];
883   char *ret;
884   struct in_addr in;
885  
886   if(ipversion == AF_INET)
887     {
888       in.s_addr=addr->v4;
889       ret = inet_ntoa(in);
890     }
891   else
892     {
893       /* IPv6 */
894       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
895     }
896
897   strncpy(buff[index], ret, 100);
898
899   ret = buff[index];
900
901   index = (index + 1) & 3;
902
903   return ret;
904 }
905
906
907
908
909 /**
910  *This function is just as bad as the previous one :-(
911  */
912 char *
913 olsr_netmask_to_string(union hna_netmask *mask)
914 {
915   char *ret;
916   struct in_addr in;
917   static char netmask[5];
918
919   if(ipversion == AF_INET)
920     {
921       in.s_addr = mask->v4;
922       ret = inet_ntoa(in);
923       return ret;
924
925     }
926   else
927     {
928       /* IPv6 */
929       sprintf(netmask, "%d", mask->v6);
930       return netmask;
931     }
932
933   return ret;
934 }
935
936
937
938
939 char *
940 sockaddr_to_string(struct sockaddr *address_to_convert)
941 {
942   struct sockaddr_in           *address;
943   
944   address=(struct sockaddr_in *)address_to_convert; 
945   return(inet_ntoa(address->sin_addr));
946   
947 }