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.
33 * Dynamic linked library example for UniK OLSRd
36 #include "olsrd_power.h"
48 ipc_send(char *, int);
51 *Do initialization here
53 *This function is called by the my_init
54 *function in uolsrd_plugin.c
60 struct olsr_apm_info apm_info;
62 /* Initial IPC value */
66 for(i = 0; i < HASHSIZE; i++)
68 list[i].next = &list[i];
69 list[i].prev = &list[i];
72 if(apm_read(&apm_info) < 0)
75 olsr_printf(1, "No APM info avalible! This node will not generate powermessages!\n\n");
79 olsr_printf(1, "Node has APM info!\n");
83 /* Register functions with olsrd */
84 olsr_parser_add_function(&olsr_parser, PARSER_TYPE, 1);
86 olsr_register_timeout_function(&olsr_timeout);
88 olsr_register_scheduler_event(&olsr_event, EMISSION_INTERVAL, 0, NULL);
96 struct sockaddr_in sin;
99 if ((ipc_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
101 perror("IPC socket");
106 /* Bind the socket */
108 /* complete the socket structure */
109 memset(&sin, 0, sizeof(sin));
110 sin.sin_family = AF_INET;
111 sin.sin_addr.s_addr = INADDR_ANY;
112 sin.sin_port = htons(IPC_PORT);
114 /* bind the socket to the port number */
115 if (bind(ipc_socket, (struct sockaddr *) &sin, sizeof(sin)) == -1)
121 /* show that we are willing to listen */
122 if (listen(ipc_socket, 1) == -1)
124 perror("IPC listen");
128 /* Register with olsrd */
129 add_olsr_socket(ipc_socket, &ipc_action);
140 struct sockaddr_in pin;
144 addrlen = sizeof(struct sockaddr_in);
146 if ((ipc_connection = accept(ipc_socket, (struct sockaddr *) &pin, &addrlen)) == -1)
148 perror("IPC accept");
153 addr = inet_ntoa(pin.sin_addr);
154 if(ntohl(pin.sin_addr.s_addr) != INADDR_LOOPBACK)
156 olsr_printf(1, "Front end-connection from foregin host(%s) not allowed!\n", addr);
157 close(ipc_connection);
163 olsr_printf(1, "POWER: Connection from %s\n",addr);
170 * destructor - called at unload
181 /* Mulitpurpose funtion */
183 plugin_io(int cmd, void *data, size_t size)
198 *A timeoutfunction called every time
199 *the scheduler is polled
204 //printf("PLUGIN Timeout!\n");
205 struct pwrentry *tmp_list;
206 struct pwrentry *entry_to_delete;
210 for(index=0;index<HASHSIZE;index++)
212 tmp_list = list[index].next;
213 /*Traverse MID list*/
214 while(tmp_list != &list[index])
216 /*Check if the entry is timed out*/
217 if(olsr_timed_out(&tmp_list->timer))
219 entry_to_delete = tmp_list;
220 tmp_list = tmp_list->next;
221 olsr_printf(1, "POWER info for %s timed out.. deleting it\n",
222 olsr_ip_to_string(&entry_to_delete->originator));
224 entry_to_delete->prev->next = entry_to_delete->next;
225 entry_to_delete->next->prev = entry_to_delete->prev;
228 free(entry_to_delete);
231 tmp_list = tmp_list->next;
245 union olsr_packet *packet;
246 union olsr_message *message;
247 struct interface *ifn;
249 /* If we can't produce power info we do nothing */
253 olsr_printf(3, "PLUG-IN: Generating package - ");
255 /* Cast the char* buffer to the packetformat */
256 packet = (union olsr_packet*)buffer;
258 /* Fetch the message based on IPversion */
259 if(ipversion == AF_INET)
260 message = (union olsr_message *)packet->v4.olsr_msg;
262 message = (union olsr_message *)packet->v6.olsr_msg;
265 /* looping trough interfaces */
266 for (ifn = ifs; ifn ; ifn = ifn->int_next)
268 olsr_printf(3, "[%s] ", ifn->int_name);
270 if(ipversion == AF_INET)
273 message->v4.olsr_msgtype = MESSAGE_TYPE;
274 message->v4.olsr_vtime = double_to_me(7.5);
275 message->v4.olsr_msgsize = htons(sizeof(struct olsrmsg));
276 memcpy(&message->v4.originator, main_addr, ipsize);
277 message->v4.ttl = MAX_TTL;
278 message->v4.hopcnt = 0;
279 message->v4.seqno = htons(get_msg_seqno());
281 get_powerstatus(&message->v4.msg);
283 *outputsize = sizeof(struct olsrmsg) + sizeof(olsr_u32_t);
284 packet->v4.olsr_packlen = htons(*outputsize);
289 message->v6.olsr_msgtype = MESSAGE_TYPE;
290 message->v6.olsr_vtime = double_to_me(7.5);
291 message->v6.olsr_msgsize = htons(sizeof(struct olsrmsg));
292 memcpy(&message->v6.originator, main_addr, ipsize);
293 message->v6.ttl = MAX_TTL;
294 message->v6.hopcnt = 0;
295 message->v6.seqno = htons(get_msg_seqno());
297 get_powerstatus(&message->v6.msg);
299 *outputsize = sizeof(struct olsrmsg6) + sizeof(olsr_u32_t);
300 packet->v6.olsr_packlen = htons(*outputsize);
306 olsr_printf(3, "\n");
308 /* Try to set up IPC socket if not already up */
320 olsr_parser(union olsr_message *m, struct interface *in_if, union olsr_ip_addr *in_addr)
322 struct powermsg *message;
323 union olsr_ip_addr originator;
326 /* Fetch the originator of the messsage */
327 memcpy(&originator, &m->v4.originator, ipsize);
329 /* Fetch the message based on IP version */
330 if(ipversion == AF_INET)
332 message = &m->v4.msg;
333 vtime = me_to_double(m->v4.olsr_vtime);
337 message = &m->v6.msg;
338 vtime = me_to_double(m->v6.olsr_vtime);
341 /* Check if message originated from this node */
342 if(memcmp(&originator, main_addr, ipsize) == 0)
343 /* If so - back off */
346 /* Check that the neighbor this message was received
348 if(check_neighbor_link(in_addr) != SYM_LINK)
350 /* If not symmetric - back off */
351 olsr_printf(3, "Received POWER from NON SYM neighbor %s\n", olsr_ip_to_string(in_addr));
355 /* Check if this message has been processed before
356 * Remeber that this also registeres the message as
357 * processed if nessecary
359 if(!check_dup_proc(&originator,
360 ntohs(m->v4.seqno))) /* REMEMBER NTOHS!! */
362 /* If so - do not process */
368 olsr_printf(3, "POWER PLUG-IN: Processing PWR from %s seqno: %d\n",
369 olsr_ip_to_string(&originator),
372 /* Call a function that updates the database entry */
373 update_power_entry(&originator, message, vtime);
377 /* Forward the message if nessecary
378 * default_fwd does all the work for us!
382 ntohs(m->v4.seqno), /* IMPORTANT!!! */
391 *Update or register a new power entry
394 update_power_entry(union olsr_ip_addr *originator, struct powermsg *message, double vtime)
397 struct pwrentry *entry;
399 hash = olsr_hashing(originator);
401 /* Check for the entry */
402 for(entry = list[hash].next;
403 entry != &list[hash];
406 if(memcmp(originator, &entry->originator, ipsize) == 0)
408 entry->source_type = message->source_type;
409 entry->percentage = message->percentage;
410 entry->time_left = message->time_left;
412 olsr_get_timestamp(vtime * 1000, &entry->timer);
418 olsr_printf(1, "New power entry %s: ", olsr_ip_to_string(originator));
420 if(message->source_type == SOURCE_BATTERY)
421 olsr_printf(1, "BATTERY P: %d%% T: %d mins\n",
425 olsr_printf(1, "AC\n");
427 entry = olsr_malloc(sizeof(struct pwrentry), "POWERPLUGIN: new power entry");
431 memcpy(&entry->originator, originator, ipsize);
433 entry->source_type = message->source_type;
434 entry->percentage = message->percentage;
435 entry->time_left = message->time_left;
437 olsr_get_timestamp(vtime * 1000, &entry->timer);
440 entry->next = list[hash].next->prev;
441 entry->prev = &list[hash];
442 list[hash].next->prev = entry;
443 list[hash].next = entry;
450 *Print all registered power entries
457 struct pwrentry *entry;
463 ipc_send("--POWERTABLE--\n", 15);
465 for(hash = 0; hash < HASHSIZE; hash++)
466 /* Check for the entry */
467 for(entry = list[hash].next;
468 entry != &list[hash];
471 sprintf(buf, "[%s]: ", olsr_ip_to_string(&entry->originator));
472 ipc_send(buf, strlen(buf));
474 if(entry->source_type == SOURCE_BATTERY)
477 "BATTERY P: %d%% T: %d mins\n",
480 ipc_send(buf, strlen(buf));
486 ipc_send("--------------\n", 15);
493 ipc_send(char *data, int size)
498 if (send(ipc_connection, data, size, MSG_NOSIGNAL) < 0)
500 //perror("send - IPC");
501 olsr_printf(1, "(OUTPUT)IPC connection lost!\n");
502 close(ipc_connection);
512 *Fill a powermsg struct with power data
515 get_powerstatus(struct powermsg *msg)
517 struct olsr_apm_info apm_info;
519 if(apm_read(&apm_info) < 0)
522 olsr_printf(1, "No APM info avalible! This node will not generate powermessages!\n\n");
525 if(apm_info.ac_line_status)
527 msg->source_type = SOURCE_AC;
533 msg->source_type = SOURCE_BATTERY;
534 msg->percentage = apm_info.battery_percentage;
535 msg->time_left = apm_info.battery_time;
547 apm_read(struct olsr_apm_info *ainfo)
554 if((apm_procfile = fopen(APM_PROC, "r")) == NULL)
558 fgets(buffer, sizeof(buffer) - 1, apm_procfile);
561 /* Try re-opening the file */
562 if((apm_procfile = fopen(APM_PROC, "r")) < 0)
564 fgets(buffer, sizeof(buffer) - 1, apm_procfile);
568 fprintf(stderr, "OLSRD-POWER: Could not read APM info");
573 buffer[sizeof(buffer) - 1] = '\0';
577 sscanf(buffer, "%s %d.%d %x %x %x %x %d%% %d %s\n",
578 ainfo->driver_version,
579 &ainfo->apm_version_major,
580 &ainfo->apm_version_minor,
582 &ainfo->ac_line_status,
583 &ainfo->battery_status,
584 &ainfo->battery_flags,
585 &ainfo->battery_percentage,
586 &ainfo->battery_time,
589 ainfo->using_minutes = !strncmp(units, "min", 3) ? 1 : 0;
592 * Should take care of old APM type info here
596 * Fix possible percentage error
598 if(ainfo->battery_percentage > 100)
599 ainfo->battery_percentage = -1;
601 fclose(apm_procfile);
609 /*************************************************************
610 * TOOLS DERIVED FROM OLSRD *
611 *************************************************************/
615 *Hashing function. Creates a key based on
617 *@param address the address to hash
618 *@return the hash(a value in the 0-31 range)
621 olsr_hashing(union olsr_ip_addr *address)
626 if(ipversion == AF_INET)
628 hash = (ntohl(address->v4));
632 tmp = (char *) &address->v6;
633 hash = (ntohl(*tmp));
636 //hash &= 0x7fffffff;
645 *Checks if a timer has times out. That means
646 *if it is smaller than present time.
647 *@param timer the timeval struct to evaluate
648 *@return positive if the timer has not timed out,
649 *0 if it matches with present time and negative
653 olsr_timed_out(struct timeval *timer)
655 return(timercmp(timer, now, <));
661 *Initiates a "timer", wich is a timeval structure,
662 *with the value given in time_value.
663 *@param time_value the value to initialize the timer with
664 *@param hold_timer the timer itself
668 olsr_init_timer(olsr_u32_t time_value, struct timeval *hold_timer)
670 olsr_u16_t time_value_sec;
671 olsr_u16_t time_value_msec;
673 time_value_sec = time_value/1000;
674 time_value_msec = time_value-(time_value_sec*1000);
676 hold_timer->tv_sec = time_value_sec;
677 hold_timer->tv_usec = time_value_msec*1000;
685 *Generaties a timestamp a certain number of milliseconds
688 *@param time_value how many milliseconds from now
689 *@param hold_timer the timer itself
693 olsr_get_timestamp(olsr_u32_t delay, struct timeval *hold_timer)
695 olsr_u16_t time_value_sec;
696 olsr_u16_t time_value_msec;
698 time_value_sec = delay/1000;
699 time_value_msec= delay - (delay*1000);
701 hold_timer->tv_sec = now->tv_sec + time_value_sec;
702 hold_timer->tv_usec = now->tv_usec + (time_value_msec*1000);
707 *Converts a olsr_ip_addr to a string
708 *Goes for both IPv4 and IPv6
710 *NON REENTRANT! If you need to use this
711 *function twice in e.g. the same printf
713 *You must use it in different calls e.g.
714 *two different printfs
716 *@param the IP to convert
717 *@return a pointer to a static string buffer
718 *representing the address in "dots and numbers"
722 olsr_ip_to_string(union olsr_ip_addr *addr)
728 if(ipversion == AF_INET)
736 ret = (char *)inet_ntop(AF_INET6, &addr->v6, ipv6_buf, sizeof(ipv6_buf));