aboutsummaryrefslogtreecommitdiff
path: root/src/lib/intmath/bits.h
blob: 80eebe93589fe613d90990e7e8737bcdbcf85f48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* Copyright (c) 2003-2004, Roger Dingledine
 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
 * Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file bits.h
 *
 * \brief Header for bits.c
 **/

#ifndef TOR_INTMATH_BITS_H
#define TOR_INTMATH_BITS_H

#include "lib/cc/torint.h"
#include "lib/cc/compat_compiler.h"

int tor_log2(uint64_t u64) ATTR_CONST;
uint64_t round_to_power_of_2(uint64_t u64);
int n_bits_set_u8(uint8_t v);

#endif /* !defined(TOR_INTMATH_BITS_H) */
href='#n237'>237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
/* Copyright (c) 2018-2019, The Tor Project, Inc. */
/* See LICENSE for licensing information */

/**
 * \file test_periodic_event.c
 * \brief Test the periodic events that Tor uses for different roles. They are
 *        part of the libevent mainloop
 */

#define CONFIG_PRIVATE
#define HS_SERVICE_PRIVATE
#define MAINLOOP_PRIVATE

#include "test/test.h"
#include "test/test_helpers.h"

#include "core/or/or.h"
#include "app/config/config.h"
#include "feature/hibernate/hibernate.h"
#include "feature/hs/hs_service.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/periodic.h"

/** Helper function: This is replaced in some tests for the event callbacks so
 * we don't actually go into the code path of those callbacks. */
static int
dumb_event_fn(time_t now, const or_options_t *options)
{
  (void) now;
  (void) options;

  /* Will get rescheduled in 300 seconds. It just can't be 0. */
  return 300;
}

static void
register_dummy_hidden_service(hs_service_t *service)
{
  memset(service, 0, sizeof(hs_service_t));
  memset(&service->keys.identity_pk, 'A', sizeof(service->keys.identity_pk));
  (void) register_service(get_hs_service_map(), service);
}

static void
test_pe_initialize(void *arg)
{
  (void) arg;

  /* Initialize the events but the callback won't get called since we would
   * need to run the main loop and then wait for a second delaying the unit
   * tests. Instead, we'll test the callback work indepedently elsewhere. */
  initialize_periodic_events();

  /* Validate that all events have been set up. */
  for (int i = 0; periodic_events[i].name; ++i) {
    periodic_event_item_t *item = &periodic_events[i];
    tt_assert(item->ev);
    tt_assert(item->fn);
    tt_u64_op(item->last_action_time, OP_EQ, 0);
    /* Every event must have role(s) assign to it. This is done statically. */
    tt_u64_op(item->roles, OP_NE, 0);
    tt_uint_op(periodic_event_is_enabled(item), OP_EQ, 0);
  }

 done:
  teardown_periodic_events();
}

