/** Run unit tests for concatenate-a-smartlist-of-strings functions. */ static void test_container_smartlist_join(void) { smartlist_t *sl = smartlist_new(); smartlist_t *sl2 = smartlist_new(), *sl3 = smartlist_new(), *sl4 = smartlist_new(); char *joined=NULL; /* unique, sorted. */ smartlist_split_string(sl, "Abashments Ambush Anchorman Bacon Banks Borscht " "Bunks Inhumane Insurance Knish Know Manners " "Maraschinos Stamina Sunbonnets Unicorns Wombats", " ", 0, 0); /* non-unique, sorted. */ smartlist_split_string(sl2, "Ambush Anchorman Anchorman Anemias Anemias Bacon " "Crossbowmen Inhumane Insurance Knish Know Manners " "Manners Maraschinos Wombats Wombats Work", " ", 0, 0); SMARTLIST_FOREACH_JOIN(sl, char *, cp1, sl2, char *, cp2, strcmp(cp1,cp2), smartlist_add(sl3, cp2)) { test_streq(cp1, cp2); smartlist_add(sl4, cp1); } SMARTLIST_FOREACH_JOIN_END(cp1, cp2);
/** Launch all server listeners that tor wants us to launch. */ static int launch_server_listeners(const managed_proxy_t *proxy) { int ret=-1; int i, n_transports; const char *transport = NULL; const char *bindaddr_temp = NULL; const char *bindaddr = NULL; config_t *cfg = NULL; /* list of transports */ smartlist_t *transports = smartlist_create(); /* a list of "<transport>-<bindaddr>" strings */ smartlist_t *bindaddrs = smartlist_create(); /* split the comma-separated transports/bindaddrs to their smartlists */ smartlist_split_string(transports, proxy->vars.transports, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); smartlist_split_string(bindaddrs, proxy->vars.bindaddrs, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); n_transports = smartlist_len(transports); /* Iterate transports; match them with their bindaddr; create their config_t. */ for (i=0;i<n_transports;i++) { transport = smartlist_get(transports, i); bindaddr_temp = smartlist_get(bindaddrs, i); obfs_assert(strlen(bindaddr_temp) > strlen(transport)+1); bindaddr = bindaddr_temp+strlen(transport)+1; /* +1 for the dash */ cfg = config_create_managed(proxy->is_server, transport, bindaddr, proxy->vars.or_port); if (cfg) /* if a config was created; put it in the config smartlist */ smartlist_add(proxy->configs, cfg); else /* otherwise, spit a method error line */ print_method_error_line(transport, proxy, ST_LAUNCH_FAIL_SETUP); } /* open listeners */ ret = open_listeners_managed(proxy); SMARTLIST_FOREACH(bindaddrs, char *, cp, free(cp)); smartlist_free(bindaddrs); SMARTLIST_FOREACH(transports, char *, cp, free(cp)); smartlist_free(transports); print_method_done_line(proxy); /* print {C,S}METHODS DONE */ return ret; }
/** Return the config line for transport <b>transport</b> in the current state. * Return NULL if there is no config line for <b>transport</b>. */ static config_line_t * get_transport_in_state_by_name(const char *transport) { or_state_t *or_state = get_or_state(); config_line_t *line; config_line_t *ret = NULL; smartlist_t *items = NULL; for (line = or_state->TransportProxies ; line ; line = line->next) { tor_assert(!strcmp(line->key, "TransportProxy")); items = smartlist_new(); smartlist_split_string(items, line->value, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); if (smartlist_len(items) != 2) /* broken state */ goto done; if (!strcmp(smartlist_get(items, 0), transport)) { ret = line; goto done; } SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); items = NULL; } done: if (items) { SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); } return ret; }
/** Parse a log severity pattern in *<b>cfg_ptr</b>. Advance cfg_ptr after * the end of the severityPattern. Set the value of <b>severity_out</b> to * the parsed pattern. Return 0 on success, -1 on failure. * * The syntax for a SeverityPattern is: * <pre> * SeverityPattern = *(DomainSeverity SP)* DomainSeverity * DomainSeverity = (DomainList SP)? SeverityRange * SeverityRange = MinSeverity ("-" MaxSeverity )? * DomainList = "[" (SP? DomainSpec SP? ",") SP? DomainSpec "]" * DomainSpec = "*" | Domain | "~" Domain * </pre> * A missing MaxSeverity defaults to ERR. Severities and domains are * case-insensitive. "~" indicates negation for a domain; negation happens * last inside a DomainList. Only one SeverityRange without a DomainList is * allowed per line. */ int parse_log_severity_config(const char **cfg_ptr, log_severity_list_t *severity_out) { const char *cfg = *cfg_ptr; int got_anything = 0; int got_an_unqualified_range = 0; memset(severity_out, 0, sizeof(*severity_out)); cfg = eat_whitespace(cfg); while (*cfg) { const char *dash, *space; char *sev_lo, *sev_hi; int low, high, i; log_domain_mask_t domains = ~0u; if (*cfg == '[') { int err = 0; char *domains_str; smartlist_t *domains_list; log_domain_mask_t neg_domains = 0; const char *closebracket = strchr(cfg, ']'); if (!closebracket) return -1; domains = 0; domains_str = tor_strndup(cfg+1, closebracket-cfg-1); domains_list = smartlist_create(); smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE, -1); tor_free(domains_str); SMARTLIST_FOREACH(domains_list, const char *, domain, { if (!strcmp(domain, "*")) { domains = ~0u; } else { int d; int negate=0; if (*domain == '~') { negate = 1; ++domain; } d = parse_log_domain(domain); if (!d) { log_warn(LD_CONFIG, "No such logging domain as %s", domain); err = 1; } else { if (negate) neg_domains |= d; else domains |= d; } } }); SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d)); smartlist_free(domains_list); if (err) return -1; domains &= ~neg_domains; cfg = eat_whitespace(closebracket+1); } else {
/* Parse a share random value line from the disk state and save it to dst * which is an allocated srv object. Return 0 on success else -1. */ static int disk_state_parse_srv(const char *value, sr_srv_t *dst) { int ret = -1; smartlist_t *args; sr_srv_t *srv; tor_assert(value); tor_assert(dst); args = smartlist_new(); smartlist_split_string(args, value, " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); if (smartlist_len(args) < 2) { log_warn(LD_BUG, "SR: Too few arguments in shared random value. " "Line: %s", escaped(value)); goto error; } srv = sr_parse_srv(args); if (srv == NULL) { goto error; } dst->num_reveals = srv->num_reveals; memcpy(dst->value, srv->value, sizeof(dst->value)); tor_free(srv); ret = 0; error: SMARTLIST_FOREACH(args, char *, s, tor_free(s)); smartlist_free(args); return ret; }
/** Finish the configuration protocol version negotiation by printing whether we support any of the suggested configuration protocols in stdout, according to the 180 spec. Return: * 0: if we actually found and selected a protocol. * -1: if we couldn't find a common supported protocol or if we couldn't even parse tor's supported protocol list. XXX: in the future we should return the protocol version we selected. let's keep it simple for now since we have just one protocol version. */ static int conf_proto_version_negotiation(const managed_proxy_t *proxy) { int r=-1; smartlist_t *versions = smartlist_create(); smartlist_split_string(versions, proxy->vars.conf_proto_version, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); SMARTLIST_FOREACH_BEGIN(versions, char *, version) { if (is_supported_conf_protocol(version)) { print_protocol_line("%s %s\n", PROTO_NEG_SUCCESS, version); r=0; goto done; } } SMARTLIST_FOREACH_END(version); /* we get here if we couldn't find a supported protocol */ print_protocol_line("%s", PROTO_NEG_FAIL); done: SMARTLIST_FOREACH(versions, char *, cp, free(cp)); smartlist_free(versions); return r; }
/** See dir_common_construct_vote_1. * Produces a vote with slightly different values. */ int dir_common_construct_vote_2(networkstatus_t **vote, authority_cert_t *cert, crypto_pk_t *sign_skey, vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), networkstatus_t **vote_out, int *n_vrs, time_t now, int clear_rl) { networkstatus_voter_info_t *voter; dir_common_setup_vote(vote, now); (*vote)->type = NS_TYPE_VOTE; (*vote)->published += 1; (*vote)->valid_after = now+1000; (*vote)->fresh_until = now+3005; (*vote)->valid_until = now+3000; (*vote)->vote_seconds = 100; (*vote)->dist_seconds = 300; smartlist_split_string((*vote)->supported_methods, "1 2 3", NULL, 0, -1); smartlist_split_string((*vote)->known_flags, "Authority Exit Fast Guard MadeOfCheese MadeOfTin " "Running Stable V2Dir Valid", 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); voter->nickname = tor_strdup("Voter2"); voter->address = tor_strdup("2.3.4.5"); voter->addr = 0x02030405; voter->dir_port = 80; voter->or_port = 9000; voter->contact = tor_strdup("*****@*****.**"); crypto_pk_get_digest(cert->identity_key, voter->identity_digest); /* * Set up a vote; generate it; try to parse it. */ smartlist_add((*vote)->voters, voter); (*vote)->cert = authority_cert_dup(cert); if (! (*vote)->net_params) (*vote)->net_params = smartlist_new(); smartlist_split_string((*vote)->net_params, "bar=2000000000 circuitwindow=20", NULL, 0, 0); /* add routerstatuses */ /* dump the vote and try to parse it. */ dir_common_add_rs_and_parse(*vote, vote_out, vrs_gen, sign_skey, n_vrs, now, clear_rl); return 0; }
int fuzz_init(void) { disable_signature_checking(); MOCK(dump_desc, mock_dump_desc__nodump); ed25519_init(); area = memarea_new(); dummy_vote = tor_malloc_zero(sizeof(*dummy_vote)); dummy_vote->known_flags = smartlist_new(); smartlist_split_string(dummy_vote->known_flags, DIRVOTE_UNIVERSAL_FLAGS, " ", 0, 0); smartlist_split_string(dummy_vote->known_flags, DIRVOTE_OPTIONAL_FLAGS, " ", 0, 0); smartlist_sort_strings(dummy_vote->known_flags); return 0; }
/** See dir_common_construct_vote_1. * Produces a vote with slightly different values. Adds a legacy key. */ int dir_common_construct_vote_3(networkstatus_t **vote, authority_cert_t *cert, crypto_pk_t *sign_skey, vote_routerstatus_t * (*vrs_gen)(int idx, time_t now), networkstatus_t **vote_out, int *n_vrs, time_t now, int clear_rl) { networkstatus_voter_info_t *voter; dir_common_setup_vote(vote, now); (*vote)->valid_after = now+1000; (*vote)->fresh_until = now+2003; (*vote)->valid_until = now+3000; (*vote)->vote_seconds = 100; (*vote)->dist_seconds = 250; smartlist_split_string((*vote)->supported_methods, "1 2 3 4", NULL, 0, -1); (*vote)->client_versions = tor_strdup("0.1.2.14,0.1.2.17"); (*vote)->server_versions = tor_strdup("0.1.2.10,0.1.2.15,0.1.2.16"); smartlist_split_string((*vote)->known_flags, "Authority Exit Fast Guard Running Stable V2Dir Valid", 0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); voter = tor_malloc_zero(sizeof(networkstatus_voter_info_t)); voter->nickname = tor_strdup("Voter2"); voter->address = tor_strdup("3.4.5.6"); voter->addr = 0x03040506; voter->dir_port = 80; voter->or_port = 9000; voter->contact = tor_strdup("*****@*****.**"); crypto_pk_get_digest(cert->identity_key, voter->identity_digest); memset(voter->legacy_id_digest, (int)'A', DIGEST_LEN); /* * Set up a vote; generate it; try to parse it. */ smartlist_add((*vote)->voters, voter); (*vote)->cert = authority_cert_dup(cert); smartlist_split_string((*vote)->net_params, "circuitwindow=80 foo=660", NULL, 0, 0); /* add routerstatuses */ /* dump the vote and try to parse it. */ dir_common_add_rs_and_parse(*vote, vote_out, vrs_gen, sign_skey, n_vrs, now, clear_rl); return 0; }
static void test_container_smartlist_most_frequent(void *arg) { (void) arg; smartlist_t *sl = smartlist_new(); int count = -1; const char *cp; cp = smartlist_get_most_frequent_string_(sl, &count); tt_int_op(count, ==, 0); tt_ptr_op(cp, ==, NULL); /* String must be sorted before we call get_most_frequent */ smartlist_split_string(sl, "abc:def:ghi", ":", 0, 0); cp = smartlist_get_most_frequent_string_(sl, &count); tt_int_op(count, ==, 1); tt_str_op(cp, ==, "ghi"); /* Ties broken in favor of later element */ smartlist_split_string(sl, "def:ghi", ":", 0, 0); smartlist_sort_strings(sl); cp = smartlist_get_most_frequent_string_(sl, &count); tt_int_op(count, ==, 2); tt_ptr_op(cp, !=, NULL); tt_str_op(cp, ==, "ghi"); /* Ties broken in favor of later element */ smartlist_split_string(sl, "def:abc:qwop", ":", 0, 0); smartlist_sort_strings(sl); cp = smartlist_get_most_frequent_string_(sl, &count); tt_int_op(count, ==, 3); tt_ptr_op(cp, !=, NULL); tt_str_op(cp, ==, "def"); /* No tie */ done: SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); }
/* Parse the Commit line(s) in the disk state and translate them to the * the memory state. Return 0 on success else -1 on error. */ static int disk_state_parse_commits(sr_state_t *state, const sr_disk_state_t *disk_state) { config_line_t *line; smartlist_t *args = NULL; tor_assert(state); tor_assert(disk_state); for (line = disk_state->Commit; line; line = line->next) { sr_commit_t *commit = NULL; /* Extra safety. */ if (strcasecmp(line->key, dstate_commit_key) || line->value == NULL) { /* Ignore any lines that are not commits. */ tor_fragile_assert(); continue; } args = smartlist_new(); smartlist_split_string(args, line->value, " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); if (smartlist_len(args) < 3) { log_warn(LD_BUG, "SR: Too few arguments in Commit Line: %s", escaped(line->value)); goto error; } commit = sr_parse_commit(args); if (commit == NULL) { /* Ignore badly formed commit. It could also be a authority * fingerprint that we don't know about so it shouldn't be used. */ smartlist_free(args); continue; } /* We consider parseable commit from our disk state to be valid because * they need to be in the first place to get in there. */ commit->valid = 1; /* Add commit to our state pointer. */ commit_add_to_state(commit, state); SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); smartlist_free(args); } return 0; error: SMARTLIST_FOREACH(args, char *, cp, tor_free(cp)); smartlist_free(args); return -1; }
/** Parse the string <b>s</b> to create a set of routerset entries, and add * them to <b>target</b>. In log messages, refer to the string as * <b>description</b>. Return 0 on success, -1 on failure. * * Three kinds of elements are allowed in routersets: nicknames, IP address * patterns, and fingerprints. They may be surrounded by optional space, and * must be separated by commas. */ int routerset_parse(routerset_t *target, const char *s, const char *description) { int r = 0; int added_countries = 0; char *countryname; smartlist_t *list = smartlist_new(); int malformed_list; smartlist_split_string(list, s, ",", SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(list, char *, nick) { addr_policy_t *p; /* if it doesn't pass our validation, assume it's malformed */ malformed_list = 1; if (is_legal_hexdigest(nick)) { char d[DIGEST_LEN]; if (*nick == '$') ++nick; log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description); base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN); digestmap_set(target->digests, d, (void*)1); } else if (is_legal_nickname(nick)) { log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description); strmap_set_lc(target->names, nick, (void*)1); } else if ((countryname = routerset_get_countryname(nick)) != NULL) { log_debug(LD_CONFIG, "Adding country %s to %s", nick, description); smartlist_add(target->country_names, countryname); added_countries = 1; } else if ((strchr(nick,'.') || strchr(nick, ':') || strchr(nick, '*')) && (p = router_parse_addr_policy_item_from_string( nick, ADDR_POLICY_REJECT, &malformed_list))) { /* IPv4 addresses contain '.', IPv6 addresses contain ':', * and wildcard addresses contain '*'. */ log_debug(LD_CONFIG, "Adding address %s to %s", nick, description); smartlist_add(target->policies, p); } else if (malformed_list) { log_warn(LD_CONFIG, "Entry '%s' in %s is malformed. Discarding entire" " list.", nick, description); r = -1; tor_free(nick); SMARTLIST_DEL_CURRENT(list, nick); } else { log_notice(LD_CONFIG, "Entry '%s' in %s is ignored. Using the" " remainder of the list.", nick, description); tor_free(nick); SMARTLIST_DEL_CURRENT(list, nick); } } SMARTLIST_FOREACH_END(nick);
/** Launch all client listeners that tor wants us to launch. */ static int launch_client_listeners(const managed_proxy_t *proxy) { int ret=-1; config_t *cfg = NULL; /* list of transports */ smartlist_t *transports = smartlist_create(); smartlist_split_string(transports, proxy->vars.transports, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); SMARTLIST_FOREACH_BEGIN(transports, char *, transport) { /* clients should find their own listen port */ cfg = config_create_managed(proxy->is_server, transport, "127.0.0.1:0", proxy->vars.or_port); if (cfg) /* if config was created; put it in the config smartlist */ smartlist_add(proxy->configs, cfg); else print_method_error_line(transport, proxy, ST_LAUNCH_FAIL_SETUP); } SMARTLIST_FOREACH_END(transport);
/** Parse the '-p' argument of tor-fw-helper. Its format is * [<external port>]:<internal port>, and <external port> is optional. * Return NULL if <b>arg</b> was c0rrupted. */ static port_to_forward_t * parse_port(const char *arg) { smartlist_t *sl = smartlist_new(); port_to_forward_t *port_to_forward = NULL; char *port_str = NULL; int ok; int port; smartlist_split_string(sl, arg, ":", 0, 0); if (smartlist_len(sl) != 2) goto err; port_to_forward = tor_malloc(sizeof(port_to_forward_t)); if (!port_to_forward) goto err; port_str = smartlist_get(sl, 0); /* macroify ? */ port = (int)tor_parse_long(port_str, 10, 1, 65535, &ok, NULL); if (!ok && strlen(port_str)) /* ":1555" is valid */ goto err; port_to_forward->external_port = port; port_str = smartlist_get(sl, 1); port = (int)tor_parse_long(port_str, 10, 1, 65535, &ok, NULL); if (!ok) goto err; port_to_forward->internal_port = port; goto done; err: tor_free(port_to_forward); done: SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); return port_to_forward; }
/** Return true if <b>line</b> is a valid state TransportProxy line. * Return false otherwise. */ static int state_transport_line_is_valid(const char *line) { smartlist_t *items = NULL; char *addrport=NULL; tor_addr_t addr; uint16_t port = 0; int r; items = smartlist_new(); smartlist_split_string(items, line, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); if (smartlist_len(items) != 2) { log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line."); goto err; } addrport = smartlist_get(items, 1); if (tor_addr_port_lookup(addrport, &addr, &port) < 0) { log_warn(LD_CONFIG, "state: Could not parse addrport."); goto err; } if (!port) { log_warn(LD_CONFIG, "state: Transport line did not contain port."); goto err; } r = 1; goto done; err: r = 0; done: SMARTLIST_FOREACH(items, char*, s, tor_free(s)); smartlist_free(items); return r; }
/** Parse the string <b>s</b> to create a set of routerset entries, and add * them to <b>target</b>. In log messages, refer to the string as * <b>description</b>. Return 0 on success, -1 on failure. * * Three kinds of elements are allowed in routersets: nicknames, IP address * patterns, and fingerprints. They may be surrounded by optional space, and * must be separated by commas. */ int routerset_parse(routerset_t *target, const char *s, const char *description) { int r = 0; int added_countries = 0; char *countryname; smartlist_t *list = smartlist_new(); smartlist_split_string(list, s, ",", SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(list, char *, nick) { addr_policy_t *p; if (is_legal_hexdigest(nick)) { char d[DIGEST_LEN]; if (*nick == '$') ++nick; log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description); base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN); digestmap_set(target->digests, d, (void*)1); } else if (is_legal_nickname(nick)) { log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description); strmap_set_lc(target->names, nick, (void*)1); } else if ((countryname = routerset_get_countryname(nick)) != NULL) { log_debug(LD_CONFIG, "Adding country %s to %s", nick, description); smartlist_add(target->country_names, countryname); added_countries = 1; } else if ((strchr(nick,'.') || strchr(nick, '*')) && (p = router_parse_addr_policy_item_from_string( nick, ADDR_POLICY_REJECT))) { log_debug(LD_CONFIG, "Adding address %s to %s", nick, description); smartlist_add(target->policies, p); } else { log_warn(LD_CONFIG, "Entry '%s' in %s is malformed.", nick, description); r = -1; tor_free(nick); SMARTLIST_DEL_CURRENT(list, nick); } } SMARTLIST_FOREACH_END(nick);
/** Configure accounting start/end time settings based on * options->AccountingStart. Return 0 on success, -1 on failure. If * <b>validate_only</b> is true, do not change the current settings. */ int accounting_parse_options(const or_options_t *options, int validate_only) { time_unit_t unit; int ok, idx; long d,h,m; smartlist_t *items; const char *v = options->AccountingStart; const char *s; char *cp; if (!v) { if (!validate_only) { cfg_unit = UNIT_MONTH; cfg_start_day = 1; cfg_start_hour = 0; cfg_start_min = 0; } return 0; } items = smartlist_new(); smartlist_split_string(items, v, NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK,0); if (smartlist_len(items)<2) { log_warn(LD_CONFIG, "Too few arguments to AccountingStart"); goto err; } s = smartlist_get(items,0); if (0==strcasecmp(s, "month")) { unit = UNIT_MONTH; } else if (0==strcasecmp(s, "week")) { unit = UNIT_WEEK; } else if (0==strcasecmp(s, "day")) { unit = UNIT_DAY; } else { log_warn(LD_CONFIG, "Unrecognized accounting unit '%s': only 'month', 'week'," " and 'day' are supported.", s); goto err; } switch (unit) { case UNIT_WEEK: d = tor_parse_long(smartlist_get(items,1), 10, 1, 7, &ok, NULL); if (!ok) { log_warn(LD_CONFIG, "Weekly accounting must begin on a day between " "1 (Monday) and 7 (Sunday)"); goto err; } break; case UNIT_MONTH: d = tor_parse_long(smartlist_get(items,1), 10, 1, 28, &ok, NULL); if (!ok) { log_warn(LD_CONFIG, "Monthly accounting must begin on a day between " "1 and 28"); goto err; } break; case UNIT_DAY: d = 0; break; /* Coverity dislikes unreachable default cases; some compilers warn on * switch statements missing a case. Tell Coverity not to worry. */ /* coverity[dead_error_begin] */ default: tor_assert(0); } idx = unit==UNIT_DAY?1:2; if (smartlist_len(items) != (idx+1)) { log_warn(LD_CONFIG,"Accounting unit '%s' requires %d argument%s.", s, idx, (idx>1)?"s":""); goto err; } s = smartlist_get(items, idx); h = tor_parse_long(s, 10, 0, 23, &ok, &cp); if (!ok) { log_warn(LD_CONFIG,"Accounting start time not parseable: bad hour."); goto err; } if (!cp || *cp!=':') { log_warn(LD_CONFIG, "Accounting start time not parseable: not in HH:MM format"); goto err; } m = tor_parse_long(cp+1, 10, 0, 59, &ok, &cp); if (!ok) { log_warn(LD_CONFIG, "Accounting start time not parseable: bad minute"); goto err; } if (!cp || *cp!='\0') { log_warn(LD_CONFIG, "Accounting start time not parseable: not in HH:MM format"); goto err; } if (!validate_only) { cfg_unit = unit; cfg_start_day = (int)d; cfg_start_hour = (int)h; cfg_start_min = (int)m; } SMARTLIST_FOREACH(items, char *, item, tor_free(item)); smartlist_free(items); return 0; err: SMARTLIST_FOREACH(items, char *, item, tor_free(item)); smartlist_free(items); return -1; }
/** Parse and validate the ASCII-encoded v2 descriptor in <b>desc</b>, * write the parsed descriptor to the newly allocated *<b>parsed_out</b>, the * binary descriptor ID of length DIGEST_LEN to <b>desc_id_out</b>, the * encrypted introduction points to the newly allocated * *<b>intro_points_encrypted_out</b>, their encrypted size to * *<b>intro_points_encrypted_size_out</b>, the size of the encoded descriptor * to *<b>encoded_size_out</b>, and a pointer to the possibly next * descriptor to *<b>next_out</b>; return 0 for success (including validation) * and -1 for failure. * * If <b>as_hsdir</b> is 1, we're parsing this as an HSDir, and we should * be strict about time formats. */ int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out, char *desc_id_out, char **intro_points_encrypted_out, size_t *intro_points_encrypted_size_out, size_t *encoded_size_out, const char **next_out, const char *desc, int as_hsdir) { rend_service_descriptor_t *result = tor_malloc_zero(sizeof(rend_service_descriptor_t)); char desc_hash[DIGEST_LEN]; const char *eos; smartlist_t *tokens = smartlist_new(); directory_token_t *tok; char secret_id_part[DIGEST_LEN]; int i, version, num_ok=1; smartlist_t *versions; char public_key_hash[DIGEST_LEN]; char test_desc_id[DIGEST_LEN]; memarea_t *area = NULL; const int strict_time_fmt = as_hsdir; tor_assert(desc); /* Check if desc starts correctly. */ if (strcmpstart(desc, "rendezvous-service-descriptor ")) { log_info(LD_REND, "Descriptor does not start correctly."); goto err; } /* Compute descriptor hash for later validation. */ if (router_get_hash_impl(desc, strlen(desc), desc_hash, "rendezvous-service-descriptor ", "\nsignature", '\n', DIGEST_SHA1) < 0) { log_warn(LD_REND, "Couldn't compute descriptor hash."); goto err; } /* Determine end of string. */ eos = strstr(desc, "\nrendezvous-service-descriptor "); if (!eos) eos = desc + strlen(desc); else eos = eos + 1; /* Check length. */ if (eos-desc > REND_DESC_MAX_SIZE) { /* XXXX+ If we are parsing this descriptor as a server, this * should be a protocol warning. */ log_warn(LD_REND, "Descriptor length is %d which exceeds " "maximum rendezvous descriptor size of %d bytes.", (int)(eos-desc), REND_DESC_MAX_SIZE); goto err; } /* Tokenize descriptor. */ area = memarea_new(); if (tokenize_string(area, desc, eos, tokens, desc_token_table, 0)) { log_warn(LD_REND, "Error tokenizing descriptor."); goto err; } /* Set next to next descriptor, if available. */ *next_out = eos; /* Set length of encoded descriptor. */ *encoded_size_out = eos - desc; /* Check min allowed length of token list. */ if (smartlist_len(tokens) < 7) { log_warn(LD_REND, "Impossibly short descriptor."); goto err; } /* Parse base32-encoded descriptor ID. */ tok = find_by_keyword(tokens, R_RENDEZVOUS_SERVICE_DESCRIPTOR); tor_assert(tok == smartlist_get(tokens, 0)); tor_assert(tok->n_args == 1); if (!rend_valid_descriptor_id(tok->args[0])) { log_warn(LD_REND, "Invalid descriptor ID: '%s'", tok->args[0]); goto err; } if (base32_decode(desc_id_out, DIGEST_LEN, tok->args[0], REND_DESC_ID_V2_LEN_BASE32) < 0) { log_warn(LD_REND, "Descriptor ID contains illegal characters: %s", tok->args[0]); goto err; } /* Parse descriptor version. */ tok = find_by_keyword(tokens, R_VERSION); tor_assert(tok->n_args == 1); result->version = (int) tor_parse_long(tok->args[0], 10, 0, INT_MAX, &num_ok, NULL); if (result->version != 2 || !num_ok) { /* If it's <2, it shouldn't be under this format. If the number * is greater than 2, we bumped it because we broke backward * compatibility. See how version numbers in our other formats * work. */ log_warn(LD_REND, "Unrecognized descriptor version: %s", escaped(tok->args[0])); goto err; } /* Parse public key. */ tok = find_by_keyword(tokens, R_PERMANENT_KEY); result->pk = tok->key; tok->key = NULL; /* Prevent free */ /* Parse secret ID part. */ tok = find_by_keyword(tokens, R_SECRET_ID_PART); tor_assert(tok->n_args == 1); if (strlen(tok->args[0]) != REND_SECRET_ID_PART_LEN_BASE32 || strspn(tok->args[0], BASE32_CHARS) != REND_SECRET_ID_PART_LEN_BASE32) { log_warn(LD_REND, "Invalid secret ID part: '%s'", tok->args[0]); goto err; } if (base32_decode(secret_id_part, DIGEST_LEN, tok->args[0], 32) < 0) { log_warn(LD_REND, "Secret ID part contains illegal characters: %s", tok->args[0]); goto err; } /* Parse publication time -- up-to-date check is done when storing the * descriptor. */ tok = find_by_keyword(tokens, R_PUBLICATION_TIME); tor_assert(tok->n_args == 1); if (parse_iso_time_(tok->args[0], &result->timestamp, strict_time_fmt, 0) < 0) { log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]); goto err; } /* Parse protocol versions. */ tok = find_by_keyword(tokens, R_PROTOCOL_VERSIONS); tor_assert(tok->n_args == 1); versions = smartlist_new(); smartlist_split_string(versions, tok->args[0], ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); for (i = 0; i < smartlist_len(versions); i++) { version = (int) tor_parse_long(smartlist_get(versions, i), 10, 0, INT_MAX, &num_ok, NULL); if (!num_ok) /* It's a string; let's ignore it. */ continue; if (version >= REND_PROTOCOL_VERSION_BITMASK_WIDTH) /* Avoid undefined left-shift behaviour. */ continue; result->protocols |= 1 << version; } SMARTLIST_FOREACH(versions, char *, cp, tor_free(cp)); smartlist_free(versions); /* Parse encrypted introduction points. Don't verify. */ tok = find_opt_by_keyword(tokens, R_INTRODUCTION_POINTS); if (tok) { if (strcmp(tok->object_type, "MESSAGE")) { log_warn(LD_DIR, "Bad object type: introduction points should be of " "type MESSAGE"); goto err; } *intro_points_encrypted_out = tor_memdup(tok->object_body, tok->object_size); *intro_points_encrypted_size_out = tok->object_size; } else { *intro_points_encrypted_out = NULL; *intro_points_encrypted_size_out = 0; } /* Parse and verify signature. */ tok = find_by_keyword(tokens, R_SIGNATURE); if (check_signature_token(desc_hash, DIGEST_LEN, tok, result->pk, 0, "v2 rendezvous service descriptor") < 0) goto err; /* Verify that descriptor ID belongs to public key and secret ID part. */ if (crypto_pk_get_digest(result->pk, public_key_hash) < 0) { log_warn(LD_REND, "Unable to compute rend descriptor public key digest"); goto err; } rend_get_descriptor_id_bytes(test_desc_id, public_key_hash, secret_id_part); if (tor_memneq(desc_id_out, test_desc_id, DIGEST_LEN)) { log_warn(LD_REND, "Parsed descriptor ID does not match " "computed descriptor ID."); goto err; } goto done; err: rend_service_descriptor_free(result); result = NULL; done: if (tokens) { SMARTLIST_FOREACH(tokens, directory_token_t *, t, token_clear(t)); smartlist_free(tokens); } if (area) memarea_drop_all(area); *parsed_out = result; if (result) return 0; return -1; }
/** * Load histogram from <b>state</b>, shuffling the resulting array * after we do so. Use this result to estimate parameters and * calculate the timeout. * * Return -1 on error. */ int circuit_build_times_parse_state(circuit_build_times_t *cbt, or_state_t *state) { int tot_values = 0; uint32_t loaded_cnt = 0, N = 0; config_line_t *line; unsigned int i; build_time_t *loaded_times; int err = 0; circuit_build_times_init(cbt); if (circuit_build_times_disabled()) { return 0; } /* build_time_t 0 means uninitialized */ loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes); for (line = state->BuildtimeHistogram; line; line = line->next) { smartlist_t *args = smartlist_new(); smartlist_split_string(args, line->value, " ", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); if (smartlist_len(args) < 2) { log_warn(LD_GENERAL, "Unable to parse circuit build times: " "Too few arguments to CircuitBuildTime"); err = 1; SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); break; } else { const char *ms_str = smartlist_get(args,0); const char *count_str = smartlist_get(args,1); uint32_t count, k; build_time_t ms; int ok; ms = (build_time_t)tor_parse_ulong(ms_str, 0, 0, CBT_BUILD_TIME_MAX, &ok, NULL); if (!ok) { log_warn(LD_GENERAL, "Unable to parse circuit build times: " "Unparsable bin number"); err = 1; SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); break; } count = (uint32_t)tor_parse_ulong(count_str, 0, 0, UINT32_MAX, &ok, NULL); if (!ok) { log_warn(LD_GENERAL, "Unable to parse circuit build times: " "Unparsable bin count"); err = 1; SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); break; } if (loaded_cnt+count+state->CircuitBuildAbandonedCount > state->TotalBuildTimes) { log_warn(LD_CIRC, "Too many build times in state file. " "Stopping short before %d", loaded_cnt+count); SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); break; } for (k = 0; k < count; k++) { loaded_times[loaded_cnt++] = ms; } N++; SMARTLIST_FOREACH(args, char*, cp, tor_free(cp)); smartlist_free(args); } } log_info(LD_CIRC, "Adding %d timeouts.", state->CircuitBuildAbandonedCount); for (i=0; i < state->CircuitBuildAbandonedCount; i++) { loaded_times[loaded_cnt++] = CBT_BUILD_ABANDONED; } if (loaded_cnt != state->TotalBuildTimes) { log_warn(LD_CIRC, "Corrupt state file? Build times count mismatch. " "Read %d times, but file says %d", loaded_cnt, state->TotalBuildTimes); err = 1; circuit_build_times_reset(cbt); goto done; } circuit_build_times_shuffle_and_store_array(cbt, loaded_times, loaded_cnt); /* Verify that we didn't overwrite any indexes */ for (i=0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) { if (!cbt->circuit_build_times[i]) break; tot_values++; } log_info(LD_CIRC, "Loaded %d/%d values from %d lines in circuit time histogram", tot_values, cbt->total_build_times, N); if (cbt->total_build_times != tot_values || cbt->total_build_times > CBT_NCIRCUITS_TO_OBSERVE) { log_warn(LD_CIRC, "Corrupt state file? Shuffled build times mismatch. " "Read %d times, but file says %d", tot_values, state->TotalBuildTimes); err = 1; circuit_build_times_reset(cbt); goto done; } circuit_build_times_set_timeout(cbt); if (!state->CircuitBuildAbandonedCount && cbt->total_build_times) { circuit_build_times_filter_timeouts(cbt); } done: tor_free(loaded_times); return err ? -1 : 0; }
/** Run unit tests for smartlist-of-strings functionality. */ static void test_container_smartlist_strings(void) { smartlist_t *sl = smartlist_new(); char *cp=NULL, *cp_alloc=NULL; size_t sz; /* Test split and join */ test_eq(0, smartlist_len(sl)); smartlist_split_string(sl, "abc", ":", 0, 0); test_eq(1, smartlist_len(sl)); test_streq("abc", smartlist_get(sl, 0)); smartlist_split_string(sl, "a::bc::", "::", 0, 0); test_eq(4, smartlist_len(sl)); test_streq("a", smartlist_get(sl, 1)); test_streq("bc", smartlist_get(sl, 2)); test_streq("", smartlist_get(sl, 3)); cp_alloc = smartlist_join_strings(sl, "", 0, NULL); test_streq(cp_alloc, "abcabc"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "!", 0, NULL); test_streq(cp_alloc, "abc!a!bc!"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL); test_streq(cp_alloc, "abcXYaXYbcXY"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL); test_streq(cp_alloc, "abcXYaXYbcXYXY"); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "", 1, NULL); test_streq(cp_alloc, "abcabc"); tor_free(cp_alloc); smartlist_split_string(sl, "/def/ /ghijk", "/", 0, 0); test_eq(8, smartlist_len(sl)); test_streq("", smartlist_get(sl, 4)); test_streq("def", smartlist_get(sl, 5)); test_streq(" ", smartlist_get(sl, 6)); test_streq("ghijk", smartlist_get(sl, 7)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); smartlist_split_string(sl, "a,bbd,cdef", ",", SPLIT_SKIP_SPACE, 0); test_eq(3, smartlist_len(sl)); test_streq("a", smartlist_get(sl,0)); test_streq("bbd", smartlist_get(sl,1)); test_streq("cdef", smartlist_get(sl,2)); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE, 0); test_eq(8, smartlist_len(sl)); test_streq("z", smartlist_get(sl,3)); test_streq("zhasd", smartlist_get(sl,4)); test_streq("", smartlist_get(sl,5)); test_streq("bnud", smartlist_get(sl,6)); test_streq("", smartlist_get(sl,7)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); smartlist_split_string(sl, " ab\tc \td ef ", NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(4, smartlist_len(sl)); test_streq("ab", smartlist_get(sl,0)); test_streq("c", smartlist_get(sl,1)); test_streq("d", smartlist_get(sl,2)); test_streq("ef", smartlist_get(sl,3)); smartlist_split_string(sl, "ghi\tj", NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(6, smartlist_len(sl)); test_streq("ghi", smartlist_get(sl,4)); test_streq("j", smartlist_get(sl,5)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL); test_streq(cp_alloc, ""); tor_free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL); test_streq(cp_alloc, "XY"); tor_free(cp_alloc); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(3, smartlist_len(sl)); test_streq("z", smartlist_get(sl, 0)); test_streq("zhasd", smartlist_get(sl, 1)); test_streq("bnud", smartlist_get(sl, 2)); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); test_eq(5, smartlist_len(sl)); test_streq("z", smartlist_get(sl, 3)); test_streq("zhasd <> <> bnud<>", smartlist_get(sl, 4)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); smartlist_split_string(sl, "abcd\n", "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(1, smartlist_len(sl)); test_streq("abcd", smartlist_get(sl, 0)); smartlist_split_string(sl, "efgh", "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); test_eq(2, smartlist_len(sl)); test_streq("efgh", smartlist_get(sl, 1)); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Test swapping, shuffling, and sorting. */ smartlist_split_string(sl, "the,onion,router,by,arma,and,nickm", ",", 0, 0); test_eq(7, smartlist_len(sl)); smartlist_sort(sl, compare_strs_); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc,"and,arma,by,nickm,onion,router,the"); tor_free(cp_alloc); smartlist_swap(sl, 1, 5); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc,"and,router,by,nickm,onion,arma,the"); tor_free(cp_alloc); smartlist_shuffle(sl); test_eq(7, smartlist_len(sl)); test_assert(smartlist_contains_string(sl, "and")); test_assert(smartlist_contains_string(sl, "router")); test_assert(smartlist_contains_string(sl, "by")); test_assert(smartlist_contains_string(sl, "nickm")); test_assert(smartlist_contains_string(sl, "onion")); test_assert(smartlist_contains_string(sl, "arma")); test_assert(smartlist_contains_string(sl, "the")); /* Test bsearch. */ smartlist_sort(sl, compare_strs_); test_streq("nickm", smartlist_bsearch(sl, "zNicKM", compare_without_first_ch_)); test_streq("and", smartlist_bsearch(sl, " AND", compare_without_first_ch_)); test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", compare_without_first_ch_)); /* Test bsearch_idx */ { int f; smartlist_t *tmp = NULL; test_eq(0, smartlist_bsearch_idx(sl," aaa",compare_without_first_ch_,&f)); test_eq(f, 0); test_eq(0, smartlist_bsearch_idx(sl," and",compare_without_first_ch_,&f)); test_eq(f, 1); test_eq(1, smartlist_bsearch_idx(sl," arm",compare_without_first_ch_,&f)); test_eq(f, 0); test_eq(1, smartlist_bsearch_idx(sl," arma",compare_without_first_ch_,&f)); test_eq(f, 1); test_eq(2, smartlist_bsearch_idx(sl," armb",compare_without_first_ch_,&f)); test_eq(f, 0); test_eq(7, smartlist_bsearch_idx(sl," zzzz",compare_without_first_ch_,&f)); test_eq(f, 0); /* Test trivial cases for list of length 0 or 1 */ tmp = smartlist_new(); test_eq(0, smartlist_bsearch_idx(tmp, "foo", compare_strs_for_bsearch_, &f)); test_eq(f, 0); smartlist_insert(tmp, 0, (void *)("bar")); test_eq(1, smartlist_bsearch_idx(tmp, "foo", compare_strs_for_bsearch_, &f)); test_eq(f, 0); test_eq(0, smartlist_bsearch_idx(tmp, "aaa", compare_strs_for_bsearch_, &f)); test_eq(f, 0); test_eq(0, smartlist_bsearch_idx(tmp, "bar", compare_strs_for_bsearch_, &f)); test_eq(f, 1); /* ... and one for length 2 */ smartlist_insert(tmp, 1, (void *)("foo")); test_eq(1, smartlist_bsearch_idx(tmp, "foo", compare_strs_for_bsearch_, &f)); test_eq(f, 1); test_eq(2, smartlist_bsearch_idx(tmp, "goo", compare_strs_for_bsearch_, &f)); test_eq(f, 0); smartlist_free(tmp); } /* Test reverse() and pop_last() */ smartlist_reverse(sl); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc,"the,router,onion,nickm,by,arma,and"); tor_free(cp_alloc); cp_alloc = smartlist_pop_last(sl); test_streq(cp_alloc, "and"); tor_free(cp_alloc); test_eq(smartlist_len(sl), 6); SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); cp_alloc = smartlist_pop_last(sl); test_eq_ptr(cp_alloc, NULL); /* Test uniq() */ smartlist_split_string(sl, "50,noon,radar,a,man,a,plan,a,canal,panama,radar,noon,50", ",", 0, 0); smartlist_sort(sl, compare_strs_); smartlist_uniq(sl, compare_strs_, tor_free_); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc, "50,a,canal,man,noon,panama,plan,radar"); tor_free(cp_alloc); /* Test contains_string, contains_string_case and contains_int_as_string */ test_assert(smartlist_contains_string(sl, "noon")); test_assert(!smartlist_contains_string(sl, "noonoon")); test_assert(smartlist_contains_string_case(sl, "nOOn")); test_assert(!smartlist_contains_string_case(sl, "nooNooN")); test_assert(smartlist_contains_int_as_string(sl, 50)); test_assert(!smartlist_contains_int_as_string(sl, 60)); /* Test smartlist_choose */ { int i; int allsame = 1; int allin = 1; void *first = smartlist_choose(sl); test_assert(smartlist_contains(sl, first)); for (i = 0; i < 100; ++i) { void *second = smartlist_choose(sl); if (second != first) allsame = 0; if (!smartlist_contains(sl, second)) allin = 0; } test_assert(!allsame); test_assert(allin); } SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_clear(sl); /* Test string_remove and remove and join_strings2 */ smartlist_split_string(sl, "Some say the Earth will end in ice and some in fire", " ", 0, 0); cp = smartlist_get(sl, 4); test_streq(cp, "will"); smartlist_add(sl, cp); smartlist_remove(sl, cp); tor_free(cp); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); test_streq(cp_alloc, "Some,say,the,Earth,fire,end,in,ice,and,some,in"); tor_free(cp_alloc); smartlist_string_remove(sl, "in"); cp_alloc = smartlist_join_strings2(sl, "+XX", 1, 0, &sz); test_streq(cp_alloc, "Some+say+the+Earth+fire+end+some+ice+and"); test_eq((int)sz, 40); done: SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); smartlist_free(sl); tor_free(cp_alloc); }
/* Test the configure_proxy() function. */ static void test_pt_configure_proxy(void *arg) { int i, retval; managed_proxy_t *mp = NULL; (void) arg; dummy_state = tor_malloc_zero(sizeof(or_state_t)); MOCK(process_read_stdout, process_read_stdout_replacement); MOCK(get_or_state, get_or_state_replacement); MOCK(queue_control_event_string, queue_control_event_string_replacement); control_testing_set_global_event_mask(EVENT_TRANSPORT_LAUNCHED); mp = tor_malloc_zero(sizeof(managed_proxy_t)); mp->conf_state = PT_PROTO_ACCEPTING_METHODS; mp->transports = smartlist_new(); mp->transports_to_launch = smartlist_new(); mp->argv = tor_malloc_zero(sizeof(char*)*2); mp->argv[0] = tor_strdup("<testcase>"); mp->is_server = 1; /* Configure the process. */ mp->process = process_new(""); process_set_stdout_read_callback(mp->process, managed_proxy_stdout_callback); process_set_data(mp->process, mp); /* Test the return value of configure_proxy() by calling it some times while it is uninitialized and then finally finalizing its configuration. */ for (i = 0 ; i < 5 ; i++) { /* force a read from our mocked stdout reader. */ process_notify_event_stdout(mp->process); /* try to configure our proxy. */ retval = configure_proxy(mp); /* retval should be zero because proxy hasn't finished configuring yet */ tt_int_op(retval, OP_EQ, 0); /* check the number of registered transports */ tt_int_op(smartlist_len(mp->transports), OP_EQ, i+1); /* check that the mp is still waiting for transports */ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); } /* Get the SMETHOD DONE written to the process. */ process_notify_event_stdout(mp->process); /* this last configure_proxy() should finalize the proxy configuration. */ retval = configure_proxy(mp); /* retval should be 1 since the proxy finished configuring */ tt_int_op(retval, OP_EQ, 1); /* check the mp state */ tt_assert(mp->conf_state == PT_PROTO_COMPLETED); tt_int_op(controlevent_n, OP_EQ, 5); tt_int_op(controlevent_event, OP_EQ, EVENT_TRANSPORT_LAUNCHED); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 5); smartlist_sort_strings(controlevent_msgs); tt_str_op(smartlist_get(controlevent_msgs, 0), OP_EQ, "650 TRANSPORT_LAUNCHED server mock1 127.0.0.1 5551\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 1), OP_EQ, "650 TRANSPORT_LAUNCHED server mock2 127.0.0.1 5552\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 2), OP_EQ, "650 TRANSPORT_LAUNCHED server mock3 127.0.0.1 5553\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 3), OP_EQ, "650 TRANSPORT_LAUNCHED server mock4 127.0.0.1 5554\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 4), OP_EQ, "650 TRANSPORT_LAUNCHED server mock5 127.0.0.1 5555\r\n"); /* Get the log message out. */ process_notify_event_stdout(mp->process); tt_int_op(controlevent_n, OP_EQ, 10); tt_int_op(controlevent_event, OP_EQ, EVENT_PT_LOG); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 10); tt_str_op(smartlist_get(controlevent_msgs, 5), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=error " "MESSAGE=\"Oh noes, " "something bad happened. What do we do!?\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 6), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=warning " "MESSAGE=\"warning msg\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 7), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=notice " "MESSAGE=\"notice msg\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 8), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=info " "MESSAGE=\"info msg\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 9), OP_EQ, "650 PT_LOG PT=<testcase> SEVERITY=debug " "MESSAGE=\"debug msg\"\r\n"); /* Get the STATUS messages out. */ process_notify_event_stdout(mp->process); tt_int_op(controlevent_n, OP_EQ, 13); tt_int_op(controlevent_event, OP_EQ, EVENT_PT_STATUS); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 13); tt_str_op(smartlist_get(controlevent_msgs, 10), OP_EQ, "650 PT_STATUS " "PT=<testcase> TRANSPORT=a K_1=a K_2=b K_3=\"foo bar\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 11), OP_EQ, "650 PT_STATUS " "PT=<testcase> TRANSPORT=b K_1=a K_2=b K_3=\"foo bar\"\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 12), OP_EQ, "650 PT_STATUS " "PT=<testcase> TRANSPORT=c K_1=a K_2=b K_3=\"foo bar\"\r\n"); { /* check that the transport info were saved properly in the tor state */ config_line_t *transport_in_state = NULL; smartlist_t *transport_info_sl = smartlist_new(); char *name_of_transport = NULL; char *bindaddr = NULL; /* Get the bindaddr for "mock1" and check it against the bindaddr that the mocked tor_get_lines_from_handle() generated. */ transport_in_state = get_transport_in_state_by_name("mock1"); tt_assert(transport_in_state); smartlist_split_string(transport_info_sl, transport_in_state->value, NULL, 0, 0); name_of_transport = smartlist_get(transport_info_sl, 0); bindaddr = smartlist_get(transport_info_sl, 1); tt_str_op(name_of_transport, OP_EQ, "mock1"); tt_str_op(bindaddr, OP_EQ, "127.0.0.1:5551"); SMARTLIST_FOREACH(transport_info_sl, char *, cp, tor_free(cp)); smartlist_free(transport_info_sl); } done: or_state_free(dummy_state); UNMOCK(process_read_stdout); UNMOCK(get_or_state); UNMOCK(queue_control_event_string); if (controlevent_msgs) { SMARTLIST_FOREACH(controlevent_msgs, char *, cp, tor_free(cp)); smartlist_free(controlevent_msgs); controlevent_msgs = NULL; } if (mp->transports) { SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_free(mp->transports); }
/** Make sure that we use GuardFraction information when we should, * according to the torrc option and consensus parameter. */ static void test_should_apply_guardfraction(void *arg) { networkstatus_t vote_enabled, vote_disabled, vote_missing; or_options_t *options = get_options_mutable(); (void) arg; { /* Fill the votes for later */ /* This one suggests enabled GuardFraction. */ memset(&vote_enabled, 0, sizeof(vote_enabled)); vote_enabled.net_params = smartlist_new(); smartlist_split_string(vote_enabled.net_params, "UseGuardFraction=1", NULL, 0, 0); /* This one suggests disabled GuardFraction. */ memset(&vote_disabled, 0, sizeof(vote_disabled)); vote_disabled.net_params = smartlist_new(); smartlist_split_string(vote_disabled.net_params, "UseGuardFraction=0", NULL, 0, 0); /* This one doesn't have GuardFraction at all. */ memset(&vote_missing, 0, sizeof(vote_missing)); vote_missing.net_params = smartlist_new(); smartlist_split_string(vote_missing.net_params, "leon=trout", NULL, 0, 0); } /* If torrc option is set to yes, we should always use * guardfraction.*/ options->UseGuardFraction = 1; tt_int_op(should_apply_guardfraction(&vote_disabled), ==, 1); /* If torrc option is set to no, we should never use * guardfraction.*/ options->UseGuardFraction = 0; tt_int_op(should_apply_guardfraction(&vote_enabled), ==, 0); /* Now let's test torrc option set to auto. */ options->UseGuardFraction = -1; /* If torrc option is set to auto, and consensus parameter is set to * yes, we should use guardfraction. */ tt_int_op(should_apply_guardfraction(&vote_enabled), ==, 1); /* If torrc option is set to auto, and consensus parameter is set to * no, we should use guardfraction. */ tt_int_op(should_apply_guardfraction(&vote_disabled), ==, 0); /* If torrc option is set to auto, and consensus parameter is not * set, we should fallback to "no". */ tt_int_op(should_apply_guardfraction(&vote_missing), ==, 0); done: SMARTLIST_FOREACH(vote_enabled.net_params, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(vote_disabled.net_params, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(vote_missing.net_params, char *, cp, tor_free(cp)); smartlist_free(vote_enabled.net_params); smartlist_free(vote_disabled.net_params); smartlist_free(vote_missing.net_params); }
/** Run unit tests for smartlist-of-strings functionality. */ static void test_container_smartlist_strings(void *unused) { smartlist_t *sl = smartlist_create(); char *cp=NULL, *cp_alloc=NULL; size_t sz; /* Test split and join */ tt_int_op(smartlist_len(sl), ==, 0); smartlist_split_string(sl, "abc", ":", 0, 0); tt_int_op(smartlist_len(sl), ==, 1); tt_str_op(smartlist_get(sl, 0), ==, "abc"); smartlist_split_string(sl, "a::bc::", "::", 0, 0); tt_int_op(smartlist_len(sl), ==, 4); tt_str_op(smartlist_get(sl, 1), ==, "a"); tt_str_op(smartlist_get(sl, 2), ==, "bc"); tt_str_op(smartlist_get(sl, 3), ==, ""); cp_alloc = smartlist_join_strings(sl, "", 0, NULL); tt_str_op(cp_alloc, ==, "abcabc"); free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "!", 0, NULL); tt_str_op(cp_alloc, ==, "abc!a!bc!"); free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL); tt_str_op(cp_alloc, ==, "abcXYaXYbcXY"); free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL); tt_str_op(cp_alloc, ==, "abcXYaXYbcXYXY"); free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "", 1, NULL); tt_str_op(cp_alloc, ==, "abcabc"); free(cp_alloc); smartlist_split_string(sl, "/def/ /ghijk", "/", 0, 0); tt_int_op(smartlist_len(sl), ==, 8); tt_str_op(smartlist_get(sl, 4), ==, ""); tt_str_op(smartlist_get(sl, 5), ==, "def"); tt_str_op(smartlist_get(sl, 6), ==, " "); tt_str_op(smartlist_get(sl, 7), ==, "ghijk"); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); smartlist_split_string(sl, "a,bbd,cdef", ",", SPLIT_SKIP_SPACE, 0); tt_int_op(smartlist_len(sl), ==, 3); tt_str_op(smartlist_get(sl,0), ==, "a"); tt_str_op(smartlist_get(sl,1), ==, "bbd"); tt_str_op(smartlist_get(sl,2), ==, "cdef"); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE, 0); tt_int_op(smartlist_len(sl), ==, 8); tt_str_op(smartlist_get(sl,3), ==, "z"); tt_str_op(smartlist_get(sl,4), ==, "zhasd"); tt_str_op(smartlist_get(sl,5), ==, ""); tt_str_op(smartlist_get(sl,6), ==, "bnud"); tt_str_op(smartlist_get(sl,7), ==, ""); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); smartlist_split_string(sl, " ab\tc \td ef ", NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); tt_int_op(smartlist_len(sl), ==, 4); tt_str_op(smartlist_get(sl,0), ==, "ab"); tt_str_op(smartlist_get(sl,1), ==, "c"); tt_str_op(smartlist_get(sl,2), ==, "d"); tt_str_op(smartlist_get(sl,3), ==, "ef"); smartlist_split_string(sl, "ghi\tj", NULL, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); tt_int_op(smartlist_len(sl), ==, 6); tt_str_op(smartlist_get(sl,4), ==, "ghi"); tt_str_op(smartlist_get(sl,5), ==, "j"); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL); tt_str_op(cp_alloc, ==, ""); free(cp_alloc); cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL); tt_str_op(cp_alloc, ==, "XY"); free(cp_alloc); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); tt_int_op(smartlist_len(sl), ==, 3); tt_str_op(smartlist_get(sl, 0), ==, "z"); tt_str_op(smartlist_get(sl, 1), ==, "zhasd"); tt_str_op(smartlist_get(sl, 2), ==, "bnud"); smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2); tt_int_op(smartlist_len(sl), ==, 5); tt_str_op(smartlist_get(sl, 3), ==, "z"); tt_str_op(smartlist_get(sl, 4), ==, "zhasd <> <> bnud<>"); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); smartlist_split_string(sl, "abcd\n", "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); tt_int_op(smartlist_len(sl), ==, 1); tt_str_op(smartlist_get(sl, 0), ==, "abcd"); smartlist_split_string(sl, "efgh", "\n", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); tt_int_op(smartlist_len(sl), ==, 2); tt_str_op(smartlist_get(sl, 1), ==, "efgh"); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); /* Test swapping, shuffling, and sorting. */ smartlist_split_string(sl, "the,onion,router,by,arma,and,nickm", ",", 0, 0); tt_int_op(smartlist_len(sl), ==, 7); smartlist_sort(sl, _compare_strs); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); tt_str_op(cp_alloc, ==, "and,arma,by,nickm,onion,router,the"); free(cp_alloc); smartlist_swap(sl, 1, 5); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); tt_str_op(cp_alloc, ==, "and,router,by,nickm,onion,arma,the"); free(cp_alloc); smartlist_shuffle(sl); tt_int_op(smartlist_len(sl), ==, 7); tt_assert(smartlist_string_isin(sl, "and")); tt_assert(smartlist_string_isin(sl, "router")); tt_assert(smartlist_string_isin(sl, "by")); tt_assert(smartlist_string_isin(sl, "nickm")); tt_assert(smartlist_string_isin(sl, "onion")); tt_assert(smartlist_string_isin(sl, "arma")); tt_assert(smartlist_string_isin(sl, "the")); /* Test bsearch. */ smartlist_sort(sl, _compare_strs); tt_str_op(smartlist_bsearch(sl, "zNicKM", _compare_without_first_ch), ==, "nickm"); tt_str_op(smartlist_bsearch(sl, " AND", _compare_without_first_ch), ==, "and"); tt_ptr_op(smartlist_bsearch(sl, " ANz", _compare_without_first_ch), ==, NULL); /* Test bsearch_idx */ { int f; tt_int_op(smartlist_bsearch_idx(sl," aaa",_compare_without_first_ch,&f), ==, 0); tt_int_op(f, ==, 0); tt_int_op(smartlist_bsearch_idx(sl," and",_compare_without_first_ch,&f), ==, 0); tt_int_op(f, ==, 1); tt_int_op(smartlist_bsearch_idx(sl," arm",_compare_without_first_ch,&f), ==, 1); tt_int_op(f, ==, 0); tt_int_op(smartlist_bsearch_idx(sl," arma",_compare_without_first_ch,&f), ==, 1); tt_int_op(f, ==, 1); tt_int_op(smartlist_bsearch_idx(sl," armb",_compare_without_first_ch,&f), ==, 2); tt_int_op(f, ==, 0); tt_int_op(smartlist_bsearch_idx(sl," zzzz",_compare_without_first_ch,&f), ==, 7); tt_int_op(f, ==, 0); } /* Test reverse() and pop_last() */ smartlist_reverse(sl); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); tt_str_op(cp_alloc, ==, "the,router,onion,nickm,by,arma,and"); free(cp_alloc); cp_alloc = smartlist_pop_last(sl); tt_str_op(cp_alloc, ==, "and"); free(cp_alloc); tt_int_op(smartlist_len(sl), ==, 6); SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); cp_alloc = smartlist_pop_last(sl); tt_ptr_op(cp_alloc, ==, NULL); /* Test uniq() */ smartlist_split_string(sl, "50,noon,radar,a,man,a,plan,a,canal,panama,radar,noon,50", ",", 0, 0); smartlist_sort(sl, _compare_strs); smartlist_uniq(sl, _compare_strs, free); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); tt_str_op(cp_alloc, ==, "50,a,canal,man,noon,panama,plan,radar"); free(cp_alloc); /* Test string_isin and isin_case and num_isin */ tt_assert(smartlist_string_isin(sl, "noon")); tt_assert(!smartlist_string_isin(sl, "noonoon")); tt_assert(smartlist_string_isin_case(sl, "nOOn")); tt_assert(!smartlist_string_isin_case(sl, "nooNooN")); tt_assert(smartlist_string_num_isin(sl, 50)); tt_assert(!smartlist_string_num_isin(sl, 60)); /* Test smartlist_choose */ { int i; int allsame = 1; int allin = 1; void *first = smartlist_choose(sl); tt_assert(smartlist_isin(sl, first)); for (i = 0; i < 100; ++i) { void *second = smartlist_choose(sl); if (second != first) allsame = 0; if (!smartlist_isin(sl, second)) allin = 0; } tt_assert(!allsame); tt_assert(allin); } SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_clear(sl); /* Test string_remove and remove and join_strings2 */ smartlist_split_string(sl, "Some say the Earth will end in ice and some in fire", " ", 0, 0); cp = smartlist_get(sl, 4); tt_str_op(cp, ==, "will"); smartlist_add(sl, cp); smartlist_remove(sl, cp); free(cp); cp_alloc = smartlist_join_strings(sl, ",", 0, NULL); tt_str_op(cp_alloc, ==, "Some,say,the,Earth,fire,end,in,ice,and,some,in"); free(cp_alloc); smartlist_string_remove(sl, "in"); cp_alloc = smartlist_join_strings2(sl, "+XX", 1, 0, &sz); tt_str_op(cp_alloc, ==, "Some+say+the+Earth+fire+end+some+ice+and"); tt_int_op((int)sz, ==, 40); end: SMARTLIST_FOREACH(sl, char *, cp, free(cp)); smartlist_free(sl); free(cp_alloc); }
/** Given: * comma-separated list of "<transport>-<bindaddr>" strings in 'all_bindaddrs'. * comma-separated list of "<transport>" strings in 'all_transports'. Return: * 0, if - all <transport> strings in 'all_bindaddrs' match with <transport> strings in 'all_transports' (order matters). AND - if all <bindaddr> strings in 'all_bindaddrs' are valid addrports. * -1, otherwise. */ int validate_bindaddrs(const char *all_bindaddrs, const char *all_transports) { int ret,i,n_bindaddrs,n_transports; struct evutil_addrinfo *bindaddr_test; char *bindaddr = NULL; char *transport = NULL; /* a list of "<proto>-<bindaddr>" strings */ smartlist_t *bindaddrs = smartlist_create(); /* a list holding (<proto>, <bindaddr>) for each 'bindaddrs' entry */ smartlist_t *split_bindaddr = NULL; /* a list of "<proto>" strings */ smartlist_t *transports = smartlist_create(); smartlist_split_string(bindaddrs, all_bindaddrs, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); smartlist_split_string(transports, all_transports, ",", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); n_bindaddrs = smartlist_len(bindaddrs); n_transports = smartlist_len(transports); if (n_bindaddrs != n_transports) goto err; for (i=0;i<n_bindaddrs;i++) { bindaddr = smartlist_get(bindaddrs, i); transport = smartlist_get(transports, i); split_bindaddr = smartlist_create(); smartlist_split_string(split_bindaddr, bindaddr, "-", SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1); /* (<proto>, <bindaddr>) */ if (smartlist_len(split_bindaddr) != 2) goto err; /* "all <transport> strings in 'all_bindaddrs' match with <transport> strings in 'all_transports' (order matters)." */ if (strcmp(smartlist_get(split_bindaddr,0), transport)) goto err; /* "if all <bindaddr> strings in 'all_bindaddrs' are valid addrports." */ bindaddr_test = resolve_address_port(smartlist_get(split_bindaddr, 1), 1, 1, NULL); if (!bindaddr_test) goto err; evutil_freeaddrinfo(bindaddr_test); SMARTLIST_FOREACH(split_bindaddr, char *, cp, free(cp)); smartlist_free(split_bindaddr); split_bindaddr = NULL; } ret = 0; goto done; err: ret = -1; done: SMARTLIST_FOREACH(bindaddrs, char *, cp, free(cp)); smartlist_free(bindaddrs); SMARTLIST_FOREACH(transports, char *, cp, free(cp)); smartlist_free(transports); if (split_bindaddr) { SMARTLIST_FOREACH(split_bindaddr, char *, cp, free(cp)); smartlist_free(split_bindaddr); } return ret; }
/* Test the configure_proxy() function. */ static void test_pt_configure_proxy(void *arg) { int i, retval; managed_proxy_t *mp = NULL; (void) arg; dummy_state = tor_malloc_zero(sizeof(or_state_t)); MOCK(tor_get_lines_from_handle, tor_get_lines_from_handle_replacement); MOCK(tor_process_handle_destroy, tor_process_handle_destroy_replacement); MOCK(get_or_state, get_or_state_replacement); MOCK(queue_control_event_string, queue_control_event_string_replacement); control_testing_set_global_event_mask(EVENT_TRANSPORT_LAUNCHED); mp = tor_malloc_zero(sizeof(managed_proxy_t)); mp->conf_state = PT_PROTO_ACCEPTING_METHODS; mp->transports = smartlist_new(); mp->transports_to_launch = smartlist_new(); mp->process_handle = tor_malloc_zero(sizeof(process_handle_t)); mp->argv = tor_malloc_zero(sizeof(char*)*2); mp->argv[0] = tor_strdup("<testcase>"); mp->is_server = 1; /* Test the return value of configure_proxy() by calling it some times while it is uninitialized and then finally finalizing its configuration. */ for (i = 0 ; i < 5 ; i++) { retval = configure_proxy(mp); /* retval should be zero because proxy hasn't finished configuring yet */ tt_int_op(retval, OP_EQ, 0); /* check the number of registered transports */ tt_assert(smartlist_len(mp->transports) == i+1); /* check that the mp is still waiting for transports */ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS); } /* this last configure_proxy() should finalize the proxy configuration. */ retval = configure_proxy(mp); /* retval should be 1 since the proxy finished configuring */ tt_int_op(retval, OP_EQ, 1); /* check the mp state */ tt_assert(mp->conf_state == PT_PROTO_COMPLETED); tt_int_op(controlevent_n, OP_EQ, 5); tt_int_op(controlevent_event, OP_EQ, EVENT_TRANSPORT_LAUNCHED); tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 5); smartlist_sort_strings(controlevent_msgs); tt_str_op(smartlist_get(controlevent_msgs, 0), OP_EQ, "650 TRANSPORT_LAUNCHED server mock1 127.0.0.1 5551\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 1), OP_EQ, "650 TRANSPORT_LAUNCHED server mock2 127.0.0.1 5552\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 2), OP_EQ, "650 TRANSPORT_LAUNCHED server mock3 127.0.0.1 5553\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 3), OP_EQ, "650 TRANSPORT_LAUNCHED server mock4 127.0.0.1 5554\r\n"); tt_str_op(smartlist_get(controlevent_msgs, 4), OP_EQ, "650 TRANSPORT_LAUNCHED server mock5 127.0.0.1 5555\r\n"); { /* check that the transport info were saved properly in the tor state */ config_line_t *transport_in_state = NULL; smartlist_t *transport_info_sl = smartlist_new(); char *name_of_transport = NULL; char *bindaddr = NULL; /* Get the bindaddr for "mock1" and check it against the bindaddr that the mocked tor_get_lines_from_handle() generated. */ transport_in_state = get_transport_in_state_by_name("mock1"); tt_assert(transport_in_state); smartlist_split_string(transport_info_sl, transport_in_state->value, NULL, 0, 0); name_of_transport = smartlist_get(transport_info_sl, 0); bindaddr = smartlist_get(transport_info_sl, 1); tt_str_op(name_of_transport, OP_EQ, "mock1"); tt_str_op(bindaddr, OP_EQ, "127.0.0.1:5551"); SMARTLIST_FOREACH(transport_info_sl, char *, cp, tor_free(cp)); smartlist_free(transport_info_sl); } done: or_state_free(dummy_state); UNMOCK(tor_get_lines_from_handle); UNMOCK(tor_process_handle_destroy); UNMOCK(get_or_state); UNMOCK(queue_control_event_string); if (controlevent_msgs) { SMARTLIST_FOREACH(controlevent_msgs, char *, cp, tor_free(cp)); smartlist_free(controlevent_msgs); controlevent_msgs = NULL; } if (mp->transports) { SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t)); smartlist_free(mp->transports); }