smart gateway: hook up SmartGatewaySpeedFile{,Period} parameters
authorFerry Huberts <ferry.huberts@pelagic.nl>
Wed, 9 May 2012 14:04:53 +0000 (16:04 +0200)
committerFerry Huberts <ferry.huberts@pelagic.nl>
Thu, 10 May 2012 09:02:47 +0000 (11:02 +0200)
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
src/gateway.c
src/gatewaySpeedFile.c [new file with mode: 0644]
src/gatewaySpeedFile.h [new file with mode: 0644]

index 048a7cb..84d88b3 100644 (file)
@@ -19,6 +19,7 @@
 #include "log.h"
 #include "gateway_default_handler.h"
 #include "gateway.h"
+#include "gatewaySpeedFile.h"
 
 #include <assert.h>
 #include <net/if.h>
@@ -87,6 +88,14 @@ static void smartgw_tunnel_monitor (int if_index __attribute__ ((unused)),
 }
 
 /**
+ * Timer callback that reads the smart gateway speed file
+ */
+static void smartgw_read_speed_file(void *context __attribute__ ((unused))) {
+       readGatewaySpeedFile(olsr_cnf->smart_gw_speed_file);
+       return;
+}
+
+/**
  * Initialize gateway system
  */
 int
@@ -107,6 +116,10 @@ olsr_init_gateways(void) {
     return 1;
   }
 
