mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
replay file.
git-svn-id: file:///svn/unbound/trunk@85 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
f6561f2f00
commit
2ebbe7e9d5
5 changed files with 296 additions and 16 deletions
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
9 February 2007: Wouter
|
||||
- replay file reading.
|
||||
|
||||
8 February 2007: Wouter
|
||||
- added tcp test.
|
||||
- replay storage.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -117,6 +118,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.
|
||||
* @param argc: arg count.
|
||||
|
|
@ -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<pass_argc; c++)
|
||||
free(pass_argv[c]);
|
||||
return res;
|
||||
|
|
|
|||
Loading…
Reference in a new issue