static void
test_pe_launch(void *arg)
{
  hs_service_t service, *to_remove = NULL;
  or_options_t *options;

  (void) arg;

  hs_init();
  /* We need to put tor in hibernation live state so the events requiring
   * network gets enabled. */
  consider_hibernation(time(NULL));

  /* Hack: We'll set a dumb fn() of each events so they don't get called when
   * dispatching them. We just want to test the state of the callbacks, not
   * the whole code path. */
  for (int i = 0; periodic_events[i].name; ++i) {
    periodic_event_item_t *item = &periodic_events[i];
    item->fn = dumb_event_fn;
  }

  options = get_options_mutable();
  options->SocksPort_set = 1;
  periodic_events_on_new_options(options);
#if 0
  /* Lets make sure that before intialization, we can't scan the periodic
   * events list and launch them. Lets try by being a Client. */
  /* XXXX We make sure these events are initialized now way earlier than we
   * did before. */
  for (int i = 0; periodic_events[i].name; ++i) {
    periodic_event_item_t *item = &periodic_events[i];
    tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
  }
#endif

  initialize_periodic_events();

  /* Now that we've initialized, rescan the list to launch. */
  periodic_events_on_new_options(options);

  for (int i = 0; periodic_events[i].name; ++i) {
    periodic_event_item_t *item = &periodic_events[i];
    if (item->roles & PERIODIC_EVENT_ROLE_CLIENT) {
      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
    } else {
      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
    }
    // enabled or not, the event has not yet been run.
    tt_u64_op(item->last_action_time, OP_EQ, 0);
  }

  /* Remove Client but become a Relay. */
  options->SocksPort_set = 0;
  options->ORPort_set = 1;
  periodic_events_on_new_options(options);

  unsigned roles = get_my_roles(options);
  tt_uint_op(roles, OP_EQ,
             PERIODIC_EVENT_ROLE_RELAY|PERIODIC_EVENT_ROLE_DIRSERVER);

  for (int i = 0; periodic_events[i].name; ++i) {
    periodic_event_item_t *item = &periodic_events[i];
    /* Only Client role should be disabled. */
    if (item->roles == PERIODIC_EVENT_ROLE_CLIENT) {
      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
    }
    if (item->roles & PERIODIC_EVENT_ROLE_RELAY) {
      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
    }
    /* Non Relay role should be disabled, except for Dirserver. */
    if (!(item->roles & roles)) {
      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
    }
  }

  /* Disable everything and we'll enable them ALL. */
  options->SocksPort_set = 0;
  options->ORPort_set = 0;
  periodic_events_on_new_options(options);

  for (int i = 0; periodic_events[i].name; ++i) {
    periodic_event_item_t *item = &periodic_events[i];
    tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
  }

  /* Enable everything. */
  options->SocksPort_set = 1; options->ORPort_set = 1;
  options->BridgeRelay = 1; options->AuthoritativeDir = 1;
  options->V3AuthoritativeDir = 1; options->BridgeAuthoritativeDir = 1;
  register_dummy_hidden_service(&service);
  periodic_events_on_new_options(options);
  /* Note down the reference because we need to remove this service from the
   * global list before the hs_free_all() call so it doesn't try to free
   * memory on the stack. Furthermore, we can't remove it now else it will
   * trigger a rescan of the event disabling the HS service event. */
  to_remove = &service;

  for (int i = 0; periodic_events[i].name; ++i) {
    periodic_event_item_t *item = &periodic_events[i];
    tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
  }

 done:
  if (to_remove) {
    remove_service(get_hs_service_map(), to_remove);
  }
  hs_free_all();
}

