sgw: do not write uplink/downlink speed directly
[olsrd.git] / lib / sgwdynspeed / src / speedFile.c
index 69f461d..0937da2 100644 (file)
@@ -5,9 +5,12 @@
 
 /* OLSRD includes */
 #include "olsr_cfg.h"
+#include "gateway.h"
 
 /* System includes */
 #include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <regex.h>
 #include <errno.h>
@@ -26,7 +29,7 @@ static const char * regexCommentString = "^([[:space:]]*|[[:space:]#]+.*)$";
 
 /** regular expression describing a key/value pair */
 static const char * regexNameValueString =
-               "^[[:space:]]*([^[:space:]]+)[[:space:]]*=[[:space:]]*([[:digit:]]+)[[:space:]]*$";
+               "^[[:space:]]*([^[:space:]]+)[[:space:]]*=[[:space:]]*(.*?)[[:space:]]*$";
 
 /** the number of matches in regexNameValueString */
 static const size_t regexNameValuematchCount = 3;
@@ -73,7 +76,7 @@ static bool readUL(const char * valueName, const char * value, unsigned long * v
        errno = 0;
        valueNew = strtoul(value, &endPtr, 10);
 
-       if (!((endPtr != value) && (*value != '\0') && (*endPtr == '\0'))) {
+       if (!((endPtr != value) && (*value != '\0') && (*endPtr == '\0')) || (errno == ERANGE)) {
                /* invalid conversion */
                sgwDynSpeedError(false, "Value of parameter %s (%s) could not be converted to a number", valueName, value);
                return false;
@@ -84,6 +87,20 @@ static bool readUL(const char * valueName, const char * value, unsigned long * v
        return true;
 }
 
+/**
+ * Strip EOL characters from a string
+ *
+ * @param str the string to strip
+ * @param endindex the index of the \0 string terminator (end-of-string/strlen)
+ */
+static void stripEols(char * str, regoff_t endindex) {
+  regoff_t len = endindex;
+  while ((len > 0) && ((str[len - 1] == '\n') || (str[len - 1] == '\r'))) {
+    len--;
+  }
+  str[len] = '\0';
+}
+
 /**
  * Initialises the speedFile reader.
  * @return true upon success, false otherwise
@@ -151,13 +168,16 @@ static bool regexMatch(regex_t * regex, char * line, size_t nmatch, regmatch_t p
 /** the buffer in which to store a line read from the file */
 static char line[LINE_LENGTH];
 
+static bool reportedErrorsPrevious = false;
+
 /**
  * Read the speed file
  * @param fileName the filename
  */
 void readSpeedFile(char * fileName) {
+       int fd;
        struct stat statBuf;
-       FILE * fd = NULL;
+       FILE * fp = NULL;
        unsigned int lineNumber = 0;
        char * name = NULL;
        char * value = NULL;
@@ -165,8 +185,15 @@ void readSpeedFile(char * fileName) {
        unsigned long downlink = DEF_DOWNLINK_SPEED;
        bool uplinkSet = false;
        bool downlinkSet = false;
+       bool reportedErrors = false;
+
+       fd = open(fileName, O_RDONLY);
+       if (fd < 0) {
+               /* could not access the file */
+               goto out;
+       }
 
-       if (stat(fileName, &statBuf)) {
+       if (fstat(fd, &statBuf)) {
                /* could not access the file */
                goto out;
        }
@@ -176,14 +203,14 @@ void readSpeedFile(char * fileName) {
                goto out;
        }
 
-       fd = fopen(fileName, "r");
-       if (!fd) {
+       fp = fdopen(fd, "r");
+       if (!fp) {
                goto out;
        }
 
        memcpy(&cachedStat.timeStamp, &statBuf.st_mtime, sizeof(cachedStat.timeStamp));
 
-       while (fgets(line, LINE_LENGTH, fd)) {
+       while (fgets(line, LINE_LENGTH, fp)) {
                regmatch_t pmatch[regexNameValuematchCount];
 
                lineNumber++;
@@ -193,11 +220,13 @@ void readSpeedFile(char * fileName) {
                }
 
                if (!regexMatch(&regexNameValue, line, regexNameValuematchCount, pmatch)) {
-                       sgwDynSpeedError(false, "Gateway speed file \"%s\", line %d uses invalid syntax: %s", fileName, lineNumber,
+                       sgwDynSpeedError(false, "Gateway speed file \"%s\", line %d uses invalid syntax: ignored (%s)", fileName, lineNumber,
                                        line);
-                       goto out;
+                       continue;
                }
 
+               stripEols(line, pmatch[2].rm_eo);
+
                /* determine name/value */
                name = &line[pmatch[1].rm_so];
                line[pmatch[1].rm_eo] = '\0';
@@ -206,29 +235,45 @@ void readSpeedFile(char * fileName) {
 
                if (!strncasecmp(SPEED_UPLINK_NAME, name, sizeof(line))) {
                        if (!readUL(SPEED_UPLINK_NAME, value, &uplink)) {
-                               goto out;
+                               sgwDynSpeedError(false, "Gateway speed file \"%s\", line %d: %s value \"%s\" is not a valid number: ignored",
+                                       fileName, lineNumber, SPEED_UPLINK_NAME, value);
+                               reportedErrors = true;
+                       } else {
+                               uplinkSet = true;
                        }
-                       uplinkSet = true;
                } else if (!strncasecmp(SPEED_DOWNLINK_NAME, name, sizeof(line))) {
                        if (!readUL(SPEED_DOWNLINK_NAME, value, &downlink)) {
-                               goto out;
+                               sgwDynSpeedError(false, "Gateway speed file \"%s\", line %d: %s value \"%s\" is not a valid number: ignored",
+                                       fileName, lineNumber, SPEED_DOWNLINK_NAME, value);
+                               reportedErrors = true;
+                       } else {
+                               downlinkSet = true;
                        }
-                       downlinkSet = true;
                } else {
-                       sgwDynSpeedError(false, "Gateway speed file \"%s\", line %d uses an invalid option \"%s\","
-                                       " valid options are [%s|%s]", fileName, lineNumber, name, SPEED_UPLINK_NAME, SPEED_DOWNLINK_NAME);
-                       goto out;
+                 if (!reportedErrorsPrevious) {
+                   sgwDynSpeedError(false, "Gateway speed file \"%s\", line %d specifies an unknown option \"%s\": ignored",
+                       fileName, lineNumber, name);
+                   reportedErrors = true;
+                 }
                }
        }
 
-       fclose(fd);
+       reportedErrorsPrevious = reportedErrors;
+
+       fclose(fp);
+       fp = NULL;
 
        if (uplinkSet) {
-               olsr_cnf->smart_gw_uplink = uplink;
+         smartgw_set_uplink(olsr_cnf, uplink);
        }
        if (downlinkSet) {
-               olsr_cnf->smart_gw_downlink = downlink;
+         smartgw_set_downlink(olsr_cnf, downlink);
+       }
+       if (uplinkSet || downlinkSet) {
+         refresh_smartgw_netmask();
        }
 
-       out: return;
+       out: if (fd >= 0) {
+               close(fd);
+       }
 }