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