4 #include "sgwDynSpeed.h"
21 #define SPEED_UPLINK_NAME "upstream"
22 #define SPEED_DOWNLINK_NAME "downstream"
24 /** the maximal length of a line that is read from the file */
25 #define LINE_LENGTH 256
27 /** regular expression describing a comment */
28 static const char * regexCommentString = "^([[:space:]]*|[[:space:]#]+.*)$";
30 /** regular expression describing a key/value pair */
31 static const char * regexNameValueString =
32 "^[[:space:]]*([^[:space:]]+)[[:space:]]*=[[:space:]]*(.*?)[[:space:]]*$";
34 /** the number of matches in regexNameValueString */
35 static const size_t regexNameValuematchCount = 3;
37 /** the compiled regular expression describing a comment */
38 static regex_t regexComment;
40 /** the compiled regular expression describing a key/value pair */
41 static regex_t regexNameValue;
43 /** true when the plugin has been started */
44 static bool started = false;
46 /** type to hold the cached stat result */
47 typedef struct _CachedStat {
48 time_t timeStamp; /* Time of last modification (second resolution) */
51 /** the cached stat result */
52 static CachedStat cachedStat;
55 Read an unsigned long number from a value string
60 the string to convert to a number
62 a pointer to the location where to store the number upon successful conversion
68 static bool readUL(const char * valueName, const char * value, unsigned long * valueNumber) {
70 unsigned long valueNew;
72 assert(valueName != NULL);
73 assert(value != NULL);
74 assert(valueNumber != NULL);
77 valueNew = strtoul(value, &endPtr, 10);
79 if (!((endPtr != value) && (*value != '\0') && (*endPtr == '\0'))) {
80 /* invalid conversion */
81 sgwDynSpeedError(false, "Value of parameter %s (%s) could not be converted to a number", valueName, value);
85 *valueNumber = valueNew;
91 * Strip EOL characters from a string
93 * @param str the string to strip
94 * @param index the index of the \0 string terminator (end-of-string/strlen)
96 static void stripEols(char * str, regoff_t index) {
98 while ((len > 0) && ((str[len - 1] == '\n') || (str[len - 1] == '\r'))) {
105 * Initialises the speedFile reader.
106 * @return true upon success, false otherwise
108 bool startSpeedFile(void) {
113 if (regcomp(®exComment, regexCommentString, REG_EXTENDED | REG_ICASE)) {
114 sgwDynSpeedError(false, "Could not compile regex \"%s\"", regexCommentString);
118 if (regcomp(®exNameValue, regexNameValueString, REG_EXTENDED | REG_ICASE)) {
119 sgwDynSpeedError(false, "Could not compile regex \"%s\"", regexNameValueString);
120 regfree(®exComment);
124 cachedStat.timeStamp = -1;
131 * Cleans up the speedFile reader.
133 void stopSpeedFile(void) {
135 regfree(®exNameValue);
136 regfree(®exComment);
142 * Performs a regex match
143 * @param regex the compiled regex to match against
144 * @param line the line to match
145 * @param nmatch the number of matches to produce
146 * @param pmatch the array with match information
147 * @return true upon success, false otherwise
149 static bool regexMatch(regex_t * regex, char * line, size_t nmatch, regmatch_t pmatch[]) {
150 int result = regexec(regex, line, nmatch, pmatch, 0);
155 if (result == REG_NOMATCH) {
161 regerror(result, regex, msgbuf, sizeof(msgbuf));
162 sgwDynSpeedError(false, "Regex match failed: %s", msgbuf);
168 /** the buffer in which to store a line read from the file */
169 static char line[LINE_LENGTH];
171 static bool reportedErrorsPrevious = false;
174 * Read the speed file
175 * @param fileName the filename
177 void readSpeedFile(char * fileName) {
181 unsigned int lineNumber = 0;
184 unsigned long uplink = DEF_UPLINK_SPEED;
185 unsigned long downlink = DEF_DOWNLINK_SPEED;
186 bool uplinkSet = false;
187 bool downlinkSet = false;
188 bool reportedErrors = false;
190 fd = open(fileName, O_RDONLY);
192 /* could not access the file */
196 if (fstat(fd, &statBuf)) {
197 /* could not access the file */
201 if (!memcmp(&cachedStat.timeStamp, &statBuf.st_mtime, sizeof(cachedStat.timeStamp))) {
202 /* file did not change since last read */
206 fp = fdopen(fd, "r");
211 memcpy(&cachedStat.timeStamp, &statBuf.st_mtime, sizeof(cachedStat.timeStamp));
213 while (fgets(line, LINE_LENGTH, fp)) {
214 regmatch_t pmatch[regexNameValuematchCount];
218 if (regexMatch(®exComment, line, 0, NULL)) {
222 if (!regexMatch(®exNameValue, line, regexNameValuematchCount, pmatch)) {
223 sgwDynSpeedError(false, "Gateway speed file \"%s\", line %d uses invalid syntax: ignored (%s)", fileName, lineNumber,
228 stripEols(line, pmatch[2].rm_eo);
230 /* determine name/value */
231 name = &line[pmatch[1].rm_so];
232 line[pmatch[1].rm_eo] = '\0';
233 value = &line[pmatch[2].rm_so];
234 line[pmatch[2].rm_eo] = '\0';
236 if (!strncasecmp(SPEED_UPLINK_NAME, name, sizeof(line))) {
237 if (!readUL(SPEED_UPLINK_NAME, value, &uplink)) {
238 sgwDynSpeedError(false, "Gateway speed file \"%s\", line %d: %s value \"%s\" is not a valid number: ignored",
239 fileName, lineNumber, SPEED_UPLINK_NAME, value);
240 reportedErrors = true;
244 } else if (!strncasecmp(SPEED_DOWNLINK_NAME, name, sizeof(line))) {
245 if (!readUL(SPEED_DOWNLINK_NAME, value, &downlink)) {
246 sgwDynSpeedError(false, "Gateway speed file \"%s\", line %d: %s value \"%s\" is not a valid number: ignored",
247 fileName, lineNumber, SPEED_DOWNLINK_NAME, value);
248 reportedErrors = true;
253 if (!reportedErrorsPrevious) {
254 sgwDynSpeedError(false, "Gateway speed file \"%s\", line %d specifies an unknown option \"%s\": ignored",
255 fileName, lineNumber, name);
256 reportedErrors = true;
261 reportedErrorsPrevious = reportedErrors;
267 olsr_cnf->smart_gw_uplink = uplink;
270 olsr_cnf->smart_gw_downlink = downlink;
272 if (uplinkSet || downlinkSet) {
273 refresh_smartgw_netmask();