static void
test_pe_get_roles(void *arg)
{
  int roles;

  (void) arg;

  /* Just so the HS global map exists. */
  hs_init();

  or_options_t *options = get_options_mutable();
  tt_assert(options);

  /* Nothing configured, should be no roles. */
  roles = get_my_roles(options);
  tt_int_op(roles, OP_EQ, 0);

  /* Indicate we have a SocksPort, roles should be come Client. */
  options->SocksPort_set = 1;
  roles = get_my_roles(options);
  tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_CLIENT);

  /* Now, we'll add a ORPort so should now be a Relay + Client. */
  options->ORPort_set = 1;
  roles = get_my_roles(options);
  tt_int_op(roles, OP_EQ,
            (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
             PERIODIC_EVENT_ROLE_DIRSERVER));

  /* Now add a Bridge. */
  options->BridgeRelay = 1;
  roles = get_my_roles(options);
  tt_int_op(roles, OP_EQ,
            (PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
             PERIODIC_EVENT_ROLE_BRIDGE | PERIODIC_EVENT_ROLE_DIRSERVER));
  tt_assert(roles & PERIODIC_EVENT_ROLE_ROUTER);
  /* Unset client so we can solely test Router role. */
  options->SocksPort_set = 0;
  roles = get_my_roles(options);
  tt_int_op(roles, OP_EQ,
            PERIODIC_EVENT_ROLE_ROUTER | PERIODIC_EVENT_ROLE_DIRSERVER);

  /* Reset options so we can test authorities. */
  options->SocksPort_set = 0;
  options->ORPort_set = 0;
  options->BridgeRelay = 0;
  roles = get_my_roles(options);
  tt_int_op(roles, OP_EQ, 0);

  /* Now upgrade to Dirauth. */
  options->DirPort_set = 1;
  options->AuthoritativeDir = 1;
  options->V3AuthoritativeDir = 1;
  roles = get_my_roles(options);
  tt_int_op(roles, OP_EQ,
            PERIODIC_EVENT_ROLE_DIRAUTH|PERIODIC_EVENT_ROLE_DIRSERVER);
  tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);

  /* Now Bridge Authority. */
  options->V3AuthoritativeDir = 0;
  options->BridgeAuthoritativeDir = 1;
  roles = get_my_roles(options);
  tt_int_op(roles, OP_EQ,
            PERIODIC_EVENT_ROLE_BRIDGEAUTH|PERIODIC_EVENT_ROLE_DIRSERVER);
  tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);

  /* Move that bridge auth to become a relay. */
  options->ORPort_set = 1;
  roles = get_my_roles(options);
  tt_int_op(roles, OP_EQ,
            (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY
             | PERIODIC_EVENT_ROLE_DIRSERVER));
  tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);

  /* And now an Hidden service. */
  hs_service_t service;
  register_dummy_hidden_service(&service);
  roles = get_my_roles(options);
  /* Remove it now so the hs_free_all() doesn't try to free stack memory. */
  remove_service(get_hs_service_map(), &service);
  tt_int_op(roles, OP_EQ,
            (PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY |
             PERIODIC_EVENT_ROLE_HS_SERVICE | PERIODIC_EVENT_ROLE_DIRSERVER));
  tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);

 done:
  hs_free_all();
}

static void
test_pe_hs_service(void *arg)
{
  hs_service_t service, *to_remove = NULL;

  (void) arg;

  hs_init();
  /* We need to put tor in hibernation live state so the events requiring
   * network gets enabled. */
  consider_hibernation(time(NULL));
  /* Initialize the events so we can enable them */
  initialize_periodic_events();

  /* Hack: We'll set a dumb fn() of each events so they don't get called when
   * dispatching them. We just want to test the state of the callbacks, not
   * the whole code path. */
  for (int i = 0; periodic_events[i].name; ++i) {
    periodic_event_item_t *item = &periodic_events[i];
    item->fn = dumb_event_fn;
  }

  /* This should trigger a rescan of the list and enable the HS service
   * events. */
  register_dummy_hidden_service(&service);
  /* Note down the reference because we need to remove this service from the
   * global list before the hs_free_all() call so it doesn't try to free
   * memory on the stack. Furthermore, we can't remove it now else it will
   * trigger a rescan of the event disabling the HS service event. */
  to_remove = &service;

  for (int i = 0; periodic_events[i].name; ++i) {
    periodic_event_item_t *item = &periodic_events[i];
    if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) {
      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
    }
  }
  to_remove = NULL;

  /* Remove the service from the global map, it should trigger a rescan and
   * disable the HS service events. */
  remove_service(get_hs_service_map(), &service);
  for (int i = 0; periodic_events[i].name; ++i) {
    periodic_event_item_t *item = &periodic_events[i];
    if (item->roles & PERIODIC_EVENT_ROLE_HS_SERVICE) {
      tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
    }
  }

 done:
  if (to_remove) {
    remove_service(get_hs_service_map(), to_remove);
  }
  hs_free_all();
}

#define PE_TEST(name) \
  { #name, test_pe_## name , TT_FORK, NULL, NULL }

struct testcase_t periodic_event_tests[] = {
  PE_TEST(initialize),
  PE_TEST(launch),
  PE_TEST(get_roles),
  PE_TEST(hs_service),

  END_OF_TESTCASES
};