/* * Active Router Transport Protocol (ARTP) implementation * Copyright (c) 2004, Tomas Rebok * All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the "BSD License" which is * distributed with the software in the file LICENSE. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the BSD * License for more details. */ /** @file * @c ARTP library for reading and setting @c ARTP main settings. * @author Tomas Rebok * @date 2004 */ #include #include #include #include #include "setting.h" #include "options.h" #include "errors.h" #include "config.h" /** Initial maximum segment size */ #define INITIAL_MSS 2048 /** Initial expiration time (in microseconds) */ #define INITIAL_EXP_TIME 10000000 /** initial retransmit timeout (in seconds) */ #define INITIAL_RTO_TIME 3 /** initial maximal send buffers size. When set to 0, buffer size will be * unlimited. (in bytes) */ #define INITIAL_SBUFFERS_MAX_SIZE 0 /** initial maximal receive buffers size. When set to 0, buffer size will be * unlimited. (in bytes) */ #define INITIAL_RBUFFERS_MAX_SIZE 0 /** initial random early detection (R.E.D.) limit. This limit says when we * want to applicate random packet dropping. It has no sense when maximal * count is unlimited. When it's set to 0 or it's greater than maximal * receive buffer size, it's not applied (buffer works as usual tail drop * buffer). */ #define INITIAL_RBUFFERS_RED_LIMIT 0 /** initial R.E.D. dropping probability (in percent) */ #define DEFAULT_RED_DROP_PROBABILITY 20 /** default timeout for retransmissions (maximal time for tries) * (in seconds) */ #define DEFAULT_RETRIES_TIMEOUT 15 /** initial maximal sequence numbers count in one acknowledgement packet */ #define DEFAULT_MAX_ACKS_COUNT 50 int setting_set_defaults(void) { /* set default setting */ global_setting.initial_mss = INITIAL_MSS; global_setting.initial_exp_time = INITIAL_EXP_TIME; global_setting.initial_rto_time = INITIAL_RTO_TIME; global_setting.initial_sbuffers_max_size = INITIAL_SBUFFERS_MAX_SIZE; global_setting.initial_rbuffers_max_size = INITIAL_RBUFFERS_MAX_SIZE; global_setting.initial_rbuffers_red_limit = INITIAL_RBUFFERS_RED_LIMIT; global_setting.default_red_drop_probability = DEFAULT_RED_DROP_PROBABILITY; global_setting.default_retries_timeout = DEFAULT_RETRIES_TIMEOUT; global_setting.default_max_acks_count = DEFAULT_MAX_ACKS_COUNT; return 0; } /** Parse given line. * This function parses given line - it searches a parameter identifier * (it's set to upper case) and its value. Pointers to both strings are * returned. It detects syntax errors, too. * * @param line * the pointer to the space where the line is stored * (must end with '\0' character!) * * @param parameter * the relevant pointer which will be moved to the place where the * parameter identifier is stored. * * @param value * the relevant pointer which will be moved to the place where the * parameter value is stored. * * @param opt_value * the relevant pointer which will be moved to the place where the * option value is stored (as you can see, it's used for options only. * * @return zero * success. * * @return nonzero * related error code if some syntax error was found (for further * information see documentation of file @c errors.h). */ static int parse_line(char *line, char **parameter, char **value, char **opt_value) { int line_length = 0; int position = 0; enum Treading_action { STARTING, PARAMETER_READING, SPACE, VALUE_READING, ENDING } action; /* find out the length of given line */ line_length = strlen(line); action = STARTING; /* parse it */ while (position < line_length) { /* skip white characters */ if ((isspace(line[position])) && ((action == STARTING) || (action == SPACE) || (action == ENDING))) { position++; continue; } switch (action) { case STARTING: /* is it a comment line? */ if (line[position] == '#') return 1; action = PARAMETER_READING; *parameter = &line[position]; /* here cannot be break! */ case PARAMETER_READING: /* set current character to its upper case */ line[position] = toupper(line[position]); /* when detected white space, the parameter is whole read */ if (isspace(line[position])) { line[position] = '\0'; action = SPACE; } break; case SPACE: /* all white characters were skipped! Now we have the first * character of value. */ action = VALUE_READING; *value = &line[position]; *opt_value = &line[position]; break; case VALUE_READING: /* detect the options value */ if (line[position] == '=') { line[position] = '\0'; *opt_value = &line[position + 1]; } /* detect the end of value */ if (isspace(line[position])) { line[position] = '\0'; action = ENDING; } break; case ENDING: /* check if there're any other non-white characters (except * comments. */ if (line[position] == '#') return 0; else return E_SYNTAX_ERROR; } position++; } if (action == ENDING) return 0; /* reading was correct */ else if (action == STARTING) return 1; /* empty line */ else return E_SYNTAX_ERROR; /* incomplete line */ } int setting_read_file(char *filename) { FILE *config_file; char line[MAX_CONFIG_LINE_LENGTH]; char *parameter; char *value; char *opt_value; char *endptr; int retval; int using; /* open given file */ config_file = fopen(filename, "r"); /* there was an error while opening given file. Exit. */ if (config_file == NULL) return E_OPENING_FILE; /* read all its lines and parse them */ while (fgets(line, MAX_CONFIG_LINE_LENGTH, config_file) != NULL) { if ((retval = parse_line(line, ¶meter, &value, &opt_value)) == 0) { /* line is correct */ endptr = value; /* find out which parameter does it obtain and check its value */ if (strcmp(parameter, "INITIAL_MSS") == 0) { global_setting.initial_mss = strtol(value, &endptr, 10); if (global_setting.initial_mss <= 0) return E_BAD_VALUE; } else if (strcmp(parameter, "INITIAL_EXP_TIME") == 0) { global_setting.initial_exp_time = strtol(value, &endptr, 10); if (global_setting.initial_exp_time < 0) return E_BAD_VALUE; } else if (strcmp(parameter, "INITIAL_RTO_TIME") == 0) { global_setting.initial_rto_time = strtod(value, &endptr); if (global_setting.initial_rto_time <= 0) return E_BAD_VALUE; } else if (strcmp(parameter, "INITIAL_SBUFFERS_MAX_SIZE") == 0) { global_setting.initial_sbuffers_max_size = strtol(value, &endptr, 10); if (global_setting.initial_sbuffers_max_size < 0) return E_BAD_VALUE; } else if (strcmp(parameter, "INITIAL_RBUFFERS_MAX_SIZE") == 0) { global_setting.initial_rbuffers_max_size = strtol(value, &endptr, 10); if (global_setting.initial_rbuffers_max_size < 0) return E_BAD_VALUE; } else if (strcmp(parameter, "INITIAL_RBUFFERS_RED_LIMIT") == 0) { global_setting.initial_rbuffers_red_limit = strtol(value, &endptr, 10); if (global_setting.initial_rbuffers_red_limit < 0) return E_BAD_VALUE; } else if (strcmp(parameter, "DEFAULT_RED_DROP_PROBABILITY") == 0) { global_setting.default_red_drop_probability = strtol(value, &endptr, 10); if (global_setting.default_red_drop_probability < 0) return E_BAD_VALUE; } else if (strcmp(parameter, "DEFAULT_RETRIES_TIMEOUT") == 0) { global_setting.default_retries_timeout = strtol(value, &endptr, 10); if (global_setting.default_retries_timeout <= 0) return E_BAD_VALUE; } else if (strcmp(parameter, "DEFAULT_MAX_ACKS_COUNT") == 0) { global_setting.default_max_acks_count = strtol(value, &endptr, 10); if (global_setting.default_max_acks_count <= 0) return E_BAD_VALUE; } else if (strcmp(parameter, "OPTION") == 0) { if (value[0] == '!') { using = 0; value += 1; } else using = 1; retval = set_global_option(value, opt_value, using); if (retval != 0) return E_BAD_VALUE; endptr = opt_value - 1; } if (endptr[0] != '\0') { return E_SYNTAX_ERROR; } } else if (retval < 0) return retval; } /* close given file */ fclose(config_file); return 0; } /* vim: set ts=4 : */