+  if (!startGatewaySpeedFile()) {
+         return 1;
+  }
+
   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
 
   /*
@@ -140,10 +153,26 @@ void refresh_smartgw_netmask(void) {
   }
 }
 
+/** The timer cookie, used to trace back the originator in debug */
+static struct olsr_cookie_info *smartgw_speed_file_timer_cookie = NULL;
+
+/** The timer */
+static struct timer_entry * smartgw_speed_file_timer = NULL;
+
 /**
  * Cleanup gateway tunnel system
  */
 void olsr_cleanup_gateways(void) {
+  if (smartgw_speed_file_timer != NULL) {
+       olsr_stop_timer(smartgw_speed_file_timer);
+       smartgw_speed_file_timer = NULL;
+  }
+  if (smartgw_speed_file_timer_cookie != NULL) {
+       olsr_free_cookie(smartgw_speed_file_timer_cookie);
+       smartgw_speed_file_timer_cookie = NULL;
+  }
+  stopGatewaySpeedFile();
+
   if (current_ipv4_gw) {
     olsr_os_del_ipip_tunnel(v4gw_tunnel);
   }
@@ -161,7 +190,28 @@ void olsr_cleanup_gateways(void) {
  */
 void
 olsr_trigger_inetgw_startup(void) {
-  gw_handler->handle_startup();
+       if (olsr_cnf->smart_gw_speed_file) {
+               smartgw_read_speed_file(NULL);
+
+               if (smartgw_speed_file_timer_cookie == NULL) {
+                       smartgw_speed_file_timer_cookie = olsr_alloc_cookie("smartgw speed file", OLSR_COOKIE_TYPE_TIMER);
+                       if (smartgw_speed_file_timer_cookie == NULL) {
+                               olsr_syslog(OLSR_LOG_ERR,
+                                               "Could not allocate smart gateway speed file cookie, will not read the file.\n");
+                               return;
+                       }
+               }
+               if (smartgw_speed_file_timer == NULL) {
+                       smartgw_speed_file_timer = olsr_start_timer(olsr_cnf->smart_gw_speed_file_period, 0, OLSR_TIMER_PERIODIC,
+                                       &smartgw_read_speed_file, NULL, smartgw_speed_file_timer_cookie);
+                       if (smartgw_speed_file_timer == NULL) {
+                               olsr_syslog(OLSR_LOG_ERR, "Could not start smart gateway speed file timer, will not read the file.\n");
+                               return;
+                       }
+               }
+       }
+
+       gw_handler->handle_startup();
 }
 
 /**
diff --git a/src/gatewaySpeedFile.c b/src/gatewaySpeedFile.c
new file mode 100644 (file)
index 0000000..78d3ecc
--- /dev/null
@@ -0,0 +1,185 @@
+#include "gatewaySpeedFile.h"
+
+#include "log.h"
+#include <regex.h>
+#include <sys/stat.h>
+
+#define LINE_LENGTH 256
+
+static const char * regexCommentString = "^([[:space:]]*|[[:space:]#]+.*)$";
+static const char * regexNameValueString =
+               "^[[:space:]]*([^[:space:]]+)[[:space:]]*=[[:space:]]*([[:digit:]]+)[[:space:]]*$";
+static const size_t regexNameValuematchCount = 3;
+
+static regex_t regexComment;
+static regex_t regexNameValue;
+static bool started = false;
+
+typedef struct _CachedStat {
+       struct timespec st_mtim; /* Time of last modification.  */
+} CachedStat;
+
+static CachedStat cachedStat;
+
+/**
+ Read an unsigned long number from a value string
+
+ @param valueName
+ the name of the value
+ @param value
+ the string to convert to a number
+ @param valueNumber
+ a pointer to the location where to store the number upon successful conversion
+
+ @return
+ - true on success
+ - false otherwise
+ */
+static bool readUL(const char * valueName, const char * value, unsigned long * valueNumber) {
+       char * endPtr = NULL;
+       unsigned long valueNew;
+
+       errno = 0;
+       valueNew = strtoul(value, &endPtr, 10);
+
+       if (!((endPtr != value) && (*value != '\0') && (*endPtr == '\0'))) {
+               /* invalid conversion */
+               olsr_syslog(OLSR_LOG_ERR, "Configured %s (%s) could not be converted to a number: %s\n", valueName, value,
+                               strerror(errno));
+               return false;
+       }
+
+       *valueNumber = valueNew;
+
+       return true;
+}
+
+bool startGatewaySpeedFile(void) {
+       if (started) {
+               return true;
+       }
+
+       if (regcomp(&regexComment, regexCommentString, REG_EXTENDED)) {
+               olsr_printf(0, "Could not compile regex \"%s\"\n", regexCommentString);
+               return false;
+       }
+
+       if (regcomp(&regexNameValue, regexNameValueString, REG_EXTENDED)) {
+               olsr_printf(0, "Could not compile regex \"%s\"\n", regexNameValueString);
+               return false;
+       }
+
+       cachedStat.st_mtim.tv_sec = -1;
+       cachedStat.st_mtim.tv_nsec = -1;
+
+       started = true;
+       return true;
+}
+
+void stopGatewaySpeedFile(void) {
+       if (started) {
+               regfree(&regexNameValue);
+               regfree(&regexComment);
+               started = false;
+       }
+}
+
+static bool regexMatch(regex_t * regex, char * line, size_t nmatch, regmatch_t pmatch[]) {
+       int result = regexec(regex, line, nmatch, pmatch, 0);
+       if (!result) {
+               return true;
+       }
+
+       if (result == REG_NOMATCH) {
+               return false;
+       }
+
+       {
+               char msgbuf[256];
+               regerror(result, regex, msgbuf, sizeof(msgbuf));
+               olsr_syslog(OLSR_LOG_ERR, "Regex match failed: %s\n", msgbuf);
+       }
+
+       return false;
+}
+
+static char line[LINE_LENGTH];
+
+void readGatewaySpeedFile(char * fileName) {
+       struct stat statBuf;
+       FILE * fd = NULL;
+       unsigned int lineNumber = 0;
+       char * name = NULL;
+       char * value = NULL;
+       unsigned long uplink = DEF_UPLINK_SPEED;
+       unsigned long downlink = DEF_DOWNLINK_SPEED;
+       bool uplinkSet = false;
+       bool downlinkSet = false;
+
+       if (stat(fileName, &statBuf)) {
+               /* could not access the file */
+               goto out;
+       }
+
+       if (!memcmp(&cachedStat.st_mtim, &statBuf.st_mtim, sizeof(cachedStat.st_mtim))) {
+               /* file did not change since last read */
+               goto out;
+       }
+
+       fd = fopen(fileName, "r");
+       if (!fd) {
+               goto out;
+       }
+
+       memcpy(&cachedStat.st_mtim, &statBuf.st_mtim, sizeof(cachedStat.st_mtim));
+
+       while (fgets(line, LINE_LENGTH, fd)) {
+               regmatch_t pmatch[regexNameValuematchCount];
+
+               lineNumber++;
+
+               if (regexMatch(&regexComment, line, 0, NULL)) {
+                       continue;
+               }
+
+               if (!regexMatch(&regexNameValue, line, regexNameValuematchCount, pmatch)) {
+                       olsr_syslog(OLSR_LOG_ERR, "Gateway speed file \"%s\", line %d uses invalid syntax: %s\n", fileName, lineNumber,
+                                       line);
+                       goto out;
+               }
+
+               /* copy name/value */
+               name = &line[pmatch[1].rm_so];
+               line[pmatch[1].rm_eo] = '\0';
+               value = &line[pmatch[2].rm_so];
+               line[pmatch[2].rm_eo] = '\0';
+
+               if (!strncasecmp(GATEWAY_SPEED_UPLINK, name, sizeof(line))) {
+                       if (!readUL(GATEWAY_SPEED_UPLINK, value, &uplink)) {
+                               goto out;
+                       }
+                       uplinkSet = true;
+               } else if (!strncasecmp(GATEWAY_SPEED_DOWNLINK, name, sizeof(line))) {
+                       if (!readUL(GATEWAY_SPEED_DOWNLINK, value, &downlink)) {
+                               goto out;
+                       }
+                       downlinkSet = true;
+               } else {
+                       olsr_syslog(OLSR_LOG_ERR, "Gateway speed file \"%s\", line %d uses an invalid option \"%s\","
+                                       " valid options are [%s|%s]\n", fileName, lineNumber, name, GATEWAY_SPEED_UPLINK,
+                                       GATEWAY_SPEED_DOWNLINK);
+                       goto out;
+               }
+       }
+
+       fclose(fd);
+
+       if (uplinkSet) {
+               olsr_cnf->smart_gw_uplink = uplink;
+       }
+       if (downlinkSet) {
+               olsr_cnf->smart_gw_downlink = downlink;
+       }
+
+       out: return;
+}
diff --git a/src/gatewaySpeedFile.h b/src/gatewaySpeedFile.h
new file mode 100644 (file)
index 0000000..e50f607
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef GATEWAYSPEEDFILE_H
+#define GATEWAYSPEEDFILE_H
+
+#include "olsr.h"
+
+#define GATEWAY_SPEED_UPLINK   "upstream"
+#define GATEWAY_SPEED_DOWNLINK "downstream"
+
+bool startGatewaySpeedFile(void);
+void stopGatewaySpeedFile(void);
+void readGatewaySpeedFile(char * fileName);
+
+#endif /* GATEWAYSPEEDFILE_H */