#include "feature/hs_common/shared_random_client.h"
#include "app/config/config.h"
#include "feature/dirauth/authmode.h"
#include "feature/dirauth/voting_schedule.h"
#include "feature/nodelist/microdesc.h"
#include "feature/nodelist/networkstatus.h"
#include "lib/encoding/binascii.h"
#include "feature/nodelist/networkstatus_st.h"
static char *
srv_to_control_string(const sr_srv_t *srv)
{
char *srv_str;
char srv_hash_encoded[SR_SRV_VALUE_BASE64_LEN + 1];
tor_assert(srv);
sr_srv_encode(srv_hash_encoded, sizeof(srv_hash_encoded), srv);
tor_asprintf(&srv_str, "%s", srv_hash_encoded);
return srv_str;
}
#define DEFAULT_NETWORK_VOTING_INTERVAL (3600)
#define TESTING_DEFAULT_NETWORK_VOTING_INTERVAL (20)
#ifdef TOR_UNIT_TESTS
#define ASSUME_AUTHORITY_SCHEDULING 1
#else
#define ASSUME_AUTHORITY_SCHEDULING 0
#endif
int
get_voting_interval(void)
{
int interval;
networkstatus_t *consensus =
networkstatus_get_reasonably_live_consensus(time(NULL),
usable_consensus_flavor());
if (consensus) {
interval = (int)(consensus->fresh_until - consensus->valid_after);
} else if (authdir_mode(get_options()) || ASSUME_AUTHORITY_SCHEDULING) {
interval = dirauth_sched_get_configured_interval();
} else if ((consensus = networkstatus_get_latest_consensus())) {
interval = (int)(consensus->fresh_until - consensus->valid_after);
} else {
if (get_options()->TestingTorNetwork) {
interval = TESTING_DEFAULT_NETWORK_VOTING_INTERVAL;
} else {
interval = DEFAULT_NETWORK_VOTING_INTERVAL;
}
}
tor_assert(interval > 0);
return interval;
}
void
sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv)
{
int ret;
char buf[SR_SRV_VALUE_BASE64_LEN + 1];
tor_assert(dst);
tor_assert(srv);
tor_assert(dst_len >= sizeof(buf));
ret = base64_encode(buf, sizeof(buf), (const char *) srv->value,
sizeof(srv->value), 0);
tor_assert(ret == (sizeof(buf) - 1));
tor_assert(ret <= (int) dst_len);
strlcpy(dst, buf, dst_len);
}
char *
sr_get_current_for_control(void)
{
char *srv_str;
const networkstatus_t *c = networkstatus_get_latest_consensus();
if (c && c->sr_info.current_srv) {
srv_str = srv_to_control_string(c->sr_info.current_srv);
} else {
srv_str = tor_strdup("");
}
return srv_str;
}
char *
sr_get_previous_for_control(void)
{
char *srv_str;
const networkstatus_t *c = networkstatus_get_latest_consensus();
if (c && c->sr_info.previous_srv) {
srv_str = srv_to_control_string(c->sr_info.previous_srv);
} else {
srv_str = tor_strdup("");
}
return srv_str;
}
const sr_srv_t *
sr_get_current(const networkstatus_t *ns)
{
const networkstatus_t *consensus;
if (ns) {
consensus = ns;
} else {
consensus = networkstatus_get_reasonably_live_consensus(approx_time(),
usable_consensus_flavor());
}
tor_assert_nonfatal(consensus);
if (consensus) {
return consensus->sr_info.current_srv;
}
return NULL;
}
const sr_srv_t *
sr_get_previous(const networkstatus_t *ns)
{
const networkstatus_t *consensus;
if (ns) {
consensus = ns;
} else {
consensus = networkstatus_get_reasonably_live_consensus(approx_time(),
usable_consensus_flavor());
}
tor_assert_nonfatal(consensus);
if (consensus) {
return consensus->sr_info.previous_srv;
}
return NULL;
}
sr_srv_t *
sr_parse_srv(const smartlist_t *args)
{
char *value;
int ok, ret;
uint64_t num_reveals;
sr_srv_t *srv = NULL;
tor_assert(args);
if (smartlist_len(args) < 2) {
goto end;
}
num_reveals = tor_parse_uint64(smartlist_get(args, 0),
10, 0, UINT64_MAX, &ok, NULL);
if (!ok) {
goto end;
}
value = smartlist_get(args, 1);
if (strlen(value) != SR_SRV_VALUE_BASE64_LEN) {
goto end;
}
srv = tor_malloc_zero(sizeof(*srv));
srv->num_reveals = num_reveals;
ret = base64_decode((char *) srv->value, sizeof(srv->value), value,
SR_SRV_VALUE_BASE64_LEN - 1);
if (ret != sizeof(srv->value)) {
tor_free(srv);
srv = NULL;
goto end;
}
end:
return srv;
}
time_t
sr_state_get_start_time_of_current_protocol_run(void)
{
int total_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES;
int voting_interval = get_voting_interval();
time_t beginning_of_curr_round;
networkstatus_t *ns =
networkstatus_get_reasonably_live_consensus(approx_time(),
usable_consensus_flavor());
if (ns) {
beginning_of_curr_round = ns->valid_after;
} else if (authdir_mode(get_options()) || ASSUME_AUTHORITY_SCHEDULING) {
beginning_of_curr_round = dirauth_sched_get_cur_valid_after_time();
} else {
beginning_of_curr_round = voting_sched_get_start_of_interval_after(
approx_time() - voting_interval,
voting_interval,
0);
}
int curr_round_slot;
curr_round_slot = (beginning_of_curr_round / voting_interval) % total_rounds;
time_t time_elapsed_since_start_of_run = curr_round_slot * voting_interval;
return beginning_of_curr_round - time_elapsed_since_start_of_run;
}
time_t
sr_state_get_start_time_of_previous_protocol_run(void)
{
time_t start_time_of_current_run =
sr_state_get_start_time_of_current_protocol_run();
return start_time_of_current_run - sr_state_get_protocol_run_duration();
}
unsigned int
sr_state_get_phase_duration(void)
{
return SHARED_RANDOM_N_ROUNDS * get_voting_interval();
}
unsigned int
sr_state_get_protocol_run_duration(void)
{
int total_protocol_rounds = SHARED_RANDOM_N_ROUNDS * SHARED_RANDOM_N_PHASES;
return total_protocol_rounds * get_voting_interval();
}