3 * Copyright (c) 2004, Andreas Tønnesen(andreto-at-olsr.org)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
32 /* $Id: olsrd_power.c,v 1.10 2005/05/25 13:50:22 br1 Exp $ */
35 * Dynamic linked library example for UniK OLSRd
38 #include "olsrd_power.h"
49 #define close(x) closesocket(x)
53 #define OS "GNU/Linux"
60 #define OS "Undefined"
69 ipc_send(char *, int);
73 *Do initialization here
75 *This function is called by the my_init
76 *function in uolsrd_plugin.c
82 struct olsr_apm_info apm_info;
84 if(ipversion != AF_INET)
86 fprintf(stderr, "This plugin only supports IPv4!\n");
89 /* Initial IPC value */
93 for(i = 0; i < HASHSIZE; i++)
95 list[i].next = &list[i];
96 list[i].prev = &list[i];
99 if(apm_read(&apm_info) < 0)
102 olsr_printf(1, "No APM info avalible! This node will not generate powermessages!\n\n");
106 olsr_printf(1, "Node has APM info!\n");
110 /* Register functions with olsrd */
111 olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
113 olsr_register_timeout_function(&olsr_timeout);
115 olsr_register_scheduler_event(&olsr_event, NULL, EMISSION_INTERVAL, 0, NULL);
123 struct sockaddr_in sin;
126 /* Init ipc socket */
127 if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
129 perror("IPC socket");
134 if (setsockopt(ipc_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)) < 0)
136 perror("SO_REUSEADDR failed");
141 if (setsockopt(ipc_socket, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes)) < 0)
143 perror("SO_REUSEADDR failed");
148 /* Bind the socket */
150 /* complete the socket structure */
151 memset(&sin, 0, sizeof(sin));
152 sin.sin_family = AF_INET;
153 sin.sin_addr.s_addr = INADDR_ANY;
154 sin.sin_port = htons(IPC_PORT);
156 /* bind the socket to the port number */
157 if (bind(ipc_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1)
163 /* show that we are willing to listen */
164 if (listen(ipc_socket, 1) == -1)
166 perror("IPC listen");
170 /* Register with olsrd */
171 add_olsr_socket(ipc_socket, &ipc_action);
182 struct sockaddr_in pin;
186 addrlen = sizeof(struct sockaddr_in);
188 if ((ipc_connection = accept(ipc_socket, (struct sockaddr *) &pin, &addrlen)) == -1)
190 perror("IPC accept");
195 addr = inet_ntoa(pin.sin_addr);
196 if(ntohl(pin.sin_addr.s_addr) != INADDR_LOOPBACK)
198 olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
199 close(ipc_connection);
205 olsr_printf(1, "POWER: Connection from %s\n",addr);
212 * destructor - called at unload
223 /* Mulitpurpose funtion */
225 plugin_io(int cmd, void *data, size_t size)
240 *A timeoutfunction called every time
241 *the scheduler is polled
246 //printf("PLUGIN Timeout!\n");
247 struct pwrentry *tmp_list;
248 struct pwrentry *entry_to_delete;
252 for(index=0;index<HASHSIZE;index++)
254 tmp_list = list[index].next;
255 /*Traverse MID list*/
256 while(tmp_list != &list[index])
258 /*Check if the entry is timed out*/
259 if(olsr_timed_out(&tmp_list->timer))
261 entry_to_delete = tmp_list;
262 tmp_list = tmp_list->next;
263 olsr_printf(1, "POWER info for %s timed out.. deleting it\n",
264 olsr_ip_to_string(&entry_to_delete->originator));
266 entry_to_delete->prev->next = entry_to_delete->next;
267 entry_to_delete->next->prev = entry_to_delete->prev;
270 free(entry_to_delete);
273 tmp_list = tmp_list->next;
285 olsr_event(void *foo)
287 union olsr_message *message = (union olsr_message*)buffer;
288 struct interface *ifn;
290 /* If we can't produce power info we do nothing */
294 olsr_printf(3, "PLUG-IN: Generating package - ");
296 /* looping trough interfaces */
297 for (ifn = ifs; ifn ; ifn = ifn->int_next)
299 olsr_printf(3, "[%s] ", ifn->int_name);
301 if(ipversion == AF_INET)
304 message->v4.olsr_msgtype = MESSAGE_TYPE;
305 message->v4.olsr_vtime = double_to_me(7.5);
306 message->v4.olsr_msgsize = htons(sizeof(struct olsrmsg));
307 memcpy(&message->v4.originator, main_addr, ipsize);
308 message->v4.ttl = MAX_TTL;
309 message->v4.hopcnt = 0;
310 message->v4.seqno = htons(get_msg_seqno());
312 get_powerstatus(&message->v4.msg);
314 if(net_outbuffer_push(ifn, (olsr_u8_t *)message, sizeof(struct olsrmsg)) != sizeof(struct olsrmsg))
317 /* Send data and try again */
319 if(net_outbuffer_push(ifn, (olsr_u8_t *)message, sizeof(struct olsrmsg)) != sizeof(struct olsrmsg))
320 olsr_printf(1, "Powerplugin: could not write to buffer for interface: %s\n", ifn->int_name);
327 message->v6.olsr_msgtype = MESSAGE_TYPE;
328 message->v6.olsr_vtime = double_to_me(7.5);
329 message->v6.olsr_msgsize = htons(sizeof(struct olsrmsg));
330 memcpy(&message->v6.originator, main_addr, ipsize);
331 message->v6.ttl = MAX_TTL;
332 message->v6.hopcnt = 0;
333 message->v6.seqno = htons(get_msg_seqno());
335 get_powerstatus(&message->v6.msg);
337 if(net_outbuffer_push(ifn, (olsr_u8_t *)message, sizeof(struct olsrmsg6)) != sizeof(struct olsrmsg6))
339 /* Send data and try again */
341 if(net_outbuffer_push(ifn, (olsr_u8_t *)message, sizeof(struct olsrmsg6)) != sizeof(struct olsrmsg6))
342 olsr_printf(1, "Powerplugin: could not write to buffer for interface: %s\n", ifn->int_name);
348 olsr_printf(2, "\n");
350 /* Try to set up IPC socket if not already up */
362 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *in_addr)
364 struct powermsg *message;
365 union olsr_ip_addr originator;
368 /* Fetch the originator of the messsage */
369 memcpy(&originator, &m->v4.originator, ipsize);
371 /* Fetch the message based on IP version */
372 if(ipversion == AF_INET)
374 message = &m->v4.msg;
375 vtime = ME_TO_DOUBLE(m->v4.olsr_vtime);
379 message = &m->v6.msg;
380 vtime = ME_TO_DOUBLE(m->v6.olsr_vtime);
383 /* Check if message originated from this node */
384 if(memcmp(&originator, main_addr, ipsize) == 0)
385 /* If so - back off */
388 /* Check that the neighbor this message was received
390 if(check_neighbor_link(in_addr) != SYM_LINK)
392 /* If not symmetric - back off */
393 olsr_printf(3, "Received POWER from NON SYM neighbor %s\n", olsr_ip_to_string(in_addr));
397 /* Check if this message has been processed before
398 * Remeber that this also registeres the message as
399 * processed if nessecary
401 if(!check_dup_proc(&originator,
402 ntohs(m->v4.seqno))) /* REMEMBER NTOHS!! */
404 /* If so - do not process */
410 olsr_printf(3, "POWER PLUG-IN: Processing PWR from %s seqno: %d\n",
411 olsr_ip_to_string(&originator),
414 /* Call a function that updates the database entry */
415 update_power_entry(&originator, message, vtime);
419 /* Forward the message if nessecary
420 * default_fwd does all the work for us!
424 ntohs(m->v4.seqno), /* IMPORTANT!!! */
433 *Update or register a new power entry
436 update_power_entry(union olsr_ip_addr *originator, struct powermsg *message, double vtime)
439 struct pwrentry *entry;
441 hash = olsr_hashing(originator);
443 /* Check for the entry */
444 for(entry = list[hash].next;
445 entry != &list[hash];
448 if(memcmp(originator, &entry->originator, ipsize) == 0)
450 entry->source_type = message->source_type;
451 entry->percentage = message->percentage;
452 entry->time_left = message->time_left;
454 olsr_get_timestamp(vtime * 1000, &entry->timer);
460 olsr_printf(1, "New power entry %s: ", olsr_ip_to_string(originator));
462 if(message->source_type == OLSR_BATTERY_POWERED)
463 olsr_printf(1, "BATTERY P: %d%% T: %d mins\n",
467 olsr_printf(1, "AC\n");
469 entry = olsr_malloc(sizeof(struct pwrentry), "POWERPLUGIN: new power entry");
473 memcpy(&entry->originator, originator, ipsize);
475 entry->source_type = message->source_type;
476 entry->percentage = message->percentage;
477 entry->time_left = message->time_left;
479 olsr_get_timestamp(vtime * 1000, &entry->timer);
482 entry->next = list[hash].next->prev;
483 entry->prev = &list[hash];
484 list[hash].next->prev = entry;
485 list[hash].next = entry;
492 *Print all registered power entries
499 struct pwrentry *entry;
505 ipc_send("--POWERTABLE--\n", 15);
507 for(hash = 0; hash < HASHSIZE; hash++)
508 /* Check for the entry */
509 for(entry = list[hash].next;
510 entry != &list[hash];
513 sprintf(buf, "[%s]: ", olsr_ip_to_string(&entry->originator));
514 ipc_send(buf, strlen(buf));
516 if(entry->source_type == OLSR_BATTERY_POWERED)
519 "BATTERY P: %d%% T: %d mins\n",
522 ipc_send(buf, strlen(buf));
528 ipc_send("--------------\n", 15);
535 ipc_send(char *data, int size)
541 if (send(ipc_connection, data, size, 0) < 0)
543 if (send(ipc_connection, data, size, MSG_NOSIGNAL) < 0)
546 //perror("send - IPC");
547 olsr_printf(1, "(OUTPUT)IPC connection lost!\n");
548 close(ipc_connection);
558 *Fill a powermsg struct with power data
561 get_powerstatus(struct powermsg *msg)
563 struct olsr_apm_info apm_info;
565 if(apm_read(&apm_info) < 0)
568 olsr_printf(1, "No APM info avalible! This node will not generate powermessages!\n\n");
571 if(apm_info.ac_line_status)
573 msg->source_type = OLSR_AC_POWERED;
579 msg->source_type = OLSR_BATTERY_POWERED;
580 msg->percentage = apm_info.battery_percentage;
581 msg->time_left = apm_info.battery_time_left;
590 /*************************************************************
591 * TOOLS DERIVED FROM OLSRD *
592 *************************************************************/
596 *Hashing function. Creates a key based on
598 *@param address the address to hash
599 *@return the hash(a value in the 0-31 range)
602 olsr_hashing(union olsr_ip_addr *address)
607 if(ipversion == AF_INET)
609 hash = (ntohl(address->v4));
613 tmp = (char *) &address->v6;
614 hash = (ntohl(*tmp));
617 //hash &= 0x7fffffff;
626 *Checks if a timer has times out. That means
627 *if it is smaller than present time.
628 *@param timer the timeval struct to evaluate
629 *@return positive if the timer has not timed out,
630 *0 if it matches with present time and negative
634 olsr_timed_out(struct timeval *timer)
636 return(timercmp(timer, now, <));
642 *Initiates a "timer", wich is a timeval structure,
643 *with the value given in time_value.
644 *@param time_value the value to initialize the timer with
645 *@param hold_timer the timer itself
649 olsr_init_timer(olsr_u32_t time_value, struct timeval *hold_timer)
651 olsr_u16_t time_value_sec;
652 olsr_u16_t time_value_msec;
654 time_value_sec = time_value/1000;
655 time_value_msec = time_value-(time_value_sec*1000);
657 hold_timer->tv_sec = time_value_sec;
658 hold_timer->tv_usec = time_value_msec*1000;
666 *Generaties a timestamp a certain number of milliseconds
669 *@param time_value how many milliseconds from now
670 *@param hold_timer the timer itself
674 olsr_get_timestamp(olsr_u32_t delay, struct timeval *hold_timer)
676 olsr_u16_t time_value_sec;
677 olsr_u16_t time_value_msec;
679 time_value_sec = delay/1000;
680 time_value_msec= delay - (delay*1000);
682 hold_timer->tv_sec = now->tv_sec + time_value_sec;
683 hold_timer->tv_usec = now->tv_usec + (time_value_msec*1000);
688 *Converts a olsr_ip_addr to a string
689 *Goes for both IPv4 and IPv6
691 *NON REENTRANT! If you need to use this
692 *function twice in e.g. the same printf
694 *You must use it in different calls e.g.
695 *two different printfs
697 *@param the IP to convert
698 *@return a pointer to a static string buffer
699 *representing the address in "dots and numbers"
703 olsr_ip_to_string(union olsr_ip_addr *addr)
709 if(ipversion == AF_INET)
717 ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));