/* Copyright (c) 2001 Matej Pfajfar.
 * Copyright (c) 2001-2004, Roger Dingledine.
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * @file dirclient_modes.c
 * @brief Functions to answer questions about how we'd like to behave
 *     as a directory client
 **/

#include "orconfig.h"

#include "core/or/or.h"

#include "feature/dirclient/dirclient_modes.h"
#include "feature/dircache/dirserv.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/stats/predict_ports.h"

#include "app/config/or_options_st.h"
#include "feature/nodelist/routerinfo_st.h"

/* Should this tor instance only use begindir for all its directory requests?
 */
int
dirclient_must_use_begindir(const or_options_t *options)
{
  /* Clients, onion services, and bridges must use begindir,
   * relays and authorities do not have to */
  return !public_server_mode(options);
}

/** Return 1 if we fetch our directory material directly from the
 * authorities, rather than from a mirror. */
int
dirclient_fetches_from_authorities(const or_options_t *options)
{
  const routerinfo_t *me;
  uint32_t addr;
  int refuseunknown;
  if (options->FetchDirInfoEarly)
    return 1;
  if (options->BridgeRelay == 1)
    return 0;
  if (server_mode(options) &&
      router_pick_published_address(options, &addr, 1) < 0)
    return 1; /* we don't know our IP address; ask an authority. */
  refuseunknown = ! router_my_exit_policy_is_reject_star() &&
    should_refuse_unknown_exits(options);
  if (!dir_server_mode(options) && !refuseunknown)
    return 0;
  if (!server_mode(options) || !advertised_server_mode())
    return 0;
  me = router_get_my_routerinfo();
  if (!me || (!me->supports_tunnelled_dir_requests && !refuseunknown))
    return 0; /* if we don't service directory requests, return 0 too */
  return 1;
}

/** Return 1 if we should fetch new networkstatuses, descriptors, etc
 * on the "mirror" schedule rather than the "client" schedule.
 */
int
dirclient_fetches_dir_info_early(const or_options_t *options)
{
  return dirclient_fetches_from_authorities(options);
}

/** Return 1 if we should fetch new networkstatuses, descriptors, etc
 * on a very passive schedule -- waiting long enough for ordinary clients
 * to probably have the info we want. These would include bridge users,
 * and maybe others in the future e.g. if a Tor client uses another Tor
 * client as a directory guard.
 */
int
dirclient_fetches_dir_info_later(const or_options_t *options)
{
  return options->UseBridges != 0;
}

/** Return 1 if we have no need to fetch new descriptors. This generally
 * happens when we're not a dir cache and we haven't built any circuits
 * lately.
 */
int
dirclient_too_idle_to_fetch_descriptors(const or_options_t *options,
                                        time_t now)
{
  return !directory_caches_dir_info(options) &&
         !options->FetchUselessDescriptors &&
         rep_hist_circbuilding_dormant(now);
}
