<commit_before>#include "catch.hpp"
#include <iostream>
#include "Database_Creator.hpp"
#include "Database_Sorter.hpp"

person readPerson(std::string file_name, size_t index) {
	person result;
	std::ifstream file(file_name);
	for (size_t i = 0; i < index + 1; i++) {
		file >> result;
	}
	file.close();
	return result;
}
/*bool isALessThanB(char A, char B, bool is_capital) {
	std::string alphabet;
	if (is_capital) {
		alphabet = " АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
	}
	else {
		alphabet = " абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
	}
	size_t A_i;
	size_t B_i;
	for (size_t i = 0; i < alphabet.size(); i++) {
		if (alphabet[i] == A) {
			A_i = i;
		}
		if (alphabet[i] == B) {
			B_i = i;
		}
	}
	return A_i < B_i;
}*/
bool isANotMoreThanB(person A, person B) {
	for (size_t i = 0; i < A.surname.length(); i++) {
		char A_char = A.surname[i];
		char B_char = (i < B.surname.length()) ? B.surname[i] : ' ';
		if (letterI(A.surname[i], i == 0) < letterI(B.surname[i], i == 0)) {
			return true;
		}
		else {
			if (A.surname[i] != B.surname[i]) {
				return false;
			}
		}
	}
	return true;
}
SCENARIO("LetterI", "[l]") {
   REQUIRE(letterI('A', true) == 1);
   REQUIRE(letterI('d', false) == 4);
}
SCENARIO("Sort", "[s]") {
	//setlocale(LC_ALL, "ru_RU.utf8");
	std::ifstream ru("russian_letters.txt");
	for (size_t i = 0; i < 6; i++) {
		std::string str;
		ru >> str;
		russian_letters[i] = str[0];
	}
	ru.close();
	size_t n_persons = 2001;
	size_t RAM_amount = 10000;
	std::string names_file_name = "Names";
	std::string surnames_file_name = "Surnames";
	std::string database_file_name = "database.txt";
	std::string output_file_name = "sorted_database.txt";
	{
		Database_Creator database_creator(database_file_name, names_file_name, surnames_file_name, n_persons);
		Database_Sorter database_sorter(database_file_name, output_file_name, RAM_amount);
		size_t start = clock();
		database_sorter.sortDatabase();
		size_t result = clock() - start;
		std::cout << result << std::endl;
		system("pause");
	}

	for (size_t i = 0; i < 25; i++) {
		size_t person1_i = rand() % n_persons;
		size_t person2_i = person1_i + rand() % (n_persons - person1_i);
		person person1 = readPerson(output_file_name, person1_i);
		person person2 = readPerson(output_file_name, person2_i);
		REQUIRE(isANotMoreThanB(person1, person2));
	}

	/*std::string str = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
	REQUIRE(letterI(str[1], true) == 2);
	REQUIRE(letterI(str[2], true) == 3);
	REQUIRE(letterI(str[3], true) == 4);
	REQUIRE(letterI(str[4], true) == 5);*/
}
<commit_msg>Update init.cpp<commit_after>#include "catch.hpp"
#include <iostream>
#include "Database_Creator.hpp"
#include "Database_Sorter.hpp"

person readPerson(std::string file_name, size_t index) {
	person result;
	std::ifstream file(file_name);
	for (size_t i = 0; i < index + 1; i++) {
		file >> result;
	}
	file.close();
	return result;
}
/*bool isALessThanB(char A, char B, bool is_capital) {
	std::string alphabet;
	if (is_capital) {
		alphabet = " АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
	}
	else {
		alphabet = " абвгдеёжзийклмнопрстуфхцчшщъыьэюя";
	}
	size_t A_i;
	size_t B_i;
	for (size_t i = 0; i < alphabet.size(); i++) {
		if (alphabet[i] == A) {
			A_i = i;
		}
		if (alphabet[i] == B) {
			B_i = i;
		}
	}
	return A_i < B_i;
}*/
bool isANotMoreThanB(person A, person B) {
	for (size_t i = 0; i < A.surname.length(); i++) {
		char A_char = A.surname[i];
		char B_char = (i < B.surname.length()) ? B.surname[i] : ' ';
		if (letterI(A.surname[i], i == 0) < letterI(B.surname[i], i == 0)) {
			return true;
		}
		else {
			if (A.surname[i] != B.surname[i]) {
				return false;
			}
		}
	}
	return true;
}
SCENARIO("LetterI", "[l]") {
   REQUIRE(letterI('A', true) == 1);
   REQUIRE(letterI('d', false) == 4);
}
SCENARIO("Sort", "[s]") {
	//setlocale(LC_ALL, "ru_RU.utf8");
	std::ifstream ru("russian_letters.txt");
	for (size_t i = 0; i < 6; i++) {
		std::string str;
		ru >> str;
		russian_letters[i] = str[0];
	}
	ru.close();
	size_t n_persons = 2001;
	size_t RAM_amount = 10000;
	std::string names_file_name = "Names";
	std::string surnames_file_name = "Surnames";
	std::string database_file_name = "database.txt";
	std::string output_file_name = "sorted_database.txt";
	{
		Database_Creator database_creator(database_file_name, names_file_name, surnames_file_name, n_persons);
		Database_Sorter database_sorter(database_file_name, output_file_name, RAM_amount);
		size_t start = clock();
		database_sorter.sortDatabase();
		size_t result = clock() - start;
		std::cout << result << std::endl;
		system("pause");
	}

	for (size_t i = 0; i < 250; i++) {
		size_t person1_i = rand() % n_persons;
		size_t person2_i = person1_i + rand() % (n_persons - person1_i);
                REQUIRE(person1_i < person2_i);
		person person1 = readPerson(output_file_name, person1_i);
		person person2 = readPerson(output_file_name, person2_i);
		REQUIRE(isANotMoreThanB(person1, person2));
	}

	/*std::string str = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";
	REQUIRE(letterI(str[1], true) == 2);
	REQUIRE(letterI(str[2], true) == 3);
	REQUIRE(letterI(str[3], true) == 4);
	REQUIRE(letterI(str[4], true) == 5);*/
}
<|endoftext|>


<commit_before>#include <stack.hpp>
#include <catch.hpp>

SCENARIO("init", "[init]") {
	stack<int> A;
	REQUIRE(A.array_size_() == 0);
	REQUIRE(A.count_() == 0);
}

SCENARIO("Push", "[push]") {
	stack<int> A;
	A.push(1);
	A.push(2);
	REQUIRE(A.count_() == 2));
}

SCENARIO("Pop", "[pop]") {
	stack<int> A;
	A.push(1);
	A.push(2);
	A.pop();
	REQUIRE(A.count_() == 1));
}

SCENARIO("oper=", "[oper=]"){
	stack<int> A;
	A.push(1);
	A.push(2);
	stack<int> B;
	B = A;
	REQUIRE(B.count_() == 2));
}
<commit_msg>Update init.cpp<commit_after>#include <stack.hpp>
#include <catch.hpp>

SCENARIO("init", "[init]") {
	stack<int> A;
	REQUIRE(A.count_() == 0);
}

SCENARIO("Push", "[push]") {
	stack<int> A;
	A.push(1);
	A.push(2);
	REQUIRE(A.count_() == 2));
}

SCENARIO("Pop", "[pop]") {
	stack<int> A;
	A.push(1);
	A.push(2);
	A.pop();
	REQUIRE(A.count_() == 1));
}

SCENARIO("oper=", "[oper=]"){
	stack<int> A;
	A.push(1);
	A.push(2);
	stack<int> B;
	B = A;
	REQUIRE(B.count_() == 2));
}
<|endoftext|>


<commit_before>#include "BinaryTree.hpp"
#include <catch.hpp>

SCENARIO("default constructor")
{
	Tree<int> node;
	REQUIRE(node.root_() == nullptr);
}

SCENARIO("insert")
{
	Tree<int> tree;
	int size1, size2;
	tree.fIn("Tree.txt");
	size1 = tree.size(tree.root_());
	tree.insert(7);
	size2 = tree.size(tree.root_());
	REQUIRE((size1 + 1) == size2);
}

SCENARIO("search")
{
	Tree<int> tree;
	Node<int> * node;
	bool a;
	tree.fIn("Tree+newEl.txt");
	a = tree.check_search(10);
	REQUIRE(a == false);
}

SCENARIO("fIn", "size")
{
	Tree<int> tree;
	int size = 0;
	tree.fIn("Tree.txt");
	size = tree.size(tree.root_());
	REQUIRE(size == 4);
}

