From: Wouter Wijngaards Date: Fri, 9 Feb 2007 13:46:11 +0000 (+0000) Subject: replay file. X-Git-Tag: release-0.0~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2ebbe7e9d50e31513d8e30f3ba39535d1095116f;p=thirdparty%2Funbound.git replay file. git-svn-id: file:///svn/unbound/trunk@85 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/configure.ac b/configure.ac index f8d48d292..ae44ee5d6 100644 --- a/configure.ac +++ b/configure.ac @@ -360,7 +360,12 @@ AC_CHECK_FUNCS([event_base_free]) # only in libevent 1.2 and later AC_CHECK_LIB(socket, socket) AC_CHECK_LIB(nsl, inet_pton) +AC_FUNC_CHOWN +AC_FUNC_FORK AC_FUNC_MALLOC +AC_TYPE_SIGNAL +AC_FUNC_FSEEKO +AC_SYS_LARGEFILE #AC_REPLACE_FUNCS(snprintf) #AC_REPLACE_FUNCS(strlcpy) @@ -434,6 +439,10 @@ AH_BOTTOM([ #else /* !HAVE_ATTR_UNUSED */ # define ATTR_UNUSED(x) x #endif /* !HAVE_ATTR_UNUSED */ +#ifndef HAVE_FSEEKO +#define fseeko fseek +#define ftello ftell +#endif /* HAVE_FSEEKO */ #include "ldns/ldns.h" diff --git a/doc/Changelog b/doc/Changelog index 607b61c7f..1036ec3e5 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,6 @@ +9 February 2007: Wouter + - replay file reading. + 8 February 2007: Wouter - added tcp test. - replay storage. diff --git a/testcode/replay.c b/testcode/replay.c index 3eb5fc4fb..82c304edf 100644 --- a/testcode/replay.c +++ b/testcode/replay.c @@ -40,14 +40,262 @@ */ #include "config.h" +#include "util/log.h" #include "testcode/replay.h" +#include "testcode/ldns-testpkts.h" + +/** max length of lines in file */ +#define MAX_LINE_LEN 10240 + +/** parse keyword in string. true if found, false if not. + * if found, the line is advanced to after the keyword. */ +static int parse_keyword(char** line, char* keyword) +{ + size_t len = (size_t)strlen(keyword); + if(strncmp(*line, keyword, len) == 0) { + *line += len; + return 1; + } + return 0; +} + +/** delete moment */ +static void +replay_moment_delete(struct replay_moment* mom) +{ + if(!mom) + return; + if(mom->match) { + delete_entry(mom->match); + } + free(mom); +} + +/** delete range */ +static void +replay_range_delete(struct replay_range* rng) +{ + if(!rng) + return; + delete_entry(rng->match); + free(rng); +} + +/** + * Read a range from file. + * @param remain: Rest of line (after RANGE keyword). + * @param in: file to read from. + * @param lineno: incremented as lines are read. + * @param line: line buffer. + * @param ttl: for readentry + * @param or: for readentry + * @param prev: for readentry + * @return: range object to add to list, or NULL on error. + */ +static struct replay_range* +replay_range_read(char* remain, FILE* in, int* lineno, char* line, + uint16_t* ttl, ldns_rdf** or, ldns_rdf** prev) +{ + struct replay_range* rng = (struct replay_range*)malloc( + sizeof(struct replay_range)); + off_t pos; + char *parse; + struct entry* entry; + if(!rng) + return NULL; + memset(rng, 0, sizeof(*rng)); + /* read time range */ + if(sscanf(remain, " %d %d", &rng->start_step, &rng->end_step)!=2) { + log_err("Could not read time range: %s", line); + free(rng); + return NULL; + } + /* read entries */ + pos = ftello(in); + while(fgets(line, MAX_LINE_LEN-1, in)) { + (*lineno)++; + parse = line; + while(isspace(*parse)) + parse++; + if(!*parse || *parse == ';') + continue; + if(parse_keyword(&parse, "RANGE_END")) { + return rng; + } + /* set position before line; read entry */ + (*lineno)--; + fseeko(in, pos, SEEK_SET); + entry = read_entry(in, "datafile", lineno, ttl, or, prev); + if(!entry) + fatal_exit("%d: bad entry", *lineno); + entry->next = rng->match; + rng->match = entry; + + pos = ftello(in); + } + replay_range_delete(rng); + return NULL; +} + +/** + * Read a replay moment 'STEP' from file. + * @param remain: Rest of line (after STEP keyword). + * @param in: file to read from. + * @param lineno: incremented as lines are read. + * @param ttl: for readentry + * @param or: for readentry + * @param prev: for readentry + * @return: range object to add to list, or NULL on error. + */ +static struct replay_moment* +replay_moment_read(char* remain, FILE* in, int* lineno, + uint16_t* ttl, ldns_rdf** or, ldns_rdf** prev) +{ + struct replay_moment* mom = (struct replay_moment*)malloc( + sizeof(struct replay_moment)); + int skip = 0; + int readentry = 0; + if(!mom) + return NULL; + memset(mom, 0, sizeof(*mom)); + if(sscanf(remain, " %d%n", &mom->time_step, &skip) != 1) { + log_err("%d: cannot read value: %s", *lineno, remain); + free(mom); + return NULL; + } + remain += skip; + while(isspace(*remain)) + remain++; + if(parse_keyword(&remain, "NOTHING")) { + mom->evt_type = repevt_nothing; + } else if(parse_keyword(&remain, "QUERY")) { + mom->evt_type = repevt_front_query; + readentry = 1; + } else if(parse_keyword(&remain, "CHECK_ANSWER")) { + mom->evt_type = repevt_front_reply; + readentry = 1; + } else if(parse_keyword(&remain, "CHECK_OUT_QUERY")) { + mom->evt_type = repevt_back_query; + readentry = 1; + } else if(parse_keyword(&remain, "REPLY")) { + mom->evt_type = repevt_back_reply; + readentry = 1; + } else if(parse_keyword(&remain, "TIMEOUT")) { + mom->evt_type = repevt_timeout; + } else if(parse_keyword(&remain, "ERROR")) { + mom->evt_type = repevt_back_query; + } else { + log_err("%d: unknown event type %s", *lineno, remain); + free(mom); + return NULL; + } + + if(readentry) { + mom->match = read_entry(in, "datafile", lineno, ttl, or, prev); + free(mom); + if(!mom->match) + return NULL; + } + + return mom; +} + +/** makes scenario with title on rest of line. */ +static struct replay_scenario* +make_scenario(char* line) +{ + struct replay_scenario* scen; + while(isspace(*line)) + line++; + if(!*line) { + log_err("scenario: no title given"); + return NULL; + } + scen = (struct replay_scenario*)malloc(sizeof(struct replay_scenario)); + if(!scen) + return NULL; + memset(scen, 0, sizeof(*scen)); + scen->title = strdup(line); + if(!scen->title) { + free(scen); + return NULL; + } + return scen; +} + struct replay_scenario* replay_scenario_read(FILE* in) { + char line[MAX_LINE_LEN]; + char *parse; + int lineno = 0; + struct replay_scenario* scen = NULL; + uint16_t ttl = 3600; + ldns_rdf* or = NULL; + ldns_rdf* prev = NULL; + line[MAX_LINE_LEN-1]=0; + + while(fgets(line, sizeof(line)-1, in)) { + parse=line; + lineno++; + while(isspace(*parse)) + parse++; + if(!*parse) + continue; /* empty line */ + if(parse_keyword(&parse, ";")) + continue; /* comment */ + if(parse_keyword(&parse, "SCENARIO_BEGIN")) { + scen = make_scenario(parse); + if(!scen) + fatal_exit("%d: could not make scen", lineno); + continue; + } + if(!scen) + fatal_exit("%d: expected SCENARIO", lineno); + if(parse_keyword(&parse, "RANGE_BEGIN")) { + struct replay_range* newr = replay_range_read( + parse, in, &lineno, line, &ttl, &or, &prev); + if(!newr) + fatal_exit("%d: bad range", lineno); + newr->next_range = scen->range_list; + scen->range_list = newr; + } else if(parse_keyword(&parse, "STEP")) { + struct replay_moment* mom = replay_moment_read( + parse, in, &lineno, &ttl, &or, &prev); + if(!mom) + fatal_exit("%d: bad moment", lineno); + if(scen->mom_last) + scen->mom_last->mom_next = mom; + else scen->mom_first = mom; + scen->mom_last = mom; + } else if(parse_keyword(&parse, "SCENARIO_END")) { + return scen; + } + } + replay_scenario_delete(scen); return NULL; } void replay_scenario_delete(struct replay_scenario* scen) { + struct replay_moment* mom, *momn; + struct replay_range* rng, *rngn; + if(!scen) + return; + if(scen->title) + free(scen->title); + mom = scen->mom_first; + while(mom) { + momn = mom->mom_next; + replay_moment_delete(mom); + mom = momn; + } + rng = scen->range_list; + while(rng) { + rngn = rng->next_range; + replay_range_delete(rng); + rng = rngn; + } + free(scen); } diff --git a/testcode/replay.h b/testcode/replay.h index 79eaf77c6..9694266e8 100644 --- a/testcode/replay.h +++ b/testcode/replay.h @@ -42,11 +42,10 @@ * File format for replay files. * * ; comment line. - * SCENARIO_BEGIN - * TITLE name_of_scenario - * RANGE start_time end_time + * SCENARIO_BEGIN name_of_scenario + * RANGE_BEGIN start_time end_time * match_entries - * END_RANGE + * RANGE_END * ; more RANGE items. * ; go to the next moment * STEP time_step event_type @@ -63,9 +62,8 @@ * * * ; Example file - * SCENARIO_BEGIN - * TITLE Example scenario - * RANGE 0 100 + * SCENARIO_BEGIN Example scenario + * RANGE_BEGIN 0 100 * ENTRY_BEGIN * ; precoded answers to queries. * ENTRY_END @@ -105,7 +103,7 @@ struct entry; */ struct replay_scenario { /** name of replay scenario. malloced string. */ - const char* title; + char* title; /** The list of replay moments. Linked list. Time increases in list. */ struct replay_moment* mom_first; @@ -133,7 +131,7 @@ struct replay_moment { * The replay time step number. Starts at 0, time is incremented * every time the fake select() is run. */ - size_t time_step; + int time_step; /** Next replay moment in list of replay moments. */ struct replay_moment* mom_next; @@ -152,7 +150,7 @@ struct replay_moment { /** test fails if query to the network does not match */ repevt_back_query, /** an error happens to outbound query */ - repevt_error, + repevt_error } evt_type; /** The sent packet must match this. Incoming events, the data. */ @@ -168,9 +166,9 @@ struct replay_moment { */ struct replay_range { /** time range when this is valid. Including start and end step. */ - size_t start_step; + int start_step; /** end step of time range. */ - size_t end_step; + int end_step; /** Matching list */ struct entry* match; diff --git a/testcode/testbound.c b/testcode/testbound.c index 3348717fd..2d276b09d 100644 --- a/testcode/testbound.c +++ b/testcode/testbound.c @@ -39,7 +39,8 @@ */ #include "config.h" -#include "ldns-testpkts.h" +#include "testcode/ldns-testpkts.h" +#include "testcode/replay.h" /** * include the main program from the unbound daemon. @@ -116,6 +117,27 @@ echo_cmdline(int argc, char* argv[]) } printf("\n"); } + +/** read playback file */ +static struct replay_scenario* +setup_playback(const char* filename) +{ + struct replay_scenario* scen = NULL; + if(filename) { + FILE *in = fopen(filename, "r"); + if(!in) { + perror(filename); + exit(1); + } + scen = replay_scenario_read(in); + fclose(in); + if(!scen) + fatal_exit("Could not read: %s", filename); + } + else fatal_exit("need a playback file (-p)"); + printf("Scenario: %s\n", scen->title); + return scen; +} /** * Main unit test program. Setup, teardown and report errors. @@ -131,7 +153,7 @@ main(int argc, char* argv[]) char* playback_file = NULL; int init_optind = optind; char* init_optarg = optarg; - struct entry* matched_answers = NULL; + struct replay_scenario* scen = NULL; printf("Start of %s testbound program.\n", PACKAGE_STRING); /* determine commandline options for the daemon */ @@ -160,8 +182,7 @@ main(int argc, char* argv[]) } /* setup test environment */ - if(playback_file) - matched_answers = read_datafile(playback_file); + scen = setup_playback(playback_file); /* init fake event backend */ pass_argv[pass_argc] = NULL; @@ -174,6 +195,7 @@ main(int argc, char* argv[]) /* run the normal daemon */ res = daemon_main(pass_argc, pass_argv); + replay_scenario_delete(scen); for(c=1; c