Removed me_to_double use. Replaced with macro
[olsrd.git] / lib / powerinfo / src / olsrd_power.c
1
2 /*
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto-at-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 notice, 
11  *   this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright notice, 
13  *   this list of conditions and the following disclaimer in the documentation 
14  *   and/or other materials provided with the distribution.
15  * * Neither the name of the UniK olsr daemon nor the names of its contributors 
16  *   may be used to endorse or promote products derived from this software 
17  *   without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
22  * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
27  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31
32 /* $Id: olsrd_power.c,v 1.9 2005/05/25 13:41:47 kattemat Exp $ */
33
34 /*
35  * Dynamic linked library example for UniK OLSRd
36  */
37
38 #include "olsrd_power.h"
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43
44 #ifdef OS
45 #undef OS
46 #endif
47
48 #ifdef WIN32
49 #define close(x) closesocket(x)
50 #define OS "Windows"
51 #endif
52 #ifdef linux
53 #define OS "GNU/Linux"
54 #endif
55 #ifdef __FreeBSD__
56 #define OS "FreeBSD"
57 #endif
58
59 #ifndef OS
60 #define OS "Undefined"
61 #endif
62
63 int ipc_socket;
64 int ipc_open;
65 int ipc_connection;
66 int ipc_connected;
67
68 int
69 ipc_send(char *, int);
70
71 #ifdef WIN32
72
73 static char *inet_ntop4(const unsigned char *src, char *dst, int size)
74 {
75   static const char fmt[] = "%u.%u.%u.%u";
76   char tmp[sizeof "255.255.255.255"];
77
78   if (sprintf(tmp, fmt, src[0], src[1], src[2], src[3]) > size)
79     return (NULL);
80
81   return strcpy(dst, tmp);
82 }
83
84 char *inet_ntop(int af, void *src, char *dst, int size)
85 {
86   switch (af)
87   {
88   case AF_INET:
89     return (inet_ntop4(src, dst, size));
90
91   default:
92     return (NULL);
93   }
94 }
95
96 #endif
97
98 /**
99  *Do initialization here
100  *
101  *This function is called by the my_init
102  *function in uolsrd_plugin.c
103  */
104 int
105 olsr_plugin_init()
106 {
107   int i;
108   struct olsr_apm_info apm_info;
109
110   if(ipversion != AF_INET)
111     {
112       fprintf(stderr, "This plugin only supports IPv4!\n");
113       return 0;
114     }
115   /* Initial IPC value */
116   ipc_open = 0;
117
118   /* Init list */
119   for(i = 0; i < HASHSIZE; i++)
120     {
121       list[i].next = &list[i];
122       list[i].prev = &list[i];
123     }
124
125   if(apm_read(&apm_info) < 0)
126     {
127       has_apm = 0;
128       olsr_printf(1, "No APM info avalible! This node will not generate powermessages!\n\n");
129     }
130   else
131     {
132       olsr_printf(1, "Node has APM info!\n");
133       has_apm = 1;
134     }
135
136   /* Register functions with olsrd */
137   olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
138
139   olsr_register_timeout_function(&olsr_timeout);
140
141   olsr_register_scheduler_event(&olsr_event, NULL, EMISSION_INTERVAL, 0, NULL);
142
143   return 1;
144 }
145
146 int
147 plugin_ipc_init()
148 {
149   struct sockaddr_in sin;
150   olsr_u32_t yes = 1;
151
152   /* Init ipc socket */
153   if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
154     {
155       perror("IPC socket");
156       return 0;
157     }
158   else
159     {
160       if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0) 
161       {
162         perror("SO_REUSEADDR failed");
163         return 0;
164       }
165
166 #ifdef __FreeBSD__
167       if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0) 
168       {
169         perror("SO_REUSEADDR failed");
170         return 0;
171       }
172 #endif
173
174       /* Bind the socket */
175       
176       /* complete the socket structure */
177       memset(&sin, 0, sizeof(sin));
178       sin.sin_family = AF_INET;
179       sin.sin_addr.s_addr = INADDR_ANY;
180       sin.sin_port = htons(IPC_PORT);
181       
182       /* bind the socket to the port number */
183       if (bind(ipc_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1) 
184         {
185           perror("IPC bind");
186           return 0;
187         }
188       
189       /* show that we are willing to listen */
190       if (listen(ipc_socket, 1) == -1) 
191         {
192           perror("IPC listen");
193           return 0;
194         }
195
196       /* Register with olsrd */
197       add_olsr_socket(ipc_socket, &ipc_action);
198
199     }
200
201   ipc_open = 1;
202   return 1;
203 }
204
205 void
206 ipc_action(int fd)
207 {
208   struct sockaddr_in pin;
209   socklen_t addrlen;
210   char *addr;  
211
212   addrlen = sizeof(struct sockaddr_in);
213
214   if ((ipc_connection = accept(ipc_socket, (struct sockaddr *)  &pin, &addrlen)) == -1)
215     {
216       perror("IPC accept");
217       exit(1);
218     }
219   else
220     {
221       addr = inet_ntoa(pin.sin_addr);
222       if(ntohl(pin.sin_addr.s_addr) != INADDR_LOOPBACK)
223         {
224           olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
225           close(ipc_connection);
226           return;
227         }
228       else
229         {
230           ipc_connected = 1;
231           olsr_printf(1, "POWER: Connection from %s\n",addr);
232         }
233     }
234
235 }
236
237 /*
238  * destructor - called at unload
239  */
240 void
241 olsr_plugin_exit()
242 {
243   if(ipc_open)
244     close(ipc_socket);
245 }
246
247
248
249 /* Mulitpurpose funtion */
250 int
251 plugin_io(int cmd, void *data, size_t size)
252 {
253
254   switch(cmd)
255     {
256     default:
257       return 0;
258     }
259   
260   return 1;
261 }
262
263
264
265 /**
266  *A timeoutfunction called every time
267  *the scheduler is polled
268  */
269 void
270 olsr_timeout()
271 {
272   //printf("PLUGIN Timeout!\n");
273   struct pwrentry *tmp_list;
274   struct pwrentry *entry_to_delete;
275   int index;
276
277
278   for(index=0;index<HASHSIZE;index++)
279     {
280       tmp_list = list[index].next;
281       /*Traverse MID list*/
282       while(tmp_list != &list[index])
283         {
284           /*Check if the entry is timed out*/
285           if(olsr_timed_out(&tmp_list->timer))
286             {
287               entry_to_delete = tmp_list;
288               tmp_list = tmp_list->next;
289               olsr_printf(1, "POWER info for %s timed out.. deleting it\n", 
290                           olsr_ip_to_string(&entry_to_delete->originator));
291               /* Dequeue */
292               entry_to_delete->prev->next = entry_to_delete->next;
293               entry_to_delete->next->prev = entry_to_delete->prev;
294
295               /* Delete */
296               free(entry_to_delete);
297             }
298           else
299               tmp_list = tmp_list->next;
300         }
301     }
302
303   return;
304 }
305
306
307 /**
308  *Scheduled event
309  */
310 void
311 olsr_event(void *foo)
312 {
313   union olsr_message *message = (union olsr_message*)buffer;
314   struct interface *ifn;
315
316   /* If we can't produce power info we do nothing */ 
317   if(!has_apm)
318     return;
319
320   olsr_printf(3, "PLUG-IN: Generating package - ");
321
322   /* looping trough interfaces */
323   for (ifn = ifs; ifn ; ifn = ifn->int_next) 
324     {
325       olsr_printf(3, "[%s]  ", ifn->int_name);
326       /* Fill message */
327       if(ipversion == AF_INET)
328         {
329           /* IPv4 */
330           message->v4.olsr_msgtype = MESSAGE_TYPE;
331           message->v4.olsr_vtime = double_to_me(7.5);
332           message->v4.olsr_msgsize = htons(sizeof(struct olsrmsg));
333           memcpy(&message->v4.originator, main_addr, ipsize);
334           message->v4.ttl = MAX_TTL;
335           message->v4.hopcnt = 0;
336           message->v4.seqno = htons(get_msg_seqno());
337           
338           get_powerstatus(&message->v4.msg);
339
340           if(net_outbuffer_push(ifn, (olsr_u8_t *)message, sizeof(struct olsrmsg)) != sizeof(struct olsrmsg))
341             {
342
343               /* Send data and try again */
344               net_output(ifn);
345               if(net_outbuffer_push(ifn, (olsr_u8_t *)message, sizeof(struct olsrmsg)) != sizeof(struct olsrmsg))
346                 olsr_printf(1, "Powerplugin: could not write to buffer for interface: %s\n", ifn->int_name);
347             }
348
349         }
350       else
351         {
352           /* IPv6 */
353           message->v6.olsr_msgtype = MESSAGE_TYPE;
354           message->v6.olsr_vtime = double_to_me(7.5);
355           message->v6.olsr_msgsize = htons(sizeof(struct olsrmsg));
356           memcpy(&message->v6.originator, main_addr, ipsize);
357           message->v6.ttl = MAX_TTL;
358           message->v6.hopcnt = 0;
359           message->v6.seqno = htons(get_msg_seqno());
360           
361           get_powerstatus(&message->v6.msg);
362
363           if(net_outbuffer_push(ifn, (olsr_u8_t *)message, sizeof(struct olsrmsg6)) != sizeof(struct olsrmsg6))
364             {
365               /* Send data and try again */
366               net_output(ifn);
367               if(net_outbuffer_push(ifn, (olsr_u8_t *)message, sizeof(struct olsrmsg6)) != sizeof(struct olsrmsg6))
368                 olsr_printf(1, "Powerplugin: could not write to buffer for interface: %s\n", ifn->int_name);
369             }
370
371         }
372
373     }
374   olsr_printf(2, "\n");
375
376   /* Try to set up IPC socket if not already up */
377   if(!ipc_open)
378     plugin_ipc_init();
379
380   print_power_table();
381
382   return;
383 }
384
385
386
387 void
388 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *in_addr)
389 {
390   struct  powermsg *message;
391   union olsr_ip_addr originator;
392   double vtime;
393
394   /* Fetch the originator of the messsage */
395   memcpy(&originator, &m->v4.originator, ipsize);
396
397   /* Fetch the message based on IP version */
398   if(ipversion == AF_INET)
399     {
400       message = &m->v4.msg;
401       vtime = ME_TO_DOUBLE(m->v4.olsr_vtime);
402     }
403   else
404     {
405       message = &m->v6.msg;
406       vtime = ME_TO_DOUBLE(m->v6.olsr_vtime);
407     }
408
409   /* Check if message originated from this node */
410   if(memcmp(&originator, main_addr, ipsize) == 0)
411     /* If so - back off */
412     return;
413
414   /* Check that the neighbor this message was received
415      from is symmetric */
416   if(check_neighbor_link(in_addr) != SYM_LINK)
417     {
418       /* If not symmetric - back off */
419       olsr_printf(3, "Received POWER from NON SYM neighbor %s\n", olsr_ip_to_string(in_addr));
420       return;
421     }
422
423   /* Check if this message has been processed before
424    * Remeber that this also registeres the message as
425    * processed if nessecary
426    */
427   if(!check_dup_proc(&originator,
428                      ntohs(m->v4.seqno))) /* REMEMBER NTOHS!! */
429     {
430       /* If so - do not process */
431       goto forward;
432     }
433
434   /* Process */
435
436   olsr_printf(3, "POWER PLUG-IN: Processing PWR from %s seqno: %d\n",
437               olsr_ip_to_string(&originator),
438               ntohs(m->v4.seqno));
439
440   /* Call a function that updates the database entry */
441   update_power_entry(&originator, message, vtime);
442
443
444  forward:
445   /* Forward the message if nessecary
446    * default_fwd does all the work for us!
447    */
448   default_fwd(m,
449               &originator,
450               ntohs(m->v4.seqno), /* IMPORTANT!!! */
451               in_if,
452               in_addr);
453
454 }
455
456
457
458 /**
459  *Update or register a new power entry
460  */
461 int
462 update_power_entry(union olsr_ip_addr *originator, struct powermsg *message, double vtime)
463 {
464   int hash;
465   struct pwrentry *entry;
466
467   hash = olsr_hashing(originator);
468
469   /* Check for the entry */
470   for(entry = list[hash].next;
471       entry != &list[hash];
472       entry = entry->next)
473     {
474       if(memcmp(originator, &entry->originator, ipsize) == 0)
475         {
476           entry->source_type = message->source_type;
477           entry->percentage = message->percentage;
478           entry->time_left = message->time_left;
479
480           olsr_get_timestamp(vtime * 1000, &entry->timer);
481
482           return 0;
483         }
484     }
485
486   olsr_printf(1, "New power entry %s: ", olsr_ip_to_string(originator));
487
488   if(message->source_type == OLSR_BATTERY_POWERED)
489     olsr_printf(1, "BATTERY P: %d%% T: %d mins\n",
490            message->percentage,
491            message->time_left);
492   else
493     olsr_printf(1, "AC\n");
494
495   entry = olsr_malloc(sizeof(struct pwrentry), "POWERPLUGIN: new power entry");
496      
497   /* Fill struct */
498
499   memcpy(&entry->originator, originator, ipsize);
500
501   entry->source_type = message->source_type;
502   entry->percentage = message->percentage;
503   entry->time_left = message->time_left;
504   
505   olsr_get_timestamp(vtime * 1000, &entry->timer);
506
507   /* Queue */
508   entry->next = list[hash].next->prev;
509   entry->prev = &list[hash];
510   list[hash].next->prev = entry;
511   list[hash].next = entry;
512
513   return 1;
514 }
515
516
517 /**
518  *Print all registered power entries
519  */
520
521 void
522 print_power_table()
523 {
524   int hash;
525   struct pwrentry *entry;
526   char buf[200];
527
528   if(!ipc_connection)
529     return;
530
531   ipc_send("--POWERTABLE--\n", 15);
532
533   for(hash = 0; hash < HASHSIZE; hash++)
534     /* Check for the entry */
535     for(entry = list[hash].next;
536         entry != &list[hash];
537         entry = entry->next)
538       {
539         sprintf(buf, "[%s]: ", olsr_ip_to_string(&entry->originator));
540         ipc_send(buf, strlen(buf));
541
542         if(entry->source_type == OLSR_BATTERY_POWERED)
543           {
544             sprintf(buf,
545                     "BATTERY P: %d%% T: %d mins\n",
546                     entry->percentage,
547                     entry->time_left);
548             ipc_send(buf, strlen(buf));
549           }
550         else
551           ipc_send("AC\n", 3);
552       }
553
554   ipc_send("--------------\n", 15);
555
556 }
557
558
559
560 int
561 ipc_send(char *data, int size)
562 {
563   if(!ipc_connected)
564     return 0;
565
566 #ifdef __FreeBSD__
567   if (send(ipc_connection, data, size, 0) < 0) 
568 #else
569   if (send(ipc_connection, data, size, MSG_NOSIGNAL) < 0) 
570 #endif
571     {
572       //perror("send - IPC");
573       olsr_printf(1, "(OUTPUT)IPC connection lost!\n");
574       close(ipc_connection);
575       //use_ipc = 0;
576       ipc_connected = 0;
577       return -1;
578     }
579
580   return 1;
581 }
582
583 /**
584  *Fill a powermsg struct with power data
585  */
586 int
587 get_powerstatus(struct powermsg *msg)
588 {
589   struct olsr_apm_info apm_info;
590   
591   if(apm_read(&apm_info) < 0)
592     {
593       has_apm = 0;
594       olsr_printf(1, "No APM info avalible! This node will not generate powermessages!\n\n");
595     }
596
597   if(apm_info.ac_line_status)
598     {
599       msg->source_type = OLSR_AC_POWERED;
600       msg->percentage = 0;
601       msg->time_left = 0;
602     }
603   else
604     {
605       msg->source_type = OLSR_BATTERY_POWERED;
606       msg->percentage = apm_info.battery_percentage;
607       msg->time_left = apm_info.battery_time_left;
608     }
609
610   return 1;
611 }
612
613
614
615
616 /*************************************************************
617  *                 TOOLS DERIVED FROM OLSRD                  *
618  *************************************************************/
619
620
621 /**
622  *Hashing function. Creates a key based on
623  *an 32-bit address.
624  *@param address the address to hash
625  *@return the hash(a value in the 0-31 range)
626  */
627 olsr_u32_t
628 olsr_hashing(union olsr_ip_addr *address)
629 {
630   olsr_u32_t hash;
631   char *tmp;
632
633   if(ipversion == AF_INET)
634     /* IPv4 */  
635     hash = (ntohl(address->v4));
636   else
637     {
638       /* IPv6 */
639       tmp = (char *) &address->v6;
640       hash = (ntohl(*tmp));
641     }
642
643   //hash &= 0x7fffffff; 
644   hash &= HASHMASK;
645
646   return hash;
647 }
648
649
650
651 /**
652  *Checks if a timer has times out. That means
653  *if it is smaller than present time.
654  *@param timer the timeval struct to evaluate
655  *@return positive if the timer has not timed out,
656  *0 if it matches with present time and negative
657  *if it is timed out.
658  */
659 int
660 olsr_timed_out(struct timeval *timer)
661 {
662   return(timercmp(timer, now, <));
663 }
664
665
666
667 /**
668  *Initiates a "timer", wich is a timeval structure,
669  *with the value given in time_value.
670  *@param time_value the value to initialize the timer with
671  *@param hold_timer the timer itself
672  *@return nada
673  */
674 void
675 olsr_init_timer(olsr_u32_t time_value, struct timeval *hold_timer)
676
677   olsr_u16_t  time_value_sec;
678   olsr_u16_t  time_value_msec;
679
680   time_value_sec = time_value/1000;
681   time_value_msec = time_value-(time_value_sec*1000);
682
683   hold_timer->tv_sec = time_value_sec;
684   hold_timer->tv_usec = time_value_msec*1000;   
685 }
686
687
688
689
690
691 /**
692  *Generaties a timestamp a certain number of milliseconds
693  *into the future.
694  *
695  *@param time_value how many milliseconds from now
696  *@param hold_timer the timer itself
697  *@return nada
698  */
699 void
700 olsr_get_timestamp(olsr_u32_t delay, struct timeval *hold_timer)
701
702   olsr_u16_t  time_value_sec;
703   olsr_u16_t  time_value_msec;
704
705   time_value_sec = delay/1000;
706   time_value_msec= delay - (delay*1000);
707
708   hold_timer->tv_sec = now->tv_sec + time_value_sec;
709   hold_timer->tv_usec = now->tv_usec + (time_value_msec*1000);   
710 }
711
712
713 /**
714  *Converts a olsr_ip_addr to a string
715  *Goes for both IPv4 and IPv6
716  *
717  *NON REENTRANT! If you need to use this
718  *function twice in e.g. the same printf
719  *it will not work.
720  *You must use it in different calls e.g.
721  *two different printfs
722  *
723  *@param the IP to convert
724  *@return a pointer to a static string buffer
725  *representing the address in "dots and numbers"
726  *
727  */
728 char *
729 olsr_ip_to_string(union olsr_ip_addr *addr)
730 {
731
732   char *ret;
733   struct in_addr in;
734   
735   if(ipversion == AF_INET)
736     {
737       in.s_addr=addr->v4;
738       ret = inet_ntoa(in);
739     }
740   else
741     {
742       /* IPv6 */
743       ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));
744     }
745
746   return ret;
747 }
748
749