SCENARIO("out_to_file")
{
	Tree<int> tree1, tree2;
	tree1.out_to_file("TreeOut.txt");
	tree2.fIn("TreeOut.txt");
	REQUIRE(tree1.size(tree1.root_() == tree2.size(tree2.root_());
}
<commit_msg>Update init.cpp<commit_after>#include "BinaryTree.hpp"
#include <catch.hpp>

SCENARIO("default constructor")
{
	Tree<int> node;
	REQUIRE(node.root_() == nullptr);
}

SCENARIO("insert")
{
	Tree<int> tree;
	int size1, size2;
	tree.fIn("Tree.txt");
	size1 = tree.size(tree.root_());
	tree.insert(7);
	size2 = tree.size(tree.root_());
	REQUIRE((size1 + 1) == size2);
}

SCENARIO("search")
{
	Tree<int> tree;
	Node<int> * node;
	bool a;
	tree.fIn("Tree+newEl.txt");
	a = tree.check_search(10);
	REQUIRE(a == false);
}

SCENARIO("fIn", "size")
{
	Tree<int> tree;
	int size = 0;
	tree.fIn("Tree.txt");
	size = tree.size(tree.root_());
	REQUIRE(size == 4);
}

SCENARIO("out_to_file")
{
	Tree<int> tree1, tree2;
	int size1, size2;
	tree1.fIn("Tree.txt");
	size1 = tree1.size(tree1.root_();
	tree1.out_to_file("TreeOut.txt");
	tree2.fIn("TreeOut.txt");
	size2 = tree2.size(tree2.root_();
	REQUIRE(size1 == size2);
}
<|endoftext|>


<commit_before>#include <BinaryTree.hpp>
#include <catch.hpp>

SSCENARIO ("init", "[init]")
{
  BinaryTree<int> obj;
  REQUIRE(obj.root() == NULLPTR);
  REQUIRE(obj.data() == 0);
}
<commit_msg>Update init.cpp<commit_after>#include <BinaryTree.hpp>
#include <catch.hpp>

SCENARIO ("init", "[init]")
{
  Tree<int> obj;
  REQUIRE(obj.root_() == nullptr);
  REQUIRE(obj.get_count() == 0);
}
SCENARIO("insert", "[insert]")
{
  Tree<int> obj;
  obj.insert_node(3);
  REQUIRE(obj.find_node(3, obj.root_())->data == 3);
}
SCENARIO("find_node", "[find_node]")
{
  Tree<int> obj;
  test.insert_node(2);
  REQUIRE(obj.find_node(2, obj.root_()) != nullptr);
  REQUIRE(obj.find_node(2, obj.root_())->data == 4);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <gtest/gtest.h>
#include <GLFW/glfw3.h>

static void error_callback(int error, const char* description)
{
  FAIL() << "GLFW Failed (" << error << "): " << description;
}

TEST(GLFWTests, BuildInvisibleWindow)
{
  GLFWwindow* window;
  glfwSetErrorCallback(error_callback);

  if (!glfwInit())
    FAIL() << "GLFW failed to initialize";

  glfwWindowHint(GLFW_VISIBLE, 0);
  window = glfwCreateWindow(640, 480, "Invisible Example", NULL, NULL);
  if (!window)
  {
    glfwTerminate();
    FAIL() << "Failed to create glfw window";
  }

  glfwDestroyWindow(window);
  glfwTerminate();
}

int main(int argc, char** argv)
{
  ::testing::InitGoogleTest(&argc, argv);

  return RUN_ALL_TESTS();
}
<commit_msg>Remove window display. There is no X server on travis.<commit_after>#include <iostream>
#include <gtest/gtest.h>
#include <GLFW/glfw3.h>

static void error_callback(int error, const char* description)
{
  FAIL() << "GLFW Failed (" << error << "): " << description;
}

TEST(GLFWTests, BuildInvisibleWindow)
{
  GLFWwindow* window;
  glfwSetErrorCallback(error_callback);

  if (!glfwInit())
    FAIL() << "GLFW failed to initialize";

  //glfwWindowHint(GLFW_VISIBLE, 0);
  //window = glfwCreateWindow(640, 480, "Invisible Example", NULL, NULL);
  //if (!window)
  //{
  //  glfwTerminate();
  //  FAIL() << "Failed to create glfw window";
  //}

  //glfwDestroyWindow(window);
  glfwTerminate();
}

int main(int argc, char** argv)
{
  ::testing::InitGoogleTest(&argc, argv);

  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*
 * Generic cache class.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "cache.hxx"
#include "hashmap.hxx"
#include "AllocatorStats.hxx"
#include "pool.hxx"
#include "event/CleanupTimer.hxx"
#include "system/clock.h"

#include <assert.h>
#include <time.h>
#include <event.h>

/* #define ENABLE_EXCESSIVE_CACHE_CHECKS */

struct cache {
    struct pool &pool;

    const struct cache_class &cls;
    const size_t max_size;
    size_t size;
    struct hashmap *const items;

    /**
     * A linked list of all cache items, sorted by last_accessed,
     * oldest first.
     */
    boost::intrusive::list<struct cache_item,
                           boost::intrusive::member_hook<struct cache_item,
                                                         cache_item::SiblingsHook,
                                                         &cache_item::sorted_siblings>,
                           boost::intrusive::constant_time_size<false>> sorted_items;

    CleanupTimer cleanup_timer;

    cache(struct pool &_pool, const struct cache_class &_cls,
          unsigned hashtable_capacity, size_t _max_size)
        :pool(_pool), cls(_cls),
         max_size(_max_size), size(0),
         items(hashmap_new(&_pool, hashtable_capacity)) {
        cleanup_timer.Init(60, ExpireCallback, this);
    }

    ~cache();

    void Delete() {
        DeleteFromPool(pool, this);
    }

    /** clean up expired cache items every 60 seconds */
    bool ExpireCallback();
    static bool ExpireCallback(void *ctx);

    void Check() const;

    void ItemRemoved(struct cache_item *item);
};

struct cache *
cache_new(struct pool &pool, const struct cache_class *cls,
          unsigned hashtable_capacity, size_t max_size)
{
    assert(cls != nullptr);

    return NewFromPool<struct cache>(pool, pool, *cls,
                                     hashtable_capacity, max_size);
}

inline
cache::~cache()
{
    cleanup_timer.Deinit();

    Check();

    if (cls.destroy != nullptr) {
        hashmap_rewind(items);

        const struct hashmap_pair *pair;
        while ((pair = hashmap_next(items)) != nullptr) {
            struct cache_item *item = (struct cache_item *)pair->value;

            assert(item->lock == 0);
            assert(size >= item->size);
            size -= item->size;

#ifndef NDEBUG
            sorted_items.erase(sorted_items.iterator_to(*item));
#endif

            cls.destroy(item);
        }

        assert(size == 0);
        assert(sorted_items.empty());
    }
}

void
cache_close(struct cache *cache)
{
    cache->Delete();
}

AllocatorStats
cache_get_stats(const struct cache &cache)
{
    AllocatorStats stats;
    stats.netto_size = pool_children_netto_size(&cache.pool);
    stats.brutto_size = pool_children_brutto_size(&cache.pool);
    return stats;
}

inline void
cache::Check() const
{
#if !defined(NDEBUG) && defined(ENABLE_EXCESSIVE_CACHE_CHECKS)
    const struct hashmap_pair *pair;
    size_t s = 0;

    assert(size <= max_size);

    hashmap_rewind(items);
    while ((pair = hashmap_next(items)) != nullptr) {
        struct cache_item *item = (struct cache_item *)pair->value;

        s += item->size;
        assert(s <= size);
    }

    assert(s == size);
#endif
}

static void
cache_destroy_item(struct cache *cache, struct cache_item *item)
{
    if (cache->cls.destroy != nullptr)
        cache->cls.destroy(item);
}

void
cache::ItemRemoved(struct cache_item *item)
{
    assert(item != nullptr);
    assert(item->size > 0);
    assert(item->lock > 0 || !item->removed);
    assert(size >= item->size);

    sorted_items.erase(sorted_items.iterator_to(*item));

    size -= item->size;

    if (item->lock == 0)
        cache_destroy_item(this, item);
    else
        /* this item is locked - postpone the destroy() call */
        item->removed = true;

    if (size == 0)
        cleanup_timer.Disable();
}

static bool
cache_flush_callback(gcc_unused const char *key, void *value, void *ctx)
{
    struct cache *cache = (struct cache *)ctx;
    struct cache_item *item = (struct cache_item *)value;

    cache->ItemRemoved(item);
    return true;
}

void
cache_flush(struct cache *cache)
{
    cache->Check();

    hashmap_remove_all_match(cache->items, cache_flush_callback, cache);

    cache->Check();
}

static bool
cache_item_validate(const struct cache *cache, struct cache_item *item,
                    unsigned now)
{
    return now < item->expires &&
        (cache->cls.validate == nullptr || cache->cls.validate(item));
}

static void
cache_refresh_item(struct cache *cache, struct cache_item *item, unsigned now)
{
    item->last_accessed = now;

    /* move to the front of the linked list */
    cache->sorted_items.erase(cache->sorted_items.iterator_to(*item));
    cache->sorted_items.push_back(*item);
}

struct cache_item *
cache_get(struct cache *cache, const char *key)
{
    struct cache_item *item = (struct cache_item *)
        hashmap_get(cache->items, key);
    if (item == nullptr)
        return nullptr;

    const unsigned now = now_s();

    if (!cache_item_validate(cache, item, now)) {
        cache->Check();

        hashmap_remove_existing(cache->items, key, item);

        cache->ItemRemoved(item);

        cache->Check();
        return nullptr;
    }

    cache_refresh_item(cache, item, now);
    return item;
}

struct cache_item *
cache_get_match(struct cache *cache, const char *key,
                bool (*match)(const struct cache_item *, void *),
                void *ctx)
{
    const unsigned now = now_s();
    const struct hashmap_pair *pair = nullptr;

    while (true) {
        if (pair != nullptr) {
            struct cache_item *item = (struct cache_item *)pair->value;

            if (!cache_item_validate(cache, item, now)) {
                /* expired cache item: delete it, and re-start the
                   search */

                cache->Check();

                hashmap_remove_existing(cache->items, key, item);

                cache->ItemRemoved(item);
                cache->Check();

                pair = nullptr;
                continue;
            }

            if (match(item, ctx)) {
                /* this one matches: return it to the caller */
                cache_refresh_item(cache, item, now);
                return item;
            }

            /* find the next cache_item for this key */
            pair = hashmap_lookup_next(pair);
        } else {
            /* find the first cache_item for this key */
            pair = hashmap_lookup_first(cache->items, key);
        }

        if (pair == nullptr)
            /* no match */
            return nullptr;
    };
}

static void
cache_destroy_oldest_item(struct cache *cache)
{
    if (cache->sorted_items.empty())
        return;

    struct cache_item &item = cache->sorted_items.front();

    cache->Check();

    hashmap_remove_existing(cache->items, item.key, &item);

    cache->ItemRemoved(&item);
    cache->Check();
}

static bool
cache_need_room(struct cache *cache, size_t size)
{
    if (size > cache->max_size)
        return false;

    while (1) {
        if (cache->size + size <= cache->max_size)
            return true;

        cache_destroy_oldest_item(cache);
    }
}

bool
cache_add(struct cache *cache, const char *key,
          struct cache_item *item)
{
    /* XXX size constraints */
    if (!cache_need_room(cache, item->size)) {
        if (cache->cls.destroy != nullptr)
            cache->cls.destroy(item);
        return false;
    }

    cache->Check();

    item->key = key;
    hashmap_add(cache->items, key, item);
    cache->sorted_items.push_back(*item);

    cache->size += item->size;
    item->last_accessed = now_s();

    cache->Check();

    cache->cleanup_timer.Enable();
    return true;
}

bool
cache_put(struct cache *cache, const char *key,
          struct cache_item *item)
{
    /* XXX size constraints */

    assert(item != nullptr);
    assert(item->size > 0);
    assert(item->lock == 0);
    assert(!item->removed);

    if (!cache_need_room(cache, item->size)) {
        if (cache->cls.destroy != nullptr)
            cache->cls.destroy(item);
        return false;
    }

    cache->Check();

    item->key = key;

    struct cache_item *old = (struct cache_item *)
        hashmap_set(cache->items, key, item);
    if (old != nullptr)
        cache->ItemRemoved(old);

    cache->size += item->size;
    item->last_accessed = now_s();

    cache->sorted_items.push_back(*item);

    cache->Check();

    cache->cleanup_timer.Enable();
    return true;
}

bool
cache_put_match(struct cache *cache, const char *key,
                struct cache_item *item,
                bool (*match)(const struct cache_item *, void *),
                void *ctx)
{
    struct cache_item *old = cache_get_match(cache, key, match, ctx);

    assert(item != nullptr);
    assert(item->size > 0);
    assert(item->lock == 0);
    assert(!item->removed);
    assert(old == nullptr || !old->removed);

    if (old != nullptr)
        cache_remove_item(cache, key, old);

    return cache_add(cache, key, item);
}

void
cache_remove(struct cache *cache, const char *key)
{
    struct cache_item *item;

    while ((item = (struct cache_item *)hashmap_remove(cache->items, key)) != nullptr)
        cache->ItemRemoved(item);

    cache->Check();
}

struct cache_remove_match_data {
    struct cache *cache;
    bool (*match)(const struct cache_item *, void *);
    void *ctx;
};

static bool
cache_remove_match_callback(void *value, void *ctx)
{
    const struct cache_remove_match_data *data =
        (const struct cache_remove_match_data *)ctx;
    struct cache_item *item = (struct cache_item *)value;

    if (data->match(item, data->ctx)) {
        data->cache->ItemRemoved(item);
        return true;
    } else
        return false;
}

void
cache_remove_match(struct cache *cache, const char *key,
                   bool (*match)(const struct cache_item *, void *),
                   void *ctx)
{
    struct cache_remove_match_data data = {
        .cache = cache,
        .match = match,
        .ctx = ctx,
    };

    cache->Check();
    hashmap_remove_match(cache->items, key,
                         cache_remove_match_callback, &data);
    cache->Check();
}

void
cache_remove_item(struct cache *cache, const char *key,
                  struct cache_item *item)
{
    if (item->removed) {
        /* item has already been removed by somebody else */
        assert(item->lock > 0);
        return;
    }

    bool found = hashmap_remove_value(cache->items, key, item);
    if (!found) {
        /* the specified item has been removed before */
        cache->Check();
        return;
    }

    cache->ItemRemoved(item);

    cache->Check();
}

struct cache_remove_all_match_data {
    struct cache *cache;
    bool (*match)(const struct cache_item *, void *);
    void *ctx;
};

static bool
cache_remove_all_match_callback(gcc_unused const char *key, void *value,
                                void *ctx)
{
    const struct cache_remove_all_match_data *data =
        (const struct cache_remove_all_match_data *)ctx;
    struct cache_item *item = (struct cache_item *)value;

    if (data->match(item, data->ctx)) {
        data->cache->ItemRemoved(item);
        return true;
    } else
        return false;
}

unsigned
cache_remove_all_match(struct cache *cache,
                       bool (*match)(const struct cache_item *, void *),
                       void *ctx)
{
    struct cache_remove_all_match_data data = {
        .cache = cache,
        .match = match,
        .ctx = ctx,
    };
    unsigned removed;

    cache->Check();
    removed = hashmap_remove_all_match(cache->items,
                                       cache_remove_all_match_callback, &data);
    cache->Check();

    return removed;
}

void
cache_item_init_absolute(struct cache_item *item, time_t expires, size_t size)
{
    time_t now = time(nullptr);
    unsigned monotonic_expires = expires > now
        ? now_s() + (expires - now)
        : 1;

    cache_item_init(item, monotonic_expires, size);
}

void
cache_item_init_relative(struct cache_item *item, unsigned max_age,
                         size_t size)
{
    cache_item_init(item, now_s() + max_age, size);
}

void
cache_item_lock(struct cache_item *item)
{
    assert(item != nullptr);

    ++item->lock;
}

void
cache_item_unlock(struct cache *cache, struct cache_item *item)
{
    assert(item != nullptr);
    assert(item->lock > 0);

    if (--item->lock == 0 && item->removed)
        /* postponed destroy */
        cache_destroy_item(cache, item);
}

/** clean up expired cache items every 60 seconds */
bool
cache::ExpireCallback()
{
    const unsigned now = now_s();

    Check();

    for (auto i = sorted_items.begin(), end = sorted_items.end(); i != end;) {
        struct cache_item &item = *i++;

        if (item.expires > now)
            /* not yet expired */
            continue;

        hashmap_remove_existing(items, item.key, &item);
        ItemRemoved(&item);
    }

    Check();

    return size > 0;
}

bool
cache::ExpireCallback(void *ctx)
{
    struct cache *cache = (struct cache *)ctx;

    return cache->ExpireCallback();
}

void
cache_event_add(struct cache *cache)
{
    if (cache->size > 0)
        cache->cleanup_timer.Enable();
}

void
cache_event_del(struct cache *cache)
{
    cache->cleanup_timer.Disable();
}
<commit_msg>cache: don't allocate from pool<commit_after>/*
 * Generic cache class.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "cache.hxx"
#include "hashmap.hxx"
#include "AllocatorStats.hxx"
#include "pool.hxx"
#include "event/CleanupTimer.hxx"
#include "system/clock.h"

#include <assert.h>
#include <time.h>
#include <event.h>

/* #define ENABLE_EXCESSIVE_CACHE_CHECKS */

struct cache {
    struct pool &pool;

    const struct cache_class &cls;
    const size_t max_size;
    size_t size;
    struct hashmap *const items;

    /**
     * A linked list of all cache items, sorted by last_accessed,
     * oldest first.
     */
    boost::intrusive::list<struct cache_item,
                           boost::intrusive::member_hook<struct cache_item,
                                                         cache_item::SiblingsHook,
                                                         &cache_item::sorted_siblings>,
                           boost::intrusive::constant_time_size<false>> sorted_items;

    CleanupTimer cleanup_timer;

    cache(struct pool &_pool, const struct cache_class &_cls,
          unsigned hashtable_capacity, size_t _max_size)
        :pool(_pool), cls(_cls),
         max_size(_max_size), size(0),
         items(hashmap_new(&_pool, hashtable_capacity)) {
        cleanup_timer.Init(60, ExpireCallback, this);
    }

    ~cache();

    /** clean up expired cache items every 60 seconds */
    bool ExpireCallback();
    static bool ExpireCallback(void *ctx);

    void Check() const;

    void ItemRemoved(struct cache_item *item);
};

struct cache *
cache_new(struct pool &pool, const struct cache_class *cls,
          unsigned hashtable_capacity, size_t max_size)
{
    assert(cls != nullptr);

    return new cache(pool, *cls, hashtable_capacity, max_size);
}

inline
cache::~cache()
{
    cleanup_timer.Deinit();

    Check();

    if (cls.destroy != nullptr) {
        hashmap_rewind(items);

        const struct hashmap_pair *pair;
        while ((pair = hashmap_next(items)) != nullptr) {
            struct cache_item *item = (struct cache_item *)pair->value;

            assert(item->lock == 0);
            assert(size >= item->size);
            size -= item->size;

#ifndef NDEBUG
            sorted_items.erase(sorted_items.iterator_to(*item));
#endif

            cls.destroy(item);
        }

        assert(size == 0);
        assert(sorted_items.empty());
    }
}

void
cache_close(struct cache *cache)
{
    delete cache;
}

AllocatorStats
cache_get_stats(const struct cache &cache)
{
    AllocatorStats stats;
    stats.netto_size = pool_children_netto_size(&cache.pool);
    stats.brutto_size = pool_children_brutto_size(&cache.pool);
    return stats;
}

inline void
cache::Check() const
{
#if !defined(NDEBUG) && defined(ENABLE_EXCESSIVE_CACHE_CHECKS)
    const struct hashmap_pair *pair;
    size_t s = 0;

    assert(size <= max_size);

    hashmap_rewind(items);
    while ((pair = hashmap_next(items)) != nullptr) {
        struct cache_item *item = (struct cache_item *)pair->value;

        s += item->size;
        assert(s <= size);
    }

    assert(s == size);
#endif
}

static void
cache_destroy_item(struct cache *cache, struct cache_item *item)
{
    if (cache->cls.destroy != nullptr)
        cache->cls.destroy(item);
}

void
cache::ItemRemoved(struct cache_item *item)
{
    assert(item != nullptr);
    assert(item->size > 0);
    assert(item->lock > 0 || !item->removed);
    assert(size >= item->size);

    sorted_items.erase(sorted_items.iterator_to(*item));

    size -= item->size;

    if (item->lock == 0)
        cache_destroy_item(this, item);
    else
        /* this item is locked - postpone the destroy() call */
        item->removed = true;

    if (size == 0)
        cleanup_timer.Disable();
}

static bool
cache_flush_callback(gcc_unused const char *key, void *value, void *ctx)
{
    struct cache *cache = (struct cache *)ctx;
    struct cache_item *item = (struct cache_item *)value;

    cache->ItemRemoved(item);
    return true;
}

void
cache_flush(struct cache *cache)
{
    cache->Check();

    hashmap_remove_all_match(cache->items, cache_flush_callback, cache);

    cache->Check();
}

static bool
cache_item_validate(const struct cache *cache, struct cache_item *item,
                    unsigned now)
{
    return now < item->expires &&
        (cache->cls.validate == nullptr || cache->cls.validate(item));
}

static void
cache_refresh_item(struct cache *cache, struct cache_item *item, unsigned now)
{
    item->last_accessed = now;

    /* move to the front of the linked list */
    cache->sorted_items.erase(cache->sorted_items.iterator_to(*item));
    cache->sorted_items.push_back(*item);
}

struct cache_item *
cache_get(struct cache *cache, const char *key)
{
    struct cache_item *item = (struct cache_item *)
        hashmap_get(cache->items, key);
    if (item == nullptr)
        return nullptr;

    const unsigned now = now_s();

    if (!cache_item_validate(cache, item, now)) {
        cache->Check();

        hashmap_remove_existing(cache->items, key, item);

        cache->ItemRemoved(item);

        cache->Check();
        return nullptr;
    }

    cache_refresh_item(cache, item, now);
    return item;
}

struct cache_item *
cache_get_match(struct cache *cache, const char *key,
                bool (*match)(const struct cache_item *, void *),
                void *ctx)
{
    const unsigned now = now_s();
    const struct hashmap_pair *pair = nullptr;

    while (true) {
        if (pair != nullptr) {
            struct cache_item *item = (struct cache_item *)pair->value;

            if (!cache_item_validate(cache, item, now)) {
                /* expired cache item: delete it, and re-start the
                   search */

                cache->Check();

                hashmap_remove_existing(cache->items, key, item);

                cache->ItemRemoved(item);
                cache->Check();

                pair = nullptr;
                continue;
            }

            if (match(item, ctx)) {
                /* this one matches: return it to the caller */
                cache_refresh_item(cache, item, now);
                return item;
            }

            /* find the next cache_item for this key */
            pair = hashmap_lookup_next(pair);
        } else {
            /* find the first cache_item for this key */
            pair = hashmap_lookup_first(cache->items, key);
        }

        if (pair == nullptr)
            /* no match */
            return nullptr;
    };
}

static void
cache_destroy_oldest_item(struct cache *cache)
{
    if (cache->sorted_items.empty())
        return;

    struct cache_item &item = cache->sorted_items.front();

    cache->Check();

    hashmap_remove_existing(cache->items, item.key, &item);

    cache->ItemRemoved(&item);
    cache->Check();
}

static bool
cache_need_room(struct cache *cache, size_t size)
{
    if (size > cache->max_size)
        return false;

    while (1) {
        if (cache->size + size <= cache->max_size)
            return true;

        cache_destroy_oldest_item(cache);
    }
}

bool
cache_add(struct cache *cache, const char *key,
          struct cache_item *item)
{
    /* XXX size constraints */
    if (!cache_need_room(cache, item->size)) {
        if (cache->cls.destroy != nullptr)
            cache->cls.destroy(item);
        return false;
    }

    cache->Check();

    item->key = key;
    hashmap_add(cache->items, key, item);
    cache->sorted_items.push_back(*item);

    cache->size += item->size;
    item->last_accessed = now_s();

    cache->Check();

    cache->cleanup_timer.Enable();
    return true;
}

bool
cache_put(struct cache *cache, const char *key,
          struct cache_item *item)
{
    /* XXX size constraints */

    assert(item != nullptr);
    assert(item->size > 0);
    assert(item->lock == 0);
    assert(!item->removed);

    if (!cache_need_room(cache, item->size)) {
        if (cache->cls.destroy != nullptr)
            cache->cls.destroy(item);
        return false;
    }

    cache->Check();

    item->key = key;

    struct cache_item *old = (struct cache_item *)
        hashmap_set(cache->items, key, item);
    if (old != nullptr)
        cache->ItemRemoved(old);

    cache->size += item->size;
    item->last_accessed = now_s();

    cache->sorted_items.push_back(*item);

    cache->Check();

    cache->cleanup_timer.Enable();
    return true;
}

bool
cache_put_match(struct cache *cache, const char *key,
                struct cache_item *item,
                bool (*match)(const struct cache_item *, void *),
                void *ctx)
{
    struct cache_item *old = cache_get_match(cache, key, match, ctx);

    assert(item != nullptr);
    assert(item->size > 0);
    assert(item->lock == 0);
    assert(!item->removed);
    assert(old == nullptr || !old->removed);

    if (old != nullptr)
        cache_remove_item(cache, key, old);

    return cache_add(cache, key, item);
}

void
cache_remove(struct cache *cache, const char *key)
{
    struct cache_item *item;

    while ((item = (struct cache_item *)hashmap_remove(cache->items, key)) != nullptr)
        cache->ItemRemoved(item);

    cache->Check();
}

struct cache_remove_match_data {
    struct cache *cache;
    bool (*match)(const struct cache_item *, void *);
    void *ctx;
};

static bool
cache_remove_match_callback(void *value, void *ctx)
{
    const struct cache_remove_match_data *data =
        (const struct cache_remove_match_data *)ctx;
    struct cache_item *item = (struct cache_item *)value;

    if (data->match(item, data->ctx)) {
        data->cache->ItemRemoved(item);
        return true;
    } else
        return false;
}

void
cache_remove_match(struct cache *cache, const char *key,
                   bool (*match)(const struct cache_item *, void *),
                   void *ctx)
{
    struct cache_remove_match_data data = {
        .cache = cache,
        .match = match,
        .ctx = ctx,
    };

    cache->Check();
    hashmap_remove_match(cache->items, key,
                         cache_remove_match_callback, &data);
    cache->Check();
}

void
cache_remove_item(struct cache *cache, const char *key,
                  struct cache_item *item)
{
    if (item->removed) {
        /* item has already been removed by somebody else */
        assert(item->lock > 0);
        return;
    }

    bool found = hashmap_remove_value(cache->items, key, item);
    if (!found) {
        /* the specified item has been removed before */
        cache->Check();
        return;
    }

    cache->ItemRemoved(item);

    cache->Check();
}

struct cache_remove_all_match_data {
    struct cache *cache;
    bool (*match)(const struct cache_item *, void *);
    void *ctx;
};

static bool
cache_remove_all_match_callback(gcc_unused const char *key, void *value,
                                void *ctx)
{
    const struct cache_remove_all_match_data *data =
        (const struct cache_remove_all_match_data *)ctx;
    struct cache_item *item = (struct cache_item *)value;

    if (data->match(item, data->ctx)) {
        data->cache->ItemRemoved(item);
        return true;
    } else
        return false;
}

unsigned
cache_remove_all_match(struct cache *cache,
                       bool (*match)(const struct cache_item *, void *),
                       void *ctx)
{
    struct cache_remove_all_match_data data = {
        .cache = cache,
        .match = match,
        .ctx = ctx,
    };
    unsigned removed;

    cache->Check();
    removed = hashmap_remove_all_match(cache->items,
                                       cache_remove_all_match_callback, &data);
    cache->Check();

    return removed;
}

void
cache_item_init_absolute(struct cache_item *item, time_t expires, size_t size)
{
    time_t now = time(nullptr);
    unsigned monotonic_expires = expires > now
        ? now_s() + (expires - now)
        : 1;

    cache_item_init(item, monotonic_expires, size);
}

void
cache_item_init_relative(struct cache_item *item, unsigned max_age,
                         size_t size)
{
    cache_item_init(item, now_s() + max_age, size);
}

void
cache_item_lock(struct cache_item *item)
{
    assert(item != nullptr);

    ++item->lock;
}

void
cache_item_unlock(struct cache *cache, struct cache_item *item)
{
    assert(item != nullptr);
    assert(item->lock > 0);

    if (--item->lock == 0 && item->removed)
        /* postponed destroy */
        cache_destroy_item(cache, item);
}

/** clean up expired cache items every 60 seconds */
bool
cache::ExpireCallback()
{
    const unsigned now = now_s();

    Check();

    for (auto i = sorted_items.begin(), end = sorted_items.end(); i != end;) {
        struct cache_item &item = *i++;

        if (item.expires > now)
            /* not yet expired */
            continue;

        hashmap_remove_existing(items, item.key, &item);
        ItemRemoved(&item);
    }

    Check();

    return size > 0;
}

bool
cache::ExpireCallback(void *ctx)
{
    struct cache *cache = (struct cache *)ctx;

    return cache->ExpireCallback();
}

void
cache_event_add(struct cache *cache)
{
    if (cache->size > 0)
        cache->cleanup_timer.Enable();
}

void
cache_event_del(struct cache *cache)
{
    cache->cleanup_timer.Disable();
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "chain.h"
#include "chainparams.h"
#include "validation.h"
#include "bignum.h"

/* Moved here from the header, because we need auxpow and the logic
   becomes more involved.  */
CBlockHeader CBlockIndex::GetBlockHeader(const Consensus::Params& consensusParams) const
{
    CBlockHeader block;

    block.nVersion       = nVersion;

    /* The CBlockIndex object's block header is missing the auxpow.
       So if this is an auxpow block, read it from disk instead.  We only
       have to read the actual *header*, not the full block.  */
    if (block.IsAuxpow())
    {
        ReadBlockHeaderFromDisk(block, this, consensusParams);
        return block;
    }

    if (pprev)
        block.hashPrevBlock = pprev->GetBlockHash();
    block.hashMerkleRoot = hashMerkleRoot;
    block.nTime          = nTime;
    block.nBits          = nBits;
    block.nNonce         = nNonce;
    return block;
}

/**
 * CChain implementation
 */
void CChain::SetTip(CBlockIndex *pindex) {
    if (pindex == NULL) {
        vChain.clear();
        return;
    }
    vChain.resize(pindex->nHeight + 1);
    while (pindex && vChain[pindex->nHeight] != pindex) {
        vChain[pindex->nHeight] = pindex;
        pindex = pindex->pprev;
    }
}

CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
    int nStep = 1;
    std::vector<uint256> vHave;
    vHave.reserve(32);

    if (!pindex)
        pindex = Tip();
    while (pindex) {
        vHave.push_back(pindex->GetBlockHash());
        // Stop when we have added the genesis block.
        if (pindex->nHeight == 0)
            break;
        // Exponentially larger steps back, plus the genesis block.
        int nHeight = std::max(pindex->nHeight - nStep, 0);
        if (Contains(pindex)) {
            // Use O(1) CChain index if possible.
            pindex = (*this)[nHeight];
        } else {
            // Otherwise, use O(log n) skiplist.
            pindex = pindex->GetAncestor(nHeight);
        }
        if (vHave.size() > 10)
            nStep *= 2;
    }

    return CBlockLocator(vHave);
}

const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
    if (pindex == NULL) {
        return NULL;
    }
    if (pindex->nHeight > Height())
        pindex = pindex->GetAncestor(Height());
    while (pindex && !Contains(pindex))
        pindex = pindex->pprev;
    return pindex;
}

CBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime) const
{
    std::vector<CBlockIndex*>::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), nTime,
        [](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTimeMax() < time; });
    return (lower == vChain.end() ? NULL : *lower);
}

/** Turn the lowest '1' bit in the binary representation of a number into a '0'. */
int static inline InvertLowestOne(int n) { return n & (n - 1); }

/** Compute what height to jump back to with the CBlockIndex::pskip pointer. */
int static inline GetSkipHeight(int height) {
    if (height < 2)
        return 0;

    // Determine which height to jump back to. Any number strictly lower than height is acceptable,
    // but the following expression seems to perform well in simulations (max 110 steps to go back
    // up to 2**18 blocks).
    return (height & 1) ? InvertLowestOne(InvertLowestOne(height - 1)) + 1 : InvertLowestOne(height);
}

CBlockIndex* CBlockIndex::GetAncestor(int height)
{
    if (height > nHeight || height < 0)
        return NULL;

    CBlockIndex* pindexWalk = this;
    int heightWalk = nHeight;
    while (heightWalk > height) {
        int heightSkip = GetSkipHeight(heightWalk);
        int heightSkipPrev = GetSkipHeight(heightWalk - 1);
        if (pindexWalk->pskip != NULL &&
            (heightSkip == height ||
             (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
                                       heightSkipPrev >= height)))) {
            // Only follow pskip if pprev->pskip isn't better than pskip->pprev.
            pindexWalk = pindexWalk->pskip;
            heightWalk = heightSkip;
        } else {
            assert(pindexWalk->pprev);
            pindexWalk = pindexWalk->pprev;
            heightWalk--;
        }
    }
    return pindexWalk;
}

const CBlockIndex* CBlockIndex::GetAncestor(int height) const
{
    return const_cast<CBlockIndex*>(this)->GetAncestor(height);
}

void CBlockIndex::BuildSkip()
{
    if (pprev)
        pskip = pprev->GetAncestor(GetSkipHeight(nHeight));
}

arith_uint256 GetBlockProofBase(const CBlockIndex& block)
{
    arith_uint256 bnTarget;
    bool fNegative;
    bool fOverflow;
    bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
    if (fNegative || fOverflow || bnTarget == 0)
        return 0;
    // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
    // as it's too large for a arith_uint256. However, as 2**256 is at least as large
    // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
    // or ~bnTarget / (nTarget+1) + 1.
    return (~bnTarget / (bnTarget + 1)) + 1;
}

int GetAlgoWorkFactor(int algo)
{
    switch (algo)
    {
        case ALGO_SHA256D:
            return 1;
        // work factor = absolute work ratio * optimisation factor
        case ALGO_SCRYPT:
            return 1024 * 4;
        case ALGO_GROESTL:
            return 64 * 8;
        case ALGO_SKEIN:
            return 4 * 6;
        case ALGO_QUBIT:
            return 128 * 8;
        default:
            return 1;
    }
}

arith_uint256 GetPrevWorkForAlgo(const CBlockIndex& block, int algo)
{
    const CBlockIndex* pindex = █
    while (pindex != NULL)
    {
        if (pindex->GetAlgo() == algo)
        {
            return GetBlockProofBase(*pindex);
        }
        pindex = pindex->pprev;
    }
    return UintToArith256(Params().GetConsensus().powLimit);
}

// arith_uint256 GetPrevWorkForAlgoWithDecay(const CBlockIndex& block, int algo)
// {
//     int nDistance = 0;
//     arith_uint256 nWork;
//     const CBlockIndex* pindex = █
//     while (pindex != NULL)
//     {
//         if (nDistance > 32)
//         {
//             return UintToArith256(Params().GetConsensus().powLimit);
//         }
//         if (pindex->GetAlgo() == algo)
//         {
//             arith_uint256 nWork = GetBlockProofBase(*pindex);
//             nWork *= (32 - nDistance);
//             nWork /= 32;
//             if (nWork < UintToArith256(Params().GetConsensus().powLimit))
//                 nWork = UintToArith256(Params().GetConsensus().powLimit);
//             return nWork;
//         }
//         pindex = pindex->pprev;
//         nDistance++;
//     }
//     return UintToArith256(Params().GetConsensus().powLimit);
// }

// arith_uint256 GetPrevWorkForAlgoWithDecay2(const CBlockIndex& block, int algo)
// {
//     int nDistance = 0;
//     arith_uint256 nWork;
//     const CBlockIndex* pindex = █
//     while (pindex != NULL)
//     {
//         if (nDistance > 32)
//         {
//             return arith_uint256(0);
//         }
//         if (pindex->GetAlgo() == algo)
//         {
//             arith_uint256 nWork = GetBlockProofBase(*pindex);
//             nWork *= (32 - nDistance);
//             nWork /= 32;
//             return nWork;
//         }
//         pindex = pindex->pprev;
//         nDistance++;
//     }
//     return arith_uint256(0);
// }

arith_uint256 GetPrevWorkForAlgoWithDecay3(const CBlockIndex& block, int algo)
{
    int nDistance = 0;
    arith_uint256 nWork;
    const CBlockIndex* pindex = █
    while (pindex != NULL)
    {
        if (nDistance > 100)
        {
            return arith_uint256(0);
        }
        if (pindex->GetAlgo() == algo)
        {
            arith_uint256 nWork = GetBlockProofBase(*pindex);
            nWork *= (100 - nDistance);
            nWork /= 100;
            return nWork;
        }
        pindex = pindex->pprev;
        nDistance++;
    }
    return arith_uint256(0);
}

arith_uint256 GetGeometricMeanPrevWork(const CBlockIndex& block)
{
    //arith_uint256 bnRes;
    arith_uint256 nBlockWork = GetBlockProofBase(block);
    CBigNum bnBlockWork = CBigNum(ArithToUint256(nBlockWork));
    int nAlgo = block.GetAlgo();

    for (int algo = 0; algo < NUM_ALGOS_IMPL; algo++)
    {
        if (algo != nAlgo)
        {
            arith_uint256 nBlockWorkAlt = GetPrevWorkForAlgoWithDecay3(block, algo);
            CBigNum bnBlockWorkAlt = CBigNum(ArithToUint256(nBlockWorkAlt));
            if (bnBlockWorkAlt != 0)
                bnBlockWork *= bnBlockWorkAlt;
        }
    }
    // Compute the geometric mean
    CBigNum bnRes = bnBlockWork.nthRoot(NUM_ALGOS);
arith_uint256 GetBlockProof(const CBlockIndex& block)
{
    const CChainParams& chainparams = Params();

    arith_uint256 bnTarget;
    int nHeight = block.nHeight;
    int nAlgo = block.GetAlgo();

    if (nHeight >= chainparams.GetConsensus().nGeoAvgWork_Start)
    {
        bnTarget = GetGeometricMeanPrevWork(block);
    }
    else if (nHeight >= chainparams.GetConsensus().nMultiAlgoFork)
    {
        arith_uint256 nBlockWork = GetBlockProofBase(block);
        for (int algo = 0; algo < NUM_ALGOS; algo++)
        {
            if (algo != nAlgo)
            {
                nBlockWork += GetPrevWorkForAlgo(block, algo);
            }
        }
        bnTarget = nBlockWork / NUM_ALGOS;
    }
    else
    {
        bnTarget = GetBlockProofBase(block);
    }
    return bnTarget;
}

    //return bnRes;
    return UintToArith256(bnRes.getuint256());
}

arith_uint256 GetBlockProof(const CBlockIndex& block)
{
    const CChainParams& chainparams = Params();

    arith_uint256 bnTarget;
    int nHeight = block.nHeight;
    int nAlgo = block.GetAlgo();

    if (nHeight >= chainparams.GetConsensus().nGeoAvgWork_Start)
    {
        bnTarget = GetGeometricMeanPrevWork(block);
    }
    else if (nHeight >= chainparams.GetConsensus().nMultiAlgoFork)
    {
        arith_uint256 nBlockWork = GetBlockProofBase(block);
        for (int algo = 0; algo < NUM_ALGOS; algo++)
        {
            if (algo != nAlgo)
            {
                nBlockWork += GetPrevWorkForAlgo(block, algo);
            }
        }
        bnTarget = nBlockWork / NUM_ALGOS;
    }
    else
    {
        bnTarget = GetBlockProofBase(block);
    }
    return bnTarget;
}

int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
{
    arith_uint256 r;
    int sign = 1;
    if (to.nChainWork > from.nChainWork) {
        r = to.nChainWork - from.nChainWork;
    } else {
        r = from.nChainWork - to.nChainWork;
        sign = -1;
    }
    r = r * arith_uint256(params.nPowTargetSpacingV2) / GetBlockProof(tip);
    if (r.bits() > 63) {
        return sign * std::numeric_limits<int64_t>::max();
    }
    return sign * r.GetLow64();
}

const CBlockIndex* GetLastBlockIndexForAlgo(const CBlockIndex* pindex, int algo)
{
    for (;;)
    {
        if (!pindex)
            return NULL;
        if (pindex->GetAlgo() == algo)
            return pindex;
        pindex = pindex->pprev;
    }
}

std::string GetAlgoName(int Algo, uint32_t time, const Consensus::Params& consensusParams)
{
    switch (Algo)
    {
        case ALGO_SHA256D:
            return std::string("sha256d");
        case ALGO_SCRYPT:
            return std::string("scrypt");
        // case ALGO_GROESTL:
        //     return std::string("groestl");
        // case ALGO_SKEIN:
        //     return std::string("skein");
        // case ALGO_QUBIT:
        //     return std::string("qubit");
        // case ALGO_YESCRYPT:
        //     return std::string("yescrypt");
    }
    return std::string("unknown");
}
<commit_msg>fix up code<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "chain.h"
#include "chainparams.h"
#include "validation.h"
#include "bignum.h"

/* Moved here from the header, because we need auxpow and the logic
   becomes more involved.  */
CBlockHeader CBlockIndex::GetBlockHeader(const Consensus::Params& consensusParams) const
{
    CBlockHeader block;

    block.nVersion       = nVersion;

    /* The CBlockIndex object's block header is missing the auxpow.
       So if this is an auxpow block, read it from disk instead.  We only
       have to read the actual *header*, not the full block.  */
    if (block.IsAuxpow())
    {
        ReadBlockHeaderFromDisk(block, this, consensusParams);
        return block;
    }

    if (pprev)
        block.hashPrevBlock = pprev->GetBlockHash();
    block.hashMerkleRoot = hashMerkleRoot;
    block.nTime          = nTime;
    block.nBits          = nBits;
    block.nNonce         = nNonce;
    return block;
}

/**
 * CChain implementation
 */
void CChain::SetTip(CBlockIndex *pindex) {
    if (pindex == NULL) {
        vChain.clear();
        return;
    }
    vChain.resize(pindex->nHeight + 1);
    while (pindex && vChain[pindex->nHeight] != pindex) {
        vChain[pindex->nHeight] = pindex;
        pindex = pindex->pprev;
    }
}

CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
    int nStep = 1;
    std::vector<uint256> vHave;
    vHave.reserve(32);

    if (!pindex)
        pindex = Tip();
    while (pindex) {
        vHave.push_back(pindex->GetBlockHash());
        // Stop when we have added the genesis block.
        if (pindex->nHeight == 0)
            break;
        // Exponentially larger steps back, plus the genesis block.
        int nHeight = std::max(pindex->nHeight - nStep, 0);
        if (Contains(pindex)) {
            // Use O(1) CChain index if possible.
            pindex = (*this)[nHeight];
        } else {
            // Otherwise, use O(log n) skiplist.
            pindex = pindex->GetAncestor(nHeight);
        }
        if (vHave.size() > 10)
            nStep *= 2;
    }

    return CBlockLocator(vHave);
}

