/******************************************/ /* runtest.c 0.3.5 (1999-Dec-20-Mon) */ /* Adam M. Costello */ /******************************************/ /* Runs a single test chosen by the first command-line argument */ /* and prints a one-line human-readable result to stdout. */ /* This is ANSI C plus POSIX code. */ #define _POSIX_SOURCE #include #include #include #include #include #include #include #include "deliver_packet.h" #include "network.h" #include "network_config.h" #include "random.h" #include "streamers.h" #include "timer.h" #include "timer_expire.h" #include "transport.h" #include "warnf.h" enum { default_seed = 17051 }; static struct network_address source_address, sink_address; static struct network_path_parameters net_params; static struct network_bottleneck_parameters bottle_params; static struct streamer_parameters source_params, sink_params; static size_t source_buffer_max, sink_buffer_max; static int flow_control_efficiency, multiplexing, congestion_control, check_buffer_max, check_forbidden; static unsigned char forbidden[4]; static double misroute_prob, start, finish; static void setup_short(void) { enum transport_extension_flags extensions; source_address.length = 1; source_address.address[0] = 1; sink_address.length = 1; sink_address.address[0] = 2; net_params.max_payload_length = 556; net_params.bit_error_rate = 0.0; net_params.drop_probability = 0.0; net_params.duplicate_probability = 0.0; net_params.delay_constant = 0.01; net_params.delay_per_bit = 0.0; net_params.delay_random_max = 0.0; bottle_params.packet_cost = 1.0; bottle_params.payload_byte_cost = 0.0; bottle_params.budget = 0.0; source_params.total_bytes = 10000; source_params.seed = default_seed; source_params.rate = 8000.0; source_params.burst_min = 100; source_params.burst_max = 100; sink_params.total_bytes = 10000; sink_params.seed = default_seed; sink_params.rate = 0.0; sink_params.burst_min = 10001; sink_params.burst_max = 10001; source_buffer_max = 1000; sink_buffer_max = 1000; extensions = transport_extensions(); flow_control_efficiency = (extensions & transport_flow_control_efficiency) != 0; multiplexing = (extensions & transport_multiplexing) != 0; congestion_control = (extensions & transport_congestion_control) != 0; check_buffer_max = 0; check_forbidden = 0; misroute_prob = 0.0; } static void setup_easy(void) { setup_short(); source_params.total_bytes = 100000; sink_params.total_bytes = 100000; sink_params.burst_min = 100001; sink_params.burst_max = 100001; } static void setup_last_packet(void) { setup_short(); source_params.total_bytes = 9950; sink_params.total_bytes = 9950; sink_params.burst_min = 9951; sink_params.burst_max = 9951; } static void setup_small_mtu(void) { setup_easy(); net_params.max_payload_length = 320; } static void setup_large_mtu(void) { setup_easy(); net_params.max_payload_length = 65535; } static void setup_drop(void) { setup_easy(); net_params.drop_probability = 0.5; } static void setup_corrupt(void) { double corrupt_probability = 0.5; setup_easy(); net_params.bit_error_rate = 1.0 - pow(1.0 - corrupt_probability, 0.125 / net_params.max_payload_length); } static void setup_duplicate(void) { setup_easy(); net_params.duplicate_probability = 0.5; } static void setup_reorder(void) { setup_easy(); net_params.delay_random_max = 2.0; } static void setup_long_delay(void) { setup_easy(); net_params.delay_constant = 60.0; } static void setup_misroute(void) { setup_easy(); misroute_prob = 0.5; } static void add_flakey_network(void) { net_params.drop_probability = 0.3; net_params.duplicate_probability = 0.3; net_params.delay_random_max = 2.0; } static void setup_flakey_network(void) { setup_easy(); add_flakey_network(); } static void setup_erratic_source(void) { setup_easy(); source_params.burst_min = 1; source_params.burst_max = 2000; } static void add_erratic_sink(void) { source_params.rate = 80000.0; sink_params.burst_min = 1; sink_params.burst_max = 2000; sink_params.rate = 8000.0; } static void setup_erratic_sink(void) { setup_easy(); add_erratic_sink(); } static void setup_erratic_both(void) { setup_erratic_source(); add_erratic_sink(); } static void setup_erratic_flakey(void) { setup_erratic_both(); add_flakey_network(); } static void setup_reinit(void) { setup_easy(); } static void setup_strange_address(void) { setup_easy(); source_address.length = 63; memset(&source_address.address, 0, 63); sink_address.length = 64; memset(&source_address.address, 0, 64); } static void setup_cheat(void) { setup_easy(); } static void setup_platform(void) { setup_easy(); } static void setup_buffer_max(void) { setup_erratic_both(); check_buffer_max = 1; } static void add_small_total(void) { source_params.total_bytes = 1000; sink_params.total_bytes = 1000; sink_params.burst_min = 1001; sink_params.burst_max = 1001; } static void setup_small_source_buffer(void) { setup_buffer_max(); source_buffer_max = 1; add_small_total(); } static void setup_small_sink_buffer(void) { setup_buffer_max(); sink_buffer_max = 1; add_small_total(); } static void setup_small_buffers(void) { setup_buffer_max(); source_buffer_max = 1; sink_buffer_max = 1; add_small_total(); } static void setup_stop_source(void) { setup_erratic_source(); sink_params.burst_min = 4000; sink_params.burst_max = 4000; sink_buffer_max = 4; } static void setup_start_source(void) { setup_erratic_source(); sink_params.burst_min = 1; sink_params.burst_max = 1; sink_buffer_max = 4; } static void setup_speed(void) { setup_easy(); source_params.rate = 1e6; } static void setup_speed_slow(void) { setup_easy(); net_params.delay_constant = 10.0; } static void setup_speed_fast(void) { setup_easy(); source_buffer_max = 10000; sink_buffer_max = 10000; source_params.rate = 1e7; } static void setup_multiplex(void) { setup_easy(); } static void setup_multiplex_flakey(void) { setup_flakey_network(); } static void setup_congest(void) { setup_easy(); source_params.rate = 80000.0; source_params.total_bytes = 1500000; sink_params.total_bytes = 1500000; sink_params.burst_min = 1500001; sink_params.burst_max = 1500001; source_buffer_max = 12000; sink_buffer_max = 12000; bottle_params.packet_cost = 0.0; bottle_params.payload_byte_cost = 1.0; bottle_params.budget = 3000.0; } static void setup_fair(void) { setup_congest(); net_params.delay_constant = 0.6; } static void *transport_source = 0, *transport_sink = 0; static void *byte_source, *byte_sink; static FILE *out, *err; /*** begin modification of warnf.c ***/ /*** we just want to silence warnf() ***/ static const char unused; const char * const warnf_code_ref_hook = &unused; static int warnf_guts(const char *format, va_list ap) { int line, r1, r2; const char *file; if (format != warnf_code_ref_hook) { return vfprintf(err,format,ap); } file = va_arg(ap, const char *); line = va_arg(ap, int); format = va_arg(ap, const char *); r1 = vfprintf(err,format,ap); if (r1 < 0) return r1; r2 = fprintf(err, " at %s line %d\n", file, line); return r2 < 0 ? r2 : r1 + r2; } int warnf(const char *format, ...) { return 0; } void failf(const char *format, ...) { va_list ap; va_start(ap,format); warnf_guts(format,ap); va_end(ap); exit(EXIT_FAILURE); } void abortf(const char *format, ...) { va_list ap; va_start(ap,format); warnf_guts(format,ap); va_end(ap); abort(); } const char *out_of_memory = "out of memory\n"; /*** end modification of warnf.c ***/ void deliver_packet(struct network_packet packet) { unsigned short length; unsigned char *address; int choose_source; length = packet.destination.length; address = packet.destination.address; if (check_forbidden) { size_t n = sizeof forbidden, offset; for (offset = 0; offset < packet.payload_length - n; ++offset) { if (memcmp(packet.payload + offset, forbidden, n) == 0) { fprintf(out, "failed (unacknowledgeable data sent)\n"); exit(EXIT_SUCCESS); } } } if (length == source_address.length && !memcmp(address, source_address.address, length)) { choose_source = 1; } else if (length == sink_address.length && !memcmp(address, sink_address.address, length)) { choose_source = 0; } else { assert(0); /* Cannot reach here. */ } if (misroute_prob > 0.0) { if (random_uniform01() < misroute_prob) choose_source = !choose_source; } if (choose_source) { transport_source_receive_packet(transport_source, packet); } else { transport_sink_receive_packet(transport_sink, packet); } } static void require_flow_control(void) { if (!flow_control_efficiency) { fprintf(out, "flow control extension not supported\n"); exit(EXIT_SUCCESS); } } static void require_multiplexing(void) { if (!multiplexing) { fprintf(out, "multiplexing extension not supported\n"); exit(EXIT_SUCCESS); } } static void require_congestion_control(void) { if (!congestion_control) { fprintf(out, "congestion control extension not supported\n"); exit(EXIT_SUCCESS); } } static void prepare(void) /* Create, configure, connect everything. */ { struct transport_connection connection; network_path_config(source_address, sink_address, net_params); network_path_config(sink_address, source_address, net_params); network_bottleneck_config(bottle_params); byte_source = byte_source_create(); byte_sink = byte_sink_create(); byte_source_config(byte_source, source_params); byte_sink_config(byte_sink, sink_params); if (!transport_source) { transport_source = transport_source_create(source_address); } if (!transport_sink) { transport_sink = transport_sink_create(sink_address); } connection.source.address = source_address; connection.source.port = 101; connection.sink.address = sink_address; connection.sink.port = 102; transport_source_create_connection( transport_source, connection, byte_source, byte_source_go_ahead, source_buffer_max ); transport_sink_create_connection( transport_sink, connection, byte_sink, byte_sink_transfer, sink_buffer_max ); byte_source_talk_to( byte_source, transport_source, transport_source_receive_bytes ); byte_sink_listen_to( byte_sink, transport_sink, transport_sink_okay_to_deliver ); } static void run_until(unsigned long total) /* Run until the byte sink has received total */ /* bytes, or no progress is made for 10000 events. */ { unsigned long sent, received, oldreceived, events, totalevents; totalevents = 0; events = 0; received = 0; while (timer_expire()) { oldreceived = received; received = byte_sink_received(byte_sink); if (received >= total) break; if (received > oldreceived) { events = 0; } else { if (++events > 10000) { fprintf(out, "failed (no progress)\n"); exit(EXIT_SUCCESS); } if (++totalevents % 10000 == 0) { fprintf(err, "."); fflush(err); } } if (byte_sink_wrong(byte_sink)) { fprintf(out, "failed (wrong bytes)\n"); exit(EXIT_SUCCESS); } if (check_buffer_max) { sent = byte_source_sent(byte_source); received = byte_sink_received(byte_sink); if (sent - received > source_buffer_max + sink_buffer_max) { fprintf(out, "failed (buffer_max exceeded)\n"); exit(EXIT_SUCCESS); } } } if (byte_sink_received(byte_sink) < total) { fprintf(out, "failed (not all bytes transferred)\n"); exit(EXIT_SUCCESS); } } static void check_incorrectness(void) /* Prints "failed" to stdout and exits, or returns if no failure. */ { unsigned long total, events; double stop; total = sink_params.total_bytes; assert(total == source_params.total_bytes); prepare(); start = timer_now(); run_until(total); finish = timer_now(); stop = finish + (finish - start); events = 0; while (timer_next() <= stop && timer_expire() && ++events < 10000); if (byte_sink_received(byte_sink) > total) { fprintf(out, "failed (too many bytes transferred)\n"); exit(EXIT_SUCCESS); } } static void check_correctness(void) /* Prints "failed" or "passed" to stdout, then exits. */ { check_incorrectness(); fprintf(out, "passed\n"); exit(EXIT_SUCCESS); } static void check_reinit(void) { double stop, oldnow, now; unsigned long events; check_incorrectness(); transport_source_delete_connection(transport_source, byte_source); transport_sink_delete_connection(transport_sink, byte_sink); byte_source_delete(byte_source); byte_sink_delete(byte_sink); /* Flush the network of packets: */ stop = timer_now() + 140.0; /* 60 + 60 + 10 + 10 */ now = timer_now(); while (timer_expire()) { oldnow = now; now = timer_now(); if (now > oldnow) { events = 0; } else { if (++events > 10000) { fprintf(out, "failed (no progress)\n"); exit(EXIT_SUCCESS); } } } check_correctness(); } static void check_flow(void) /* Prints "failed" or "passed" to stdout, then exits. */ { unsigned long total, i, events; uint32 rand_increment = 0xb, rand_factor = 0x41c64e6d, /* Above must match streamers.c. */ rand_state = default_seed; double stop; total = sink_params.burst_min; assert(total == sink_params.burst_max); assert(sink_params.rate == 0.0); for (i = 0; i < total + sink_buffer_max; ++i) { rand_state = (rand_state + rand_increment) * rand_factor; } forbidden[0] = (rand_state >> 24) & 0xff; rand_state = (rand_state + rand_increment) * rand_factor; forbidden[1] = (rand_state >> 24) & 0xff; rand_state = (rand_state + rand_increment) * rand_factor; forbidden[2] = (rand_state >> 24) & 0xff; rand_state = (rand_state + rand_increment) * rand_factor; forbidden[3] = (rand_state >> 24) & 0xff; check_forbidden = 1; prepare(); start = timer_now(); run_until(total); finish = timer_now(); stop = finish + 10 * (finish - start); events = 0; while (timer_next() <= stop && timer_expire() && ++events < 10000); if (byte_sink_received(byte_sink) > total) { fprintf(out, "failed (too many bytes transferred)\n"); exit(EXIT_SUCCESS); } fprintf(out, "passed\n"); exit(EXIT_SUCCESS); } static void check_speed(void) /* Prints "failed" or a data rate to stdout, then exits. */ { double bps; check_incorrectness(); bps = byte_sink_received(byte_sink) / (finish - start) * 8; fprintf(out, "%.4g kbps\n", bps / 1000); exit(EXIT_SUCCESS); } static void check_multiple(void) /* Prints "failed" or "passed" to stdout, then exits. */ { unsigned long total, events; double stop; void *byte_source1, *byte_sink1, *byte_source2, *byte_sink2, *byte_source3, *byte_sink3; struct transport_connection connection2, connection3; total = sink_params.total_bytes; assert(total == source_params.total_bytes); prepare(); byte_source1 = byte_source; byte_sink1 = byte_sink; byte_source2 = byte_source_create(); byte_sink2 = byte_sink_create(); byte_source_config(byte_source2, source_params); byte_sink_config(byte_sink2, sink_params); connection2.source.address = source_address; connection2.source.port = 101; connection2.sink.address = sink_address; connection2.sink.port = 202; byte_source_talk_to( byte_source2, transport_source, transport_source_receive_bytes ); byte_sink_listen_to( byte_sink2, transport_sink, transport_sink_okay_to_deliver ); byte_source3 = byte_source_create(); byte_sink3 = byte_sink_create(); byte_source_config(byte_source3, source_params); byte_sink_config(byte_sink3, sink_params); connection3.source.address = source_address; connection3.source.port = 201; connection3.sink.address = sink_address; connection3.sink.port = 202; byte_source_talk_to( byte_source3, transport_source, transport_source_receive_bytes ); byte_sink_listen_to( byte_sink3, transport_sink, transport_sink_okay_to_deliver ); transport_source_create_connection( transport_source, connection2, byte_source2, byte_source_go_ahead, source_buffer_max ); transport_source_create_connection( transport_source, connection3, byte_source3, byte_source_go_ahead, source_buffer_max ); transport_sink_create_connection( transport_sink, connection3, byte_sink3, byte_sink_transfer, sink_buffer_max ); transport_sink_create_connection( transport_sink, connection2, byte_sink2, byte_sink_transfer, sink_buffer_max ); start = timer_now(); run_until(total); byte_source = byte_source2; byte_sink = byte_sink2; run_until(total); byte_source = byte_source3; byte_sink = byte_sink3; run_until(total); finish = timer_now(); stop = finish + (finish - start); events = 0; while (timer_next() <= stop && timer_expire() && ++events < 10000); if (byte_sink_wrong(byte_sink2) || byte_sink_wrong(byte_sink3)) { fprintf(out, "failed (wrong bytes)\n"); exit(EXIT_SUCCESS); } if (byte_sink_received(byte_sink1) > total || byte_sink_received(byte_sink2) > total || byte_sink_received(byte_sink3) > total ) { fprintf(out, "failed (too many bytes transferred)\n"); exit(EXIT_SUCCESS); } fprintf(out, "passed\n"); exit(EXIT_SUCCESS); } static void check_congest(void) /* Prints "failed" or three data rates */ /* and a drop rate to stdout, then exits. */ { unsigned long total, bigchunk, smallchunk, start_bytes, finish_bytes; double rate; struct network_statistics stats; total = sink_params.total_bytes; assert(total <= source_params.total_bytes); bigchunk = total / 3; smallchunk = bigchunk / 5; net_params.delay_constant = 0.6; prepare(); run_until(bigchunk - smallchunk); start = timer_now(); start_bytes = byte_sink_received(byte_sink); run_until(bigchunk); finish = timer_now(); finish_bytes = byte_sink_received(byte_sink); rate = (finish_bytes - start_bytes) * 8.0 / (finish - start); fprintf(out, "%.3g kbps", rate / 1000); net_params.delay_constant = 6.0; network_path_config(source_address, sink_address, net_params); network_path_config(sink_address, source_address, net_params); run_until(2 * bigchunk - smallchunk); start = timer_now(); start_bytes = byte_sink_received(byte_sink); run_until(2 * bigchunk); finish = timer_now(); finish_bytes = byte_sink_received(byte_sink); rate = (finish_bytes - start_bytes) * 8.0 / (finish - start); fprintf(out, ", %.3g kbps", rate / 1000); net_params.delay_constant = 1.2; network_path_config(source_address, sink_address, net_params); network_path_config(sink_address, source_address, net_params); run_until(3 * bigchunk - smallchunk); start = timer_now(); start_bytes = byte_sink_received(byte_sink); run_until(3 * bigchunk); finish = timer_now(); finish_bytes = byte_sink_received(byte_sink); rate = (finish_bytes - start_bytes) * 8.0 / (finish - start); fprintf(out, ", %.3g kbps", rate / 1000); stats = network_statistics(); rate = (double) stats.packets_dropped / stats.packets_sent; fprintf(out, ", %.2g%% drop rate\n", rate * 100); exit(EXIT_SUCCESS); } static void check_fair(void) /* Prints "failed" or two data rates and */ /* a drop rate to stdout, then exits. */ { unsigned long total, bigchunk, smallchunk, start_bytes1, finish_bytes1, start_bytes2, finish_bytes2; double rate; struct network_statistics stats; void *byte_source2, *byte_sink2; struct transport_connection connection2; total = sink_params.total_bytes; assert(total <= source_params.total_bytes); bigchunk = total / 3; smallchunk = bigchunk / 5; prepare(); run_until(bigchunk); byte_source2 = byte_source_create(); byte_sink2 = byte_sink_create(); byte_source_config(byte_source2, source_params); byte_sink_config(byte_sink2, sink_params); connection2.source.address = source_address; connection2.source.port = 201; connection2.sink.address = sink_address; connection2.sink.port = 202; byte_source_talk_to( byte_source2, transport_source, transport_source_receive_bytes ); byte_sink_listen_to( byte_sink2, transport_sink, transport_sink_okay_to_deliver ); transport_source_create_connection( transport_source, connection2, byte_source2, byte_source_go_ahead, source_buffer_max ); transport_sink_create_connection( transport_sink, connection2, byte_sink2, byte_sink_transfer, sink_buffer_max ); run_until(3 * bigchunk - smallchunk); start = timer_now(); start_bytes1 = byte_sink_received(byte_sink); start_bytes2 = byte_sink_received(byte_sink2); run_until(3 * bigchunk); finish = timer_now(); finish_bytes1 = byte_sink_received(byte_sink); finish_bytes2 = byte_sink_received(byte_sink2); rate = (finish_bytes1 - start_bytes1) * 8.0 / (finish - start); fprintf(out, "%.3g kbps", rate / 1000); rate = (finish_bytes2 - start_bytes2) * 8.0 / (finish - start); fprintf(out, ", %.3g kbps", rate / 1000); stats = network_statistics(); rate = (double) stats.packets_dropped / stats.packets_sent; fprintf(out, ", %.2g%% drop rate\n", rate * 100); exit(EXIT_SUCCESS); } int main(int argc, char **argv) { int d; d = dup(1); if (d == -1) { perror("dup(1)"); return EXIT_FAILURE; } out = fdopen(d, "w"); if (!out) { perror("fdopen(d, \"w\")"); return EXIT_FAILURE; } d = dup(2); if (d == -1) { perror("dup(2)"); return EXIT_FAILURE; } err = fdopen(d, "w"); if (!err) { perror("fdopen(d, \"w\")"); return EXIT_FAILURE; } if (!freopen("/dev/null", "r", stdin)) { perror("freopen(\"/dev/null\", \"r\", stdin)"); return EXIT_FAILURE; } if (!freopen("/dev/null", "w", stdout)) { perror("freopen(\"/dev/null\", \"w\", stdout)"); return EXIT_FAILURE; } if (!freopen("/dev/null", "w", stderr)) { perror("freopen(\"/dev/null\", \"w\", stderr)"); return EXIT_FAILURE; } if (argc < 2) { fprintf(err, "first argument must be the test name\n"); return EXIT_FAILURE; } if (strcmp(argv[1], "short") == 0) { setup_short(); check_correctness(); } else if (strcmp(argv[1], "easy") == 0) { setup_easy(); check_correctness(); } else if (strcmp(argv[1], "last_packet") == 0) { setup_last_packet(); check_correctness(); } else if (strcmp(argv[1], "small_mtu") == 0) { setup_small_mtu(); check_correctness(); } else if (strcmp(argv[1], "large_mtu") == 0) { setup_large_mtu(); check_correctness(); } else if (strcmp(argv[1], "drop") == 0) { setup_drop(); check_correctness(); } else if (strcmp(argv[1], "corrupt") == 0) { setup_corrupt(); check_correctness(); } else if (strcmp(argv[1], "duplicate") == 0) { setup_duplicate(); check_correctness(); } else if (strcmp(argv[1], "reorder") == 0) { setup_reorder(); check_correctness(); } else if (strcmp(argv[1], "long_delay") == 0) { setup_long_delay(); check_correctness(); } else if (strcmp(argv[1], "misroute") == 0) { setup_misroute(); check_correctness(); } else if (strcmp(argv[1], "flakey_network") == 0) { setup_flakey_network(); check_correctness(); } else if (strcmp(argv[1], "erratic_source") == 0) { setup_erratic_source(); check_correctness(); } else if (strcmp(argv[1], "erratic_sink") == 0) { setup_erratic_sink(); check_correctness(); } else if (strcmp(argv[1], "erratic_both") == 0) { setup_erratic_both(); check_correctness(); } else if (strcmp(argv[1], "erratic_flakey") == 0) { setup_erratic_flakey(); check_correctness(); } else if (strcmp(argv[1], "reinit") == 0) { setup_reinit(); check_reinit(); } else if (strcmp(argv[1], "strange_address") == 0) { setup_strange_address(); check_correctness(); } else if (strcmp(argv[1], "cheat") == 0) { setup_cheat(); fprintf(out, "test not yet implemented\n"); return EXIT_SUCCESS; } else if (strcmp(argv[1], "platform") == 0) { setup_platform(); fprintf(out, "test not yet implemented\n"); return EXIT_SUCCESS; } else if (strcmp(argv[1], "buffer_max") == 0) { setup_buffer_max(); require_flow_control(); check_correctness(); } else if (strcmp(argv[1], "small_source_buffer") == 0) { setup_small_source_buffer(); require_flow_control(); check_correctness(); } else if (strcmp(argv[1], "small_sink_buffer") == 0) { setup_small_sink_buffer(); require_flow_control(); check_correctness(); } else if (strcmp(argv[1], "small_buffers") == 0) { setup_small_buffers(); require_flow_control(); check_correctness(); } else if (strcmp(argv[1], "stop_source") == 0) { setup_stop_source(); require_flow_control(); check_flow(); } else if (strcmp(argv[1], "start_source") == 0) { setup_start_source(); require_flow_control(); check_flow(); } else if (strcmp(argv[1], "speed") == 0) { setup_speed(); require_flow_control(); check_speed(); } else if (strcmp(argv[1], "speed_slow") == 0) { setup_speed_slow(); require_flow_control(); check_speed(); } else if (strcmp(argv[1], "speed_fast") == 0) { setup_speed_fast(); require_flow_control(); check_speed(); } else if (strcmp(argv[1], "multiplex") == 0) { setup_multiplex(); require_multiplexing(); check_multiple(); } else if (strcmp(argv[1], "multiplex_flakey") == 0) { setup_multiplex_flakey(); require_multiplexing(); check_multiple(); } else if (strcmp(argv[1], "congest") == 0) { setup_congest(); require_congestion_control(); check_congest(); } else if (strcmp(argv[1], "fair") == 0) { setup_fair(); require_congestion_control(); require_multiplexing(); check_fair(); } else { fprintf(err, "unknown test name %s\n", argv[1]); return EXIT_FAILURE; } assert(0); /* Cannot reach here. */ }