xref: /openbsd/usr.sbin/unbound/testcode/replay.h (revision 2682a17c)
1712b2f30Ssthen /*
2712b2f30Ssthen  * testcode/replay.h - store and use a replay of events for the DNS resolver.
3712b2f30Ssthen  *
4712b2f30Ssthen  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5712b2f30Ssthen  *
6712b2f30Ssthen  * This software is open source.
7712b2f30Ssthen  *
8712b2f30Ssthen  * Redistribution and use in source and binary forms, with or without
9712b2f30Ssthen  * modification, are permitted provided that the following conditions
10712b2f30Ssthen  * are met:
11712b2f30Ssthen  *
12712b2f30Ssthen  * Redistributions of source code must retain the above copyright notice,
13712b2f30Ssthen  * this list of conditions and the following disclaimer.
14712b2f30Ssthen  *
15712b2f30Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16712b2f30Ssthen  * this list of conditions and the following disclaimer in the documentation
17712b2f30Ssthen  * and/or other materials provided with the distribution.
18712b2f30Ssthen  *
19712b2f30Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20712b2f30Ssthen  * be used to endorse or promote products derived from this software without
21712b2f30Ssthen  * specific prior written permission.
22712b2f30Ssthen  *
23712b2f30Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24712b2f30Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25712b2f30Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26712b2f30Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27712b2f30Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28712b2f30Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29712b2f30Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30712b2f30Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31712b2f30Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32712b2f30Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33712b2f30Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34712b2f30Ssthen  */
35712b2f30Ssthen 
36712b2f30Ssthen /**
37712b2f30Ssthen  * \file
38712b2f30Ssthen  * Store and use a replay of events for the DNS resolver.
39712b2f30Ssthen  * Used to test known scenarios to get known outcomes.
40712b2f30Ssthen  *
41712b2f30Ssthen  * <pre>
42712b2f30Ssthen  * File format for replay files.
43712b2f30Ssthen  *
44712b2f30Ssthen  * ; unbound.conf options.
45712b2f30Ssthen  * ; ...
46712b2f30Ssthen  * ; additional commandline options to pass to unbound
47712b2f30Ssthen  * COMMANDLINE cmdline_option
48712b2f30Ssthen  * ; autotrust key file contents, also adds auto-trust-anchor-file: "x" to cfg
49712b2f30Ssthen  * AUTOTRUST_FILE id
50712b2f30Ssthen  * ; contents of that file
51712b2f30Ssthen  * AUTOTRUST_END
52712b2f30Ssthen  * ; temp file names are echoed as "tmp/xxx.fname"
53712b2f30Ssthen  * TEMPFILE_NAME fname
54712b2f30Ssthen  * ; temp file contents, inline, deleted at end of run
55712b2f30Ssthen  * TEMPFILE_CONTENTS fname
56712b2f30Ssthen  * ; contents of that file
57712b2f30Ssthen  * ; this creates $INCLUDE /tmp/xxx.fname
58712b2f30Ssthen  * $INCLUDE_TEMPFILE fname
59712b2f30Ssthen  * TEMPFILE_END
60712b2f30Ssthen  * CONFIG_END
61712b2f30Ssthen  * ; comment line.
62712b2f30Ssthen  * SCENARIO_BEGIN name_of_scenario
63712b2f30Ssthen  * RANGE_BEGIN start_time end_time
64712b2f30Ssthen  *    ; give ip of the virtual server, it matches any ip if not present.
65712b2f30Ssthen  *    ADDRESS ip_address
66712b2f30Ssthen  *    match_entries
67712b2f30Ssthen  * RANGE_END
68712b2f30Ssthen  * ; more RANGE items.
69712b2f30Ssthen  * ; go to the next moment
70712b2f30Ssthen  * STEP time_step event_type [ADDRESS ip_address]
71712b2f30Ssthen  * ; event_type can be:
72712b2f30Ssthen  *	o NOTHING - nothing
73712b2f30Ssthen  *	o QUERY - followed by entry
74712b2f30Ssthen  *	o CHECK_ANSWER - followed by entry
75712b2f30Ssthen  *	o CHECK_OUT_QUERY - followed by entry (if copy-id it is also reply).
76712b2f30Ssthen  *	o REPLY - followed by entry
77712b2f30Ssthen  *	o TIMEOUT
78712b2f30Ssthen  *	o TIME_PASSES ELAPSE [seconds] - increase 'now' time counter, can be
79712b2f30Ssthen  *		a floating point number.
80712b2f30Ssthen  *	  TIME_PASSES EVAL [macro] - expanded for seconds to move time.
81712b2f30Ssthen  *	o TRAFFIC - like CHECK_ANSWER, causes traffic to flow.
82712b2f30Ssthen  *		actually the traffic flows before this step is taken.
83712b2f30Ssthen  *		the step waits for traffic to stop.
84712b2f30Ssthen  *	o CHECK_AUTOTRUST [id] - followed by FILE_BEGIN [to match] FILE_END.
85712b2f30Ssthen  *		The file contents is macro expanded before match.
86712b2f30Ssthen  *	o CHECK_TEMPFILE [fname] - followed by FILE_BEGIN [to match] FILE_END
87712b2f30Ssthen  *	o INFRA_RTT [ip] [dp] [rtt] - update infra cache entry with rtt.
88*2682a17cSsthen  *	o FLUSH_MESSAGE name type class - flushes entry in message cache.
89*2682a17cSsthen  *	o EXPIRE_MESSAGE name type class - expires entry in message cache.
90712b2f30Ssthen  *	o ERROR
91712b2f30Ssthen  * ; following entry starts on the next line, ENTRY_BEGIN.
92712b2f30Ssthen  * ; more STEP items
93712b2f30Ssthen  * SCENARIO_END
94712b2f30Ssthen  *
95712b2f30Ssthen  * Calculations, a macro-like system: ${$myvar + 3600}
96712b2f30Ssthen  * STEP 10 ASSIGN myvar = 3600
97712b2f30Ssthen  * 	; ASSIGN event. '=' is syntactic sugar here. 3600 is some expression.
98712b2f30Ssthen  * ${..} is macro expanded from its expression.  Text substitution.
99712b2f30Ssthen  * 	o $var replaced with its value.  var is identifier [azAZ09_]*
100712b2f30Ssthen  * 	o number is that number.
101712b2f30Ssthen  * 	o ${variables and arithmetic }
102712b2f30Ssthen  * 	o +, -, / and *.  Note, evaluated left-to-right. Use ${} for brackets.
103712b2f30Ssthen  * 	  So again, no precedence rules, so 2+3*4 == ${2+3}*4 = 20.
104712b2f30Ssthen  * 	  Do 2+${3*4} to get 24.
105712b2f30Ssthen  * 	o ${function params}
106712b2f30Ssthen  *		o ${time} is the current time for the simulated unbound.
107712b2f30Ssthen  *		o ${ctime value} is the text ctime(value), Fri 3 Aug 2009, ...
108712b2f30Ssthen  *		o ${timeout} is the time until next timeout in comm_timer list.
109712b2f30Ssthen  *		o ${range lower value upper} checks if lower<=value<=upper
110712b2f30Ssthen  *			returns value if check succeeds.
111712b2f30Ssthen  *
112712b2f30Ssthen  * ; Example file
113712b2f30Ssthen  * SCENARIO_BEGIN Example scenario
114712b2f30Ssthen  * RANGE_BEGIN 0 100
115712b2f30Ssthen  *   ENTRY_BEGIN
116712b2f30Ssthen  *   ; precoded answers to queries.
117712b2f30Ssthen  *   ENTRY_END
118712b2f30Ssthen  * END_RANGE
119712b2f30Ssthen  * STEP 0 QUERY
120712b2f30Ssthen  *   ENTRY_BEGIN
121712b2f30Ssthen  *   ; query
122712b2f30Ssthen  *   ENTRY_END
123712b2f30Ssthen  * ; a query is sent out to the network by resolver.
124712b2f30Ssthen  * ; precoded answer from range is returned.
125712b2f30Ssthen  * ; algorithm will do precoded answers from RANGE immediately, except if
126712b2f30Ssthen  * ; the next step specifically checks for that OUT_QUERY.
127712b2f30Ssthen  * ; or if none of the precoded answers match.
128712b2f30Ssthen  * STEP 1 CHECK_ANSWER
129712b2f30Ssthen  *   ENTRY_BEGIN
130712b2f30Ssthen  *   ; what the reply should look like
131712b2f30Ssthen  *   ENTRY_END
132712b2f30Ssthen  * ; successful termination. (if the answer was OK).
133712b2f30Ssthen  * ; also, all answers must have been checked with CHECK_ANSWER.
134712b2f30Ssthen  * ; and, no more pending out_queries (that have not been checked).
135712b2f30Ssthen  * SCENARIO_END
136712b2f30Ssthen  *
137712b2f30Ssthen  * </pre>
138712b2f30Ssthen  */
139712b2f30Ssthen 
140712b2f30Ssthen #ifndef TESTCODE_REPLAY_H
141712b2f30Ssthen #define TESTCODE_REPLAY_H
142712b2f30Ssthen #include "util/netevent.h"
143712b2f30Ssthen #include "testcode/testpkts.h"
144712b2f30Ssthen #include "util/rbtree.h"
145712b2f30Ssthen struct replay_answer;
146712b2f30Ssthen struct replay_moment;
147712b2f30Ssthen struct replay_range;
148712b2f30Ssthen struct fake_pending;
149712b2f30Ssthen struct fake_timer;
150712b2f30Ssthen struct replay_var;
151712b2f30Ssthen struct infra_cache;
152712b2f30Ssthen struct sldns_buffer;
153*2682a17cSsthen struct daemon;
154712b2f30Ssthen 
155712b2f30Ssthen /**
156712b2f30Ssthen  * A replay scenario.
157712b2f30Ssthen  */
158712b2f30Ssthen struct replay_scenario {
159712b2f30Ssthen 	/** name of replay scenario. malloced string. */
160712b2f30Ssthen 	char* title;
161712b2f30Ssthen 
162712b2f30Ssthen 	/** The list of replay moments. Linked list. Time increases in list. */
163712b2f30Ssthen 	struct replay_moment* mom_first;
164712b2f30Ssthen 	/** The last element in list of replay moments. */
165712b2f30Ssthen 	struct replay_moment* mom_last;
166712b2f30Ssthen 
167712b2f30Ssthen 	/**
168712b2f30Ssthen 	 * List of matching answers. This is to ease replay scenario
169712b2f30Ssthen 	 * creation. It lists queries (to the network) and what answer
170712b2f30Ssthen 	 * should be returned. The matching answers are valid for a range
171712b2f30Ssthen 	 * of time steps.
172712b2f30Ssthen 	 * So: timestep, parts of query, destination --> answer.
173712b2f30Ssthen 	 */
174712b2f30Ssthen 	struct replay_range* range_list;
175712b2f30Ssthen };
176712b2f30Ssthen 
177712b2f30Ssthen /**
178712b2f30Ssthen  * A replay moment.
179712b2f30Ssthen  * Basically, it consists of events to a fake select() call.
180712b2f30Ssthen  * This is a recording of an event that happens.
181712b2f30Ssthen  * And if output is presented, what is done with that.
182712b2f30Ssthen  */
183712b2f30Ssthen struct replay_moment {
184712b2f30Ssthen 	/**
185712b2f30Ssthen 	 * The replay time step number. Starts at 0, time is incremented
186712b2f30Ssthen 	 * every time the fake select() is run.
187712b2f30Ssthen 	 */
188712b2f30Ssthen 	int time_step;
189712b2f30Ssthen 	/** Next replay moment in list of replay moments. */
190712b2f30Ssthen 	struct replay_moment* mom_next;
191712b2f30Ssthen 
192712b2f30Ssthen 	/** what happens this moment? */
193712b2f30Ssthen 	enum replay_event_type {
194712b2f30Ssthen 		/** nothing happens, as if this event is not there. */
195712b2f30Ssthen 		repevt_nothing,
196712b2f30Ssthen 		/** incoming query */
197712b2f30Ssthen 		repevt_front_query,
198712b2f30Ssthen 		/** test fails if reply to query does not match */
199712b2f30Ssthen 		repevt_front_reply,
200712b2f30Ssthen 		/** timeout */
201712b2f30Ssthen 		repevt_timeout,
202712b2f30Ssthen 		/** time passes */
203712b2f30Ssthen 		repevt_time_passes,
204712b2f30Ssthen 		/** reply arrives from the network */
205712b2f30Ssthen 		repevt_back_reply,
206712b2f30Ssthen 		/** test fails if query to the network does not match */
207712b2f30Ssthen 		repevt_back_query,
208712b2f30Ssthen 		/** check autotrust key file */
209712b2f30Ssthen 		repevt_autotrust_check,
210712b2f30Ssthen 		/** check a temp file */
211712b2f30Ssthen 		repevt_tempfile_check,
212712b2f30Ssthen 		/** an error happens to outbound query */
213712b2f30Ssthen 		repevt_error,
214712b2f30Ssthen 		/** assignment to a variable */
215712b2f30Ssthen 		repevt_assign,
216712b2f30Ssthen 		/** store infra rtt cache entry: addr and string (int) */
217712b2f30Ssthen 		repevt_infra_rtt,
218*2682a17cSsthen 		/** flush message cache entry */
219*2682a17cSsthen 		repevt_flush_message,
220*2682a17cSsthen 		/** expire message cache entry */
221*2682a17cSsthen 		repevt_expire_message,
222712b2f30Ssthen 		/** cause traffic to flow */
223712b2f30Ssthen 		repevt_traffic
224712b2f30Ssthen 	}
225712b2f30Ssthen 		/** variable with what is to happen this moment */
226712b2f30Ssthen 		evt_type;
227712b2f30Ssthen 
228712b2f30Ssthen 	/** The sent packet must match this. Incoming events, the data. */
229712b2f30Ssthen 	struct entry* match;
230712b2f30Ssthen 
231712b2f30Ssthen 	/** the amount of time that passes */
232712b2f30Ssthen 	struct timeval elapse;
233712b2f30Ssthen 
234712b2f30Ssthen 	/** address that must be matched, or packet remote host address. */
235712b2f30Ssthen 	struct sockaddr_storage addr;
236712b2f30Ssthen 	/** length of addr, if 0, then any address will do */
237712b2f30Ssthen 	socklen_t addrlen;
238712b2f30Ssthen 
239712b2f30Ssthen 	/** macro name, for assign. */
240712b2f30Ssthen 	char* variable;
241712b2f30Ssthen 	/** string argument, for assign. */
242712b2f30Ssthen 	char* string;
243712b2f30Ssthen 
244712b2f30Ssthen 	/** the autotrust file id to check */
245712b2f30Ssthen 	char* autotrust_id;
246712b2f30Ssthen 	/** file contents to match, one string per line */
247712b2f30Ssthen 	struct config_strlist* file_content;
248712b2f30Ssthen };
249712b2f30Ssthen 
250712b2f30Ssthen /**
251712b2f30Ssthen  * Range of timesteps, and canned replies to matching queries.
252712b2f30Ssthen  */
253712b2f30Ssthen struct replay_range {
254712b2f30Ssthen 	/** time range when this is valid. Including start and end step. */
255712b2f30Ssthen 	int start_step;
256712b2f30Ssthen 	/** end step of time range. */
257712b2f30Ssthen 	int end_step;
258712b2f30Ssthen 	/** address of where this range is served. */
259712b2f30Ssthen 	struct sockaddr_storage addr;
260712b2f30Ssthen 	/** length of addr, if 0, then any address will do */
261712b2f30Ssthen 	socklen_t addrlen;
262712b2f30Ssthen 
263712b2f30Ssthen 	/** Matching list */
264712b2f30Ssthen 	struct entry* match;
265712b2f30Ssthen 
266712b2f30Ssthen 	/** next in list of time ranges. */
267712b2f30Ssthen 	struct replay_range* next_range;
268712b2f30Ssthen };
269712b2f30Ssthen 
270712b2f30Ssthen /**
271712b2f30Ssthen  * Replay storage of runtime information.
272712b2f30Ssthen  */
273712b2f30Ssthen struct replay_runtime {
274712b2f30Ssthen 	/**
275712b2f30Ssthen 	 * The scenario
276712b2f30Ssthen 	 */
277712b2f30Ssthen 	struct replay_scenario* scenario;
278712b2f30Ssthen 	/**
279712b2f30Ssthen 	 * Current moment.
280712b2f30Ssthen 	 */
281712b2f30Ssthen 	struct replay_moment* now;
282712b2f30Ssthen 
283712b2f30Ssthen 	/**
284712b2f30Ssthen 	 * List of pending queries in order they were sent out. First
285712b2f30Ssthen 	 * one has been sent out most recently. Last one in list is oldest.
286712b2f30Ssthen 	 */
287712b2f30Ssthen 	struct fake_pending* pending_list;
288712b2f30Ssthen 
289712b2f30Ssthen 	/**
290712b2f30Ssthen 	 * List of answers to queries from clients. These need to be checked.
291712b2f30Ssthen 	 */
292712b2f30Ssthen 	struct replay_answer* answer_list;
293712b2f30Ssthen 
294712b2f30Ssthen 	/** last element in answer list. */
295712b2f30Ssthen 	struct replay_answer* answer_last;
296712b2f30Ssthen 
297712b2f30Ssthen 	/** list of fake timer callbacks that are pending */
298712b2f30Ssthen 	struct fake_timer* timer_list;
299712b2f30Ssthen 
300712b2f30Ssthen 	/** callback to call for incoming queries */
301712b2f30Ssthen 	comm_point_callback_type* callback_query;
302712b2f30Ssthen 	/** user argument for incoming query callback */
303712b2f30Ssthen 	void *cb_arg;
304712b2f30Ssthen 
305712b2f30Ssthen 	/** ref the infra cache (was passed to outside_network_create) */
306712b2f30Ssthen 	struct infra_cache* infra;
307*2682a17cSsthen 	/** the daemon structure passed in worker call to remote accept open */
308*2682a17cSsthen 	struct daemon* daemon;
309712b2f30Ssthen 
310712b2f30Ssthen 	/** the current time in seconds */
311712b2f30Ssthen 	time_t now_secs;
312712b2f30Ssthen 	/** the current time in microseconds */
313712b2f30Ssthen 	struct timeval now_tv;
314712b2f30Ssthen 
3157bc20e6dSsthen 	/** has TCP connection seen a keepalive? */
3167bc20e6dSsthen 	int tcp_seen_keepalive;
3177bc20e6dSsthen 
318712b2f30Ssthen 	/** signal handler callback */
319712b2f30Ssthen 	void (*sig_cb)(int, void*);
320712b2f30Ssthen 	/** signal handler user arg */
321712b2f30Ssthen 	void *sig_cb_arg;
322712b2f30Ssthen 	/** time to exit cleanly */
323712b2f30Ssthen 	int exit_cleanly;
324712b2f30Ssthen 
325712b2f30Ssthen 	/** size of buffers */
326712b2f30Ssthen 	size_t bufsize;
327712b2f30Ssthen 
328712b2f30Ssthen 	/**
329712b2f30Ssthen 	 * Tree of macro values. Of type replay_var
330712b2f30Ssthen 	 */
331712b2f30Ssthen 	rbtree_type* vars;
332712b2f30Ssthen };
333712b2f30Ssthen 
334712b2f30Ssthen /**
335712b2f30Ssthen  * Pending queries to network, fake replay version.
336712b2f30Ssthen  */
337712b2f30Ssthen struct fake_pending {
338712b2f30Ssthen 	/** what is important only that we remember the query, copied here. */
339712b2f30Ssthen 	struct sldns_buffer* buffer;
340712b2f30Ssthen 	/** and to what address this is sent to. */
341712b2f30Ssthen 	struct sockaddr_storage addr;
342712b2f30Ssthen 	/** len of addr */
343712b2f30Ssthen 	socklen_t addrlen;
344712b2f30Ssthen 	/** zone name, uncompressed wire format (as used when sent) */
345712b2f30Ssthen 	uint8_t* zone;
346712b2f30Ssthen 	/** length of zone name */
347712b2f30Ssthen 	size_t zonelen;
348712b2f30Ssthen 	/** qtype */
349712b2f30Ssthen 	int qtype;
350712b2f30Ssthen 	/** The callback function to call when answer arrives (or timeout) */
351712b2f30Ssthen 	comm_point_callback_type* callback;
352712b2f30Ssthen 	/** callback user argument */
353712b2f30Ssthen 	void* cb_arg;
354712b2f30Ssthen 	/** original timeout in seconds from 'then' */
355712b2f30Ssthen 	int timeout;
356712b2f30Ssthen 
357712b2f30Ssthen 	/** next in pending list */
358712b2f30Ssthen 	struct fake_pending* next;
359712b2f30Ssthen 	/** the buffer parsed into a sldns_pkt */
360712b2f30Ssthen 	uint8_t* pkt;
361712b2f30Ssthen 	size_t pkt_len;
362712b2f30Ssthen 	/** by what transport was the query sent out */
363712b2f30Ssthen 	enum transport_type transport;
364712b2f30Ssthen 	/** if this is a serviced query */
365712b2f30Ssthen 	int serviced;
366712b2f30Ssthen 	/** if we are handling a multi pkt tcp stream, non 0 and the pkt nr*/
367712b2f30Ssthen 	int tcp_pkt_counter;
368712b2f30Ssthen 	/** the runtime structure this is part of */
369712b2f30Ssthen 	struct replay_runtime* runtime;
370712b2f30Ssthen };
371712b2f30Ssthen 
372712b2f30Ssthen /**
373712b2f30Ssthen  * An answer that is pending to happen.
374712b2f30Ssthen  */
375712b2f30Ssthen struct replay_answer {
376712b2f30Ssthen 	/** Next in list */
377712b2f30Ssthen 	struct replay_answer* next;
378712b2f30Ssthen 	/** reply information */
379712b2f30Ssthen 	struct comm_reply repinfo;
380712b2f30Ssthen 	/** the answer preparsed as ldns pkt */
381712b2f30Ssthen 	uint8_t* pkt;
382712b2f30Ssthen 	size_t pkt_len;
383712b2f30Ssthen };
384712b2f30Ssthen 
385712b2f30Ssthen /**
386712b2f30Ssthen  * Timers with callbacks, fake replay version.
387712b2f30Ssthen  */
388712b2f30Ssthen struct fake_timer {
389712b2f30Ssthen 	/** next in list */
390712b2f30Ssthen 	struct fake_timer* next;
391712b2f30Ssthen 	/** the runtime structure this is part of */
392712b2f30Ssthen 	struct replay_runtime* runtime;
393712b2f30Ssthen 	/** the callback to call */
394712b2f30Ssthen 	void (*cb)(void*);
395712b2f30Ssthen 	/** the callback user argument */
396712b2f30Ssthen 	void* cb_arg;
397712b2f30Ssthen 	/** if timer is enabled */
398712b2f30Ssthen 	int enabled;
399712b2f30Ssthen 	/** when the timer expires */
400712b2f30Ssthen 	struct timeval tv;
401712b2f30Ssthen };
402712b2f30Ssthen 
403712b2f30Ssthen /**
404712b2f30Ssthen  * Replay macro variable.  And its value.
405712b2f30Ssthen  */
406712b2f30Ssthen struct replay_var {
407712b2f30Ssthen 	/** rbtree node. Key is this structure. Sorted by name. */
408712b2f30Ssthen 	rbnode_type node;
409712b2f30Ssthen 	/** the variable name */
410712b2f30Ssthen 	char* name;
411712b2f30Ssthen 	/** the variable value */
412712b2f30Ssthen 	char* value;
413712b2f30Ssthen };
414712b2f30Ssthen 
415712b2f30Ssthen /**
416712b2f30Ssthen  * Read a replay scenario from the file.
417712b2f30Ssthen  * @param in: file to read from.
418712b2f30Ssthen  * @param name: name to print in errors.
419712b2f30Ssthen  * @param lineno: incremented for every line read.
420712b2f30Ssthen  * @return: Scenario. NULL if no scenario read.
421712b2f30Ssthen  */
422712b2f30Ssthen struct replay_scenario* replay_scenario_read(FILE* in, const char* name,
423712b2f30Ssthen 	int* lineno);
424712b2f30Ssthen 
425712b2f30Ssthen /**
426712b2f30Ssthen  * Delete scenario.
427712b2f30Ssthen  * @param scen: to delete.
428712b2f30Ssthen  */
429712b2f30Ssthen void replay_scenario_delete(struct replay_scenario* scen);
430712b2f30Ssthen 
431712b2f30Ssthen /** compare two replay_vars */
432712b2f30Ssthen int replay_var_compare(const void* a, const void* b);
433712b2f30Ssthen 
434712b2f30Ssthen /** get oldest enabled fake timer */
435712b2f30Ssthen struct fake_timer* replay_get_oldest_timer(struct replay_runtime* runtime);
436712b2f30Ssthen 
437a6cc1574Ssthen /** strip whitespace from end of string */
438a6cc1574Ssthen void strip_end_white(char* p);
439a6cc1574Ssthen 
440712b2f30Ssthen /**
441712b2f30Ssthen  * Create variable storage
442712b2f30Ssthen  * @return new or NULL on failure.
443712b2f30Ssthen  */
444712b2f30Ssthen rbtree_type* macro_store_create(void);
445712b2f30Ssthen 
446712b2f30Ssthen /**
447712b2f30Ssthen  * Delete variable storage
448712b2f30Ssthen  * @param store: the macro storage to free up.
449712b2f30Ssthen  */
450712b2f30Ssthen void macro_store_delete(rbtree_type* store);
451712b2f30Ssthen 
452712b2f30Ssthen /**
453712b2f30Ssthen  * Apply macro substitution to string.
454712b2f30Ssthen  * @param store: variable store.
455712b2f30Ssthen  * @param runtime: the runtime to look up values as needed.
456712b2f30Ssthen  * @param text: string to work on.
457712b2f30Ssthen  * @return newly malloced string with result.
458712b2f30Ssthen  */
459712b2f30Ssthen char* macro_process(rbtree_type* store, struct replay_runtime* runtime,
460712b2f30Ssthen 	char* text);
461712b2f30Ssthen 
462712b2f30Ssthen /**
463712b2f30Ssthen  * Look up a macro value. Like calling ${$name}.
464712b2f30Ssthen  * @param store: variable store
465712b2f30Ssthen  * @param name: macro name
466712b2f30Ssthen  * @return newly malloced string with result or strdup("") if not found.
467712b2f30Ssthen  * 	or NULL on malloc failure.
468712b2f30Ssthen  */
469712b2f30Ssthen char* macro_lookup(rbtree_type* store, char* name);
470712b2f30Ssthen 
471712b2f30Ssthen /**
472712b2f30Ssthen  * Set macro value.
473712b2f30Ssthen  * @param store: variable store
474712b2f30Ssthen  * @param name: macro name
475712b2f30Ssthen  * @param value: text to set it to.  Not expanded.
476712b2f30Ssthen  * @return false on failure.
477712b2f30Ssthen  */
478712b2f30Ssthen int macro_assign(rbtree_type* store, char* name, char* value);
479712b2f30Ssthen 
480712b2f30Ssthen /** Print macro variables stored as debug info */
481712b2f30Ssthen void macro_print_debug(rbtree_type* store);
482712b2f30Ssthen 
483712b2f30Ssthen /** testbounds self test */
484712b2f30Ssthen void testbound_selftest(void);
485712b2f30Ssthen 
486712b2f30Ssthen #endif /* TESTCODE_REPLAY_H */
487