const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {
    if (pindex == NULL) {
        return NULL;
    }
    if (pindex->nHeight > Height())
        pindex = pindex->GetAncestor(Height());
    while (pindex && !Contains(pindex))
        pindex = pindex->pprev;
    return pindex;
}

CBlockIndex* CChain::FindEarliestAtLeast(int64_t nTime) const
{
    std::vector<CBlockIndex*>::const_iterator lower = std::lower_bound(vChain.begin(), vChain.end(), nTime,
        [](CBlockIndex* pBlock, const int64_t& time) -> bool { return pBlock->GetBlockTimeMax() < time; });
    return (lower == vChain.end() ? NULL : *lower);
}

/** Turn the lowest '1' bit in the binary representation of a number into a '0'. */
int static inline InvertLowestOne(int n) { return n & (n - 1); }

/** Compute what height to jump back to with the CBlockIndex::pskip pointer. */
int static inline GetSkipHeight(int height) {
    if (height < 2)
        return 0;

    // Determine which height to jump back to. Any number strictly lower than height is acceptable,
    // but the following expression seems to perform well in simulations (max 110 steps to go back
    // up to 2**18 blocks).
    return (height & 1) ? InvertLowestOne(InvertLowestOne(height - 1)) + 1 : InvertLowestOne(height);
}

CBlockIndex* CBlockIndex::GetAncestor(int height)
{
    if (height > nHeight || height < 0)
        return NULL;

    CBlockIndex* pindexWalk = this;
    int heightWalk = nHeight;
    while (heightWalk > height) {
        int heightSkip = GetSkipHeight(heightWalk);
        int heightSkipPrev = GetSkipHeight(heightWalk - 1);
        if (pindexWalk->pskip != NULL &&
            (heightSkip == height ||
             (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
                                       heightSkipPrev >= height)))) {
            // Only follow pskip if pprev->pskip isn't better than pskip->pprev.
            pindexWalk = pindexWalk->pskip;
            heightWalk = heightSkip;
        } else {
            assert(pindexWalk->pprev);
            pindexWalk = pindexWalk->pprev;
            heightWalk--;
        }
    }
    return pindexWalk;
}

const CBlockIndex* CBlockIndex::GetAncestor(int height) const
{
    return const_cast<CBlockIndex*>(this)->GetAncestor(height);
}

void CBlockIndex::BuildSkip()
{
    if (pprev)
        pskip = pprev->GetAncestor(GetSkipHeight(nHeight));
}

arith_uint256 GetBlockProofBase(const CBlockIndex& block)
{
    arith_uint256 bnTarget;
    bool fNegative;
    bool fOverflow;
    bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
    if (fNegative || fOverflow || bnTarget == 0)
        return 0;
    // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256
    // as it's too large for a arith_uint256. However, as 2**256 is at least as large
    // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
    // or ~bnTarget / (nTarget+1) + 1.
    return (~bnTarget / (bnTarget + 1)) + 1;
}

int GetAlgoWorkFactor(int algo)
{
    switch (algo)
    {
        case ALGO_SHA256D:
            return 1;
        // work factor = absolute work ratio * optimisation factor
        case ALGO_SCRYPT:
            return 1024 * 4;
        case ALGO_GROESTL:
            return 64 * 8;
        case ALGO_SKEIN:
            return 4 * 6;
        case ALGO_QUBIT:
            return 128 * 8;
        default:
            return 1;
    }
}

arith_uint256 GetPrevWorkForAlgo(const CBlockIndex& block, int algo)
{
    const CBlockIndex* pindex = █
    while (pindex != NULL)
    {
        if (pindex->GetAlgo() == algo)
        {
            return GetBlockProofBase(*pindex);
        }
        pindex = pindex->pprev;
    }
    return UintToArith256(Params().GetConsensus().powLimit);
}

// arith_uint256 GetPrevWorkForAlgoWithDecay(const CBlockIndex& block, int algo)
// {
//     int nDistance = 0;
//     arith_uint256 nWork;
//     const CBlockIndex* pindex = █
//     while (pindex != NULL)
//     {
//         if (nDistance > 32)
//         {
//             return UintToArith256(Params().GetConsensus().powLimit);
//         }
//         if (pindex->GetAlgo() == algo)
//         {
//             arith_uint256 nWork = GetBlockProofBase(*pindex);
//             nWork *= (32 - nDistance);
//             nWork /= 32;
//             if (nWork < UintToArith256(Params().GetConsensus().powLimit))
//                 nWork = UintToArith256(Params().GetConsensus().powLimit);
//             return nWork;
//         }
//         pindex = pindex->pprev;
//         nDistance++;
//     }
//     return UintToArith256(Params().GetConsensus().powLimit);
// }

// arith_uint256 GetPrevWorkForAlgoWithDecay2(const CBlockIndex& block, int algo)
// {
//     int nDistance = 0;
//     arith_uint256 nWork;
//     const CBlockIndex* pindex = █
//     while (pindex != NULL)
//     {
//         if (nDistance > 32)
//         {
//             return arith_uint256(0);
//         }
//         if (pindex->GetAlgo() == algo)
//         {
//             arith_uint256 nWork = GetBlockProofBase(*pindex);
//             nWork *= (32 - nDistance);
//             nWork /= 32;
//             return nWork;
//         }
//         pindex = pindex->pprev;
//         nDistance++;
//     }
//     return arith_uint256(0);
// }

arith_uint256 GetPrevWorkForAlgoWithDecay3(const CBlockIndex& block, int algo)
{
    int nDistance = 0;
    arith_uint256 nWork;
    const CBlockIndex* pindex = █
    while (pindex != NULL)
    {
        if (nDistance > 100)
        {
            return arith_uint256(0);
        }
        if (pindex->GetAlgo() == algo)
        {
            arith_uint256 nWork = GetBlockProofBase(*pindex);
            nWork *= (100 - nDistance);
            nWork /= 100;
            return nWork;
        }
        pindex = pindex->pprev;
        nDistance++;
    }
    return arith_uint256(0);
}

arith_uint256 GetGeometricMeanPrevWork(const CBlockIndex& block)
{
    //arith_uint256 bnRes;
    arith_uint256 nBlockWork = GetBlockProofBase(block);
    CBigNum bnBlockWork = CBigNum(ArithToUint256(nBlockWork));
    int nAlgo = block.GetAlgo();

    for (int algo = 0; algo < NUM_ALGOS_IMPL; algo++)
    {
        if (algo != nAlgo)
        {
            arith_uint256 nBlockWorkAlt = GetPrevWorkForAlgoWithDecay3(block, algo);
            CBigNum bnBlockWorkAlt = CBigNum(ArithToUint256(nBlockWorkAlt));
            if (bnBlockWorkAlt != 0)
                bnBlockWork *= bnBlockWorkAlt;
        }
    }
    // Compute the geometric mean
    CBigNum bnRes = bnBlockWork.nthRoot(NUM_ALGOS);

    //return bnRes;
    return UintToArith256(bnRes.getuint256());
}

arith_uint256 GetBlockProof(const CBlockIndex& block)
{
    const CChainParams& chainparams = Params();

    arith_uint256 bnTarget;
    int nHeight = block.nHeight;
    int nAlgo = block.GetAlgo();

    if (nHeight >= chainparams.GetConsensus().nGeoAvgWork_Start)
    {
        bnTarget = GetGeometricMeanPrevWork(block);
    }
    else if (nHeight >= chainparams.GetConsensus().nMultiAlgoFork)
    {
        arith_uint256 nBlockWork = GetBlockProofBase(block);
        for (int algo = 0; algo < NUM_ALGOS; algo++)
        {
            if (algo != nAlgo)
            {
                nBlockWork += GetPrevWorkForAlgo(block, algo);
            }
        }
        bnTarget = nBlockWork / NUM_ALGOS;
    }
    else
    {
        bnTarget = GetBlockProofBase(block);
    }
    return bnTarget;
}

int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
{
    arith_uint256 r;
    int sign = 1;
    if (to.nChainWork > from.nChainWork) {
        r = to.nChainWork - from.nChainWork;
    } else {
        r = from.nChainWork - to.nChainWork;
        sign = -1;
    }
    r = r * arith_uint256(params.nPowTargetSpacingV2) / GetBlockProof(tip);
    if (r.bits() > 63) {
        return sign * std::numeric_limits<int64_t>::max();
    }
    return sign * r.GetLow64();
}

const CBlockIndex* GetLastBlockIndexForAlgo(const CBlockIndex* pindex, int algo)
{
    for (;;)
    {
        if (!pindex)
            return NULL;
        if (pindex->GetAlgo() == algo)
            return pindex;
        pindex = pindex->pprev;
    }
}

std::string GetAlgoName(int Algo, uint32_t time, const Consensus::Params& consensusParams)
{
    switch (Algo)
    {
        case ALGO_SHA256D:
            return std::string("sha256d");
        case ALGO_SCRYPT:
            return std::string("scrypt");
        // case ALGO_GROESTL:
        //     return std::string("groestl");
        // case ALGO_SKEIN:
        //     return std::string("skein");
        // case ALGO_QUBIT:
        //     return std::string("qubit");
        // case ALGO_YESCRYPT:
        //     return std::string("yescrypt");
    }
    return std::string("unknown");
}
<|endoftext|>


<commit_before>#include "client_net.h"
#include "interactive.h"
#include "crc32.h"
#include "md5.h"
#include "sha1.h"
#include "sha256.h"
#include "sha3.h"
#include "spdlog/spdlog.h"
#include "logging.h"
#include "auth_common.h"
#include "packets/radius_packet.h"
#include "packets/eap_packet.h"
#include "packets/packet.h"
#include "packets/utils.h"

using namespace std;
const std::vector<byte> temp = {0xe0, 0xbd, 0x18, 0xdb, 0x4c, 0xc2, 0xf8, 0x5c,
                                0xed, 0xef, 0x65, 0x4f, 0xcc, 0xc4, 0xa4, 0xd8};

const std::string LOGGER_NAME = "client";
std::string hashString(std::string input, std::string hash);
int main(int argc, char **argv) {
    using namespace TCLAP;
    try {

        CmdLine cmd("NAS Test Client", ' ');

        ValueArg<string> logpathArg("l", "log",
                                    "The path where log file shall be written",
                                    false, "client.log", "string");
        cmd.add(logpathArg);

        ValueArg<string> loginArg(
            "u", "username", "The name of a user that wishes to authenticate",
            false, "Basia", "string");
        cmd.add(loginArg);

        ValueArg<string> passArg("", "password", "The password of a user",
                                 false, "password", "string");
        cmd.add(passArg);

        /*         SwitchArg interSwitch("i", "interactive", */
        /*                               "Run in the interactive mode", false);
         */
        /*         cmd.add(interSwitch); */

        SwitchArg verboseSwitch("v", "verbose", "Run in the verbose mode",
                                false);
        cmd.add(verboseSwitch);

        ValueArg<string> secretArg("s", "secret", "The secret shared with NAS",
                                   true, "", "string");
        cmd.add(secretArg);

        ValueArg<int> portArg("p", "port", "Binded port", false, 0, "number");
        cmd.add(portArg);

        ValueArg<string> bindIpArg("b", "bind-ip", "Binded IP address", false,
                                   "0.0.0.0", "IP");

        cmd.add(bindIpArg);

        ValueArg<string> ipArg("a", "address", "Server IP address", true, "",
                               "IP");

        cmd.add(ipArg);

        ValueArg<string> hashArg(
            "", "hash", "Type of hashing function (crc32 md5 sha1 sha256 sha3)",
            false, "sha256", "string");
        cmd.add(hashArg);

        cmd.parse(argc, argv);

        int port = portArg.getValue();
        string ip = ipArg.getValue();
        string bindIp = ipArg.getValue();
        string secret = secretArg.getValue();
        string logpath = logpathArg.getValue();
        radius::initLogger(logpath, LOGGER_NAME);

        bool verbose = verboseSwitch.getValue();
        if (verbose) {
            spdlog::set_level(spdlog::level::trace);
        }

        auto logger = spdlog::get(LOGGER_NAME);

        string hash = hashArg.getValue();

        string login = loginArg.getValue();
        string pas = passArg.getValue();
        /* bool inter = interSwitch.getValue(); */
        // setup address structure //adres serwera
        struct sockaddr_in server_addr;
        memset((char *)&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_port = htons(port);

        /* if (inter) { */
        /*     login = radius::getUsername(); */
        /*     pas = radius::getPassword("Enter password:\n"); */
        /* } */
        pas = hashString(pas, hash);

        // radius::packets::Packet newPack(temp, server_addr);

        radius::startClient(ip.c_str(), port);
        // 1.access-request
        using namespace radius;
        using namespace radius::packets;
			EapPacket eapIdentity;
			eapIdentity = makeIdentity(login);
			eapIdentity.setType(EapPacket::RESPONSE);
			eapIdentity.setIdentifier(1);

			EapMessage eapMessage;
			eapMessage.setValue(eapIdentity.getBuffer());

			RadiusPacket arPacket;
			arPacket.setIdentifier(1);
			arPacket.setCode(RadiusPacket::ACCESS_REQUEST);
			std::array<radius::byte, 16> authTable = generateRandom16();
			arPacket.setAuthenticator(authTable);
			arPacket.addAVP(static_cast<const RadiusAVP &>(eapMessage));
			calcAndSetMsgAuth(arPacket, secret);

        radius::packets::Packet newPack(arPacket.getBuffer(), server_addr);
		logger->info() <<"Send Packet";
        logger->info() <<"[Packet:]\n" << packet2LogBytes(newPack.bytes);
		logger->info() <<"[RadiusPacket:]\n"<< arPacket;
		logger->info() <<"[EapPacket:]\n"<< eapIdentity;

        radius::sendPack(newPack);
        // 2.otrzymuj odpowiedz od Radius server
        newPack = radius::receivePack();

		RadiusPacket recArPacket(newPack.bytes);
		logger->info() <<"Received Packet";
		logger->info() <<"[Packet:]\n" <<packet2LogBytes(recArPacket.getBuffer());
		logger->info() <<"[RadiusPacket:]\n"<< recArPacket;
		EapPacket recEapIdentity = extractEapPacket(recArPacket);
		logger->info() <<"[EapPacket:]\n"<< recEapIdentity;

			std::array<radius::byte,16> chalArray =calcChalVal(recEapIdentity,secret);

		//make response
		EapPacket eapMd5Chal;
		eapMd5Chal = makeChallengeResp(chalArray);
		eapMd5Chal.setType(EapPacket::RESPONSE);
		eapMd5Chal.setIdentifier(2);

			EapMessage eapMessage2;
			eapMessage2.setValue(eapMd5Chal.getBuffer());

		RadiusPacket responsePacket;
		responsePacket.setIdentifier(2);
		responsePacket.setCode(RadiusPacket::ACCESS_REQUEST);
		authTable = generateRandom16();
		responsePacket.setAuthenticator(authTable);
		responsePacket.addAVP(static_cast<const RadiusAVP &>(eapMessage2));
		calcAndSetMsgAuth(responsePacket, secret);

		radius::packets::Packet responsePack(responsePacket.getBuffer() , server_addr);

			logger->info() <<"Send Packet";
			logger->info() <<"[Packet:]\n" << packet2LogBytes(responsePack.bytes);
			logger->info() <<"[RadiusPacket:]\n"<< responsePacket;
			logger->info() <<"[EapPacket:]\n"<< eapMd5Chal;

        radius::sendPack(responsePack);
        // 4.success or failure
        newPack = radius::receivePack();

		RadiusPacket sucArPacket(newPack.bytes);
		logger->info() <<"Received Packet";
		logger->info() <<"[Packet:]\n" <<packet2LogBytes(sucArPacket.getBuffer());
		logger->info() <<"[RadiusPacket:]\n"<< sucArPacket;
		EapPacket sucEapIdentity = extractEapPacket(recArPacket);
		logger->info() <<"[EapPacket:]\n"<< sucEapIdentity;
		if (newPack.bytes[0]==0x02)
		{
			logger->info() <<"ACCEPT";
		}
		else if (newPack.bytes[0]==0x03	)
		{
			logger->error() <<"REJECT";
		}

        radius::stopClient();

    } catch (ArgException &e) {
        cerr << "error: " << e.error() << " for arg " << e.argId() << endl;
    }
}

std::string hashString(std::string input, std::string hash) {
    std::string output;

    if (hash == "sha256") {
        SHA256 sha256;
        output = sha256(input);
    } else if (hash == "sha1") {
        SHA1 sha1;
        output = sha1(input);
    } else if (hash == "sha3") {
        SHA3 sha3;
        output = sha3(input);
    } else if (hash == "md5") {
        MD5 md5;
        output = md5(input);
    } else if (hash == "crc32") {
        CRC32 crc32;
        output = crc32(input);
    } else {
        output = input;
    }
    return output;
}
<commit_msg>password in md5<commit_after>#include "client_net.h"
#include "interactive.h"
#include "crc32.h"
#include "md5.h"
#include "sha1.h"
#include "sha256.h"
#include "sha3.h"
#include "spdlog/spdlog.h"
#include "logging.h"
#include "auth_common.h"
#include "packets/radius_packet.h"
#include "packets/eap_packet.h"
#include "packets/packet.h"
#include "packets/utils.h"

using namespace std;
const std::vector<byte> temp = {0xe0, 0xbd, 0x18, 0xdb, 0x4c, 0xc2, 0xf8, 0x5c,
                                0xed, 0xef, 0x65, 0x4f, 0xcc, 0xc4, 0xa4, 0xd8};

const std::string LOGGER_NAME = "client";
std::string hashString(std::string input, std::string hash);
int main(int argc, char **argv) {
    using namespace TCLAP;
    try {

        CmdLine cmd("NAS Test Client", ' ');

        ValueArg<string> logpathArg("l", "log",
                                    "The path where log file shall be written",
                                    false, "client.log", "string");
        cmd.add(logpathArg);

        ValueArg<string> loginArg(
            "u", "username", "The name of a user that wishes to authenticate",
            false, "Basia", "string");
        cmd.add(loginArg);

        ValueArg<string> passArg("", "password", "The password of a user",
                                 false, "password", "string");
        cmd.add(passArg);

        /*         SwitchArg interSwitch("i", "interactive", */
        /*                               "Run in the interactive mode", false);
         */
        /*         cmd.add(interSwitch); */

        SwitchArg verboseSwitch("v", "verbose", "Run in the verbose mode",
                                false);
        cmd.add(verboseSwitch);

        ValueArg<string> secretArg("s", "secret", "The secret shared with NAS",
                                   true, "", "string");
        cmd.add(secretArg);

        ValueArg<int> portArg("p", "port", "Binded port", false, 0, "number");
        cmd.add(portArg);

        ValueArg<string> bindIpArg("b", "bind-ip", "Binded IP address", false,
                                   "0.0.0.0", "IP");

        cmd.add(bindIpArg);

        ValueArg<string> ipArg("a", "address", "Server IP address", true, "",
                               "IP");

        cmd.add(ipArg);

        ValueArg<string> hashArg(
            "", "hash", "Type of hashing function (crc32 md5 sha1 sha256 sha3)",
            false, "sha256", "string");
        cmd.add(hashArg);

        cmd.parse(argc, argv);

        int port = portArg.getValue();
        string ip = ipArg.getValue();
        string bindIp = ipArg.getValue();
        string secret = secretArg.getValue();
        string logpath = logpathArg.getValue();
        radius::initLogger(logpath, LOGGER_NAME);

        bool verbose = verboseSwitch.getValue();
        if (verbose) {
            spdlog::set_level(spdlog::level::trace);
        }

        auto logger = spdlog::get(LOGGER_NAME);

        string hash = hashArg.getValue();

        string login = loginArg.getValue();
        string pas = passArg.getValue();
        /* bool inter = interSwitch.getValue(); */
        // setup address structure //adres serwera
        struct sockaddr_in server_addr;
        memset((char *)&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_port = htons(port);

        /* if (inter) { */
        /*     login = radius::getUsername(); */
        /*     pas = radius::getPassword("Enter password:\n"); */
        /* } */
        pas = hashString(pas, hash);

        // radius::packets::Packet newPack(temp, server_addr);

        radius::startClient(ip.c_str(), port);
        // 1.access-request
        using namespace radius;
        using namespace radius::packets;
			EapPacket eapIdentity;
			eapIdentity = makeIdentity(login);
			eapIdentity.setType(EapPacket::RESPONSE);
			eapIdentity.setIdentifier(1);

			EapMessage eapMessage;
			eapMessage.setValue(eapIdentity.getBuffer());

			RadiusPacket arPacket;
			arPacket.setIdentifier(1);
			arPacket.setCode(RadiusPacket::ACCESS_REQUEST);
			std::array<radius::byte, 16> authTable = generateRandom16();
			arPacket.setAuthenticator(authTable);
			arPacket.addAVP(static_cast<const RadiusAVP &>(eapMessage));
			calcAndSetMsgAuth(arPacket, secret);

        radius::packets::Packet newPack(arPacket.getBuffer(), server_addr);
		logger->info() <<"Send Packet";
        logger->info() <<"[Packet:]\n" << packet2LogBytes(newPack.bytes);
		logger->info() <<"[RadiusPacket:]\n"<< arPacket;
		logger->info() <<"[EapPacket:]\n"<< eapIdentity;

        radius::sendPack(newPack);
        // 2.otrzymuj odpowiedz od Radius server
        newPack = radius::receivePack();

		RadiusPacket recArPacket(newPack.bytes);
		logger->info() <<"Received Packet";
		logger->info() <<"[Packet:]\n" <<packet2LogBytes(recArPacket.getBuffer());
		logger->info() <<"[RadiusPacket:]\n"<< recArPacket;
		EapPacket recEapIdentity = extractEapPacket(recArPacket);
		logger->info() <<"[EapPacket:]\n"<< recEapIdentity;

			std::array<radius::byte,16> chalArray =calcChalVal(recEapIdentity,pas);

		//make response
		EapPacket eapMd5Chal;
		eapMd5Chal = makeChallengeResp(chalArray);
		eapMd5Chal.setType(EapPacket::RESPONSE);
		eapMd5Chal.setIdentifier(2);

			EapMessage eapMessage2;
			eapMessage2.setValue(eapMd5Chal.getBuffer());

		RadiusPacket responsePacket;
		responsePacket.setIdentifier(2);
		responsePacket.setCode(RadiusPacket::ACCESS_REQUEST);
		authTable = generateRandom16();
		responsePacket.setAuthenticator(authTable);
		responsePacket.addAVP(static_cast<const RadiusAVP &>(eapMessage2));
		calcAndSetMsgAuth(responsePacket, secret);

		radius::packets::Packet responsePack(responsePacket.getBuffer() , server_addr);

			logger->info() <<"Send Packet";
			logger->info() <<"[Packet:]\n" << packet2LogBytes(responsePack.bytes);
			logger->info() <<"[RadiusPacket:]\n"<< responsePacket;
			logger->info() <<"[EapPacket:]\n"<< eapMd5Chal;

        radius::sendPack(responsePack);
        // 4.success or failure
        newPack = radius::receivePack();

		RadiusPacket sucArPacket(newPack.bytes);
		logger->info() <<"Received Packet";
		logger->info() <<"[Packet:]\n" << packet2LogBytes(sucArPacket.getBuffer());
		logger->info() <<"[RadiusPacket:]\n"<< sucArPacket;
		EapPacket sucEapIdentity = extractEapPacket(recArPacket);
		logger->info() <<"[EapPacket:]\n"<< sucEapIdentity;
		if (newPack.bytes[0]==0x02)
		{
			logger->info() <<"ACCEPT";
		}
		else if (newPack.bytes[0]==0x03	)
		{
			logger->error() <<"REJECT";
		}

        radius::stopClient();

    } catch (ArgException &e) {
        cerr << "error: " << e.error() << " for arg " << e.argId() << endl;
    }
}

std::string hashString(std::string input, std::string hash) {
    std::string output;

    if (hash == "sha256") {
        SHA256 sha256;
        output = sha256(input);
    } else if (hash == "sha1") {
        SHA1 sha1;
        output = sha1(input);
    } else if (hash == "sha3") {
        SHA3 sha3;
        output = sha3(input);
    } else if (hash == "md5") {
        MD5 md5;
        output = md5(input);
    } else if (hash == "crc32") {
        CRC32 crc32;
        output = crc32(input);
    } else {
        output = input;
    }
    return output;
}
<|endoftext|>