Strongswan hashtable enumerator backtrace可运行观察

//宏
#include <stdio.h>
#include <stdint.h>
#include <execinfo.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/**
 *  hashtable macro
 */
/* The minimum size of the hash table (MUST be a power of 2) */
#define MIN_SIZE 8
/** The maximum size of the hash table (MUST be a power of 2) */
#define MAX_SIZE (1 << 30)

/** Determine the capacity/maximum load of the table (higher values cause
 * more collisions, lower values increase the memory overhead) */
#define CAPACITY(size) (size / 3 * 2)
/** Factor for the new table size based on the number of items when resizing,
 * with the above load factor this results in doubling the size when growing */
#define RESIZE_FACTOR 3


#define INIT(this, ...) ({ (this) = malloc(sizeof(*(this))); \
                           *(this) = (typeof(*(this))){ __VA_ARGS__ }; (this); })

#define TRUE true
#define FALSE false

#define METHOD(iface, name, ret, this, ...) \
    static ret name(union {iface *_public; this;} \
    __attribute__((transparent_union)), ##__VA_ARGS__); \
    static typeof(name) *_##name = (typeof(name)*)name; \
    static ret name(this, ##__VA_ARGS__)

/**
 * Macro gives back larger of two values.
 */
#define max(x,y) ({ \
    typeof(x) _x = (x); \
    typeof(y) _y = (y); \
    _x > _y ? _x : _y; })

/**
  * args macro
  */
/**
 * This macro allows counting the number of arguments passed to a macro.
 * Combined with the VA_ARGS_DISPATCH() macro this can be used to implement
 * macro overloading based on the number of arguments.
 * 0 to 10 arguments are currently supported.
 */
#define VA_ARGS_NUM(...) _VA_ARGS_NUM(0,##__VA_ARGS__,10,9,8,7,6,5,4,3,2,1,0)
#define _VA_ARGS_NUM(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,NUM,...) NUM

/**
 * This macro can be used to dispatch a macro call based on the number of given
 * arguments, for instance:
 *
 * @code
 * #define MY_MACRO(...) VA_ARGS_DISPATCH(MY_MACRO, __VA_ARGS__)(__VA_ARGS__)
 * #define MY_MACRO1(arg) one_arg(arg)
 * #define MY_MACRO2(arg1,arg2) two_args(arg1,arg2)
 * @endcode
 *
 * MY_MACRO() can now be called with either one or two arguments, which will
 * resolve to one_arg(arg) or two_args(arg1,arg2), respectively.
 */
#define VA_ARGS_DISPATCH(func, ...) _VA_ARGS_DISPATCH(func, VA_ARGS_NUM(__VA_ARGS__))
#define _VA_ARGS_DISPATCH(func, num) __VA_ARGS_DISPATCH(func, num)
#define __VA_ARGS_DISPATCH(func, num) func ## num

/**
 * Assign variadic arguments to the given variables.
 *
 * @note The order and types of the variables are significant and must match the
 * variadic arguments passed to the function that calls this macro exactly.
 *
 * @param last		the last argument before ... in the function that calls this
 * @param ...		variable names
 */
#define VA_ARGS_GET(last, ...) ({ \
    va_list _va_args_get_ap; \
    va_start(_va_args_get_ap, last); \
    _VA_ARGS_GET_ASGN(__VA_ARGS__) \
    va_end(_va_args_get_ap); \
})

/**
 * Assign variadic arguments from a va_list to the given variables.
 *
 * @note The order and types of the variables are significant and must match the
 * variadic arguments passed to the function that calls this macro exactly.
 *
 * @param list		the va_list variable in the function that calls this
 * @param ...		variable names
 */
#define VA_ARGS_VGET(list, ...) ({ \
    va_list _va_args_get_ap; \
    va_copy(_va_args_get_ap, list); \
    _VA_ARGS_GET_ASGN(__VA_ARGS__) \
    va_end(_va_args_get_ap); \
})

#define _VA_ARGS_GET_ASGN(...) VA_ARGS_DISPATCH(_VA_ARGS_GET_ASGN, __VA_ARGS__)(__VA_ARGS__)
#define _VA_ARGS_GET_ASGN1(v1) __VA_ARGS_GET_ASGN(v1)
#define _VA_ARGS_GET_ASGN2(v1,v2) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2)
#define _VA_ARGS_GET_ASGN3(v1,v2,v3) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
    __VA_ARGS_GET_ASGN(v3)
#define _VA_ARGS_GET_ASGN4(v1,v2,v3,v4) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
    __VA_ARGS_GET_ASGN(v3) __VA_ARGS_GET_ASGN(v4)
#define _VA_ARGS_GET_ASGN5(v1,v2,v3,v4,v5) __VA_ARGS_GET_ASGN(v1) __VA_ARGS_GET_ASGN(v2) \
    __VA_ARGS_GET_ASGN(v3) __VA_ARGS_GET_ASGN(v4) __VA_ARGS_GET_ASGN(v5)
#define __VA_ARGS_GET_ASGN(v) v = va_arg(_va_args_get_ap, typeof(v));
/**
 * enumerator
 */

typedef struct hashtable_t hashtable_t;
typedef struct hashlist_t hashlist_t;

typedef struct enumerator_t enumerator_t;

/**
 * Enumerator interface, allows enumeration over collections.
 */
struct enumerator_t {
    bool (*enumerate)(enumerator_t *this, ...);
    bool (*venumerate)(enumerator_t *this, va_list args);
    void (*destroy)(enumerator_t *this);
};

bool enumerator_enumerate_default(enumerator_t *enumerator, ...)
{
    va_list args;
    bool result;

    if (!enumerator->venumerate)
    {
        return FALSE;
    }
    va_start(args, enumerator);
    result = enumerator->venumerate(enumerator, args);
    va_end(args);
    return result;
}

METHOD(enumerator_t, enumerate_empty, bool,
    enumerator_t *enumerator, va_list args)
{
    return FALSE;
}
/**
  * backtrace
  */
typedef struct backtrace_t backtrace_t;

/**
 * 反向跟踪会在创建过程中将帧注册到堆栈上。
 */
struct backtrace_t {

    /**
     * 将回溯记录到 FILE 流中。
     *
     * 如果没有给出文件指针,则通过调试框架报告给已注册的 dbg() 回调函数。
     *
     * @param file		记录回溯日志的文件,对于 dbg() 函数为空
     * @param detailed	TRUE 表示使用 addr2line 解析行/文件(速度慢)
     */
    void (*log)(backtrace_t *this, FILE *file, bool detailed);

    /**
     * 检查回溯是否包含一个具有列表函数的帧。
     *
     * @param		函数名数组
     * @param		函数数组中的元素数
     * @return		如果其中一个函数在堆栈中,则为 TRUE
     */
    bool (*contains_function)(backtrace_t *this, char *function[], int count);

    /**
     * 检查两条回溯线是否相等。
     *
     * @param other	backtrace to compare to this
     * @return		TRUE if backtraces are equal
     */
    bool (*equals)(backtrace_t *this, backtrace_t *other);

    /**
     * 创建该回溯跟踪的副本。
     *
     * @return		cloned copy
     */
    backtrace_t* (*clone)(backtrace_t *this);

    /**
     * 在堆栈帧地址上创建一个枚举器。
     *
     * @return		enumerator_t over void*
     */
    enumerator_t* (*create_frame_enumerator)(backtrace_t *this);

    /**
     * 销毁一个反向跟踪实例。
     */
    void (*destroy)(backtrace_t *this);
};

typedef struct private_backtrace_t private_backtrace_t;

/**
 * Private data of an backtrace_t object.
 */
struct private_backtrace_t {

    /**
     * Public backtrace_t interface.
     */
    backtrace_t public;

    /**
     * 在 stack_frames 中获得的堆栈帧数
     */
    int frame_count;

    /**
     * 记录的堆栈帧。
     */
    void *frames[];
};

/**
 * 为整数表达式构建断言宏,求值为 0
 */
#define BUILD_ASSERT(x) (sizeof(char[(x) ? 0 : -1]))

/**
 * 构建时检查断言 a 是数组,结果为 0
 *
 * 数组元素的地址是指针类型,与数组类型不兼容。
 */
#define BUILD_ASSERT_ARRAY(a) \
        BUILD_ASSERT(!__builtin_types_compatible_p(typeof(a), typeof(&(a)[0])))

/**
 * 获取数组中元素的个数
 */
#define countof(array) (sizeof(array)/sizeof((array)[0]) \
                        + BUILD_ASSERT_ARRAY(array))

static backtrace_t get_methods();

/**
 * 将带有参数的格式字符串写入 FILE 行,如果为 NULL,则写入 DBG
 */
static void println(FILE *file, char *format, ...)
{
    char buf[512];
    va_list args;

    va_start(args, format);
    if (file)
    {
        vfprintf(file, format, args);
        fputs("\n", file);
    }
    else
    {
        vsnprintf(buf, sizeof(buf), format, args);
    }
    va_end(args);
}

METHOD(backtrace_t, log_, void,
    private_backtrace_t *this, FILE *file, bool detailed)
{
    size_t i;
    char **strings = NULL;

    println(file, " dumping %d stack frame addresses:", this->frame_count);
    for (i = 0; i < this->frame_count; i++)
    {
        if (!strings)
        {
            strings = backtrace_symbols(this->frames, this->frame_count);
        }
        if (strings)
        {
            println(file, "    %s", strings[i]);
        }
        else
        {
            println(file, "    %p", this->frames[i]);
        }
    }
    free(strings);
}

METHOD(backtrace_t, contains_function, bool,
    private_backtrace_t *this, char *function[], int count)
{
    return FALSE;
}

METHOD(backtrace_t, equals, bool,
    private_backtrace_t *this, backtrace_t *other_public)
{
    private_backtrace_t *other = (private_backtrace_t*)other_public;
    int i;

    if (this == other)
    {
        return TRUE;
    }
    if (this->frame_count != other->frame_count)
    {
        return FALSE;
    }
    for (i = 0; i < this->frame_count; i++)
    {
        if (this->frames[i] != other->frames[i])
        {
            return FALSE;
        }
    }
    return TRUE;
}

/**
 * Frame enumerator
 */
typedef struct {
    /** implements enumerator_t */
    enumerator_t public;
    /** reference to backtrace */
    private_backtrace_t *bt;
    /** current position */
    int i;
} frame_enumerator_t;

METHOD(enumerator_t, frame_enumerate, bool,
    frame_enumerator_t *this, va_list args)
{
    void **addr;

    VA_ARGS_VGET(args, addr);

    if (this->i < this->bt->frame_count)
    {
        *addr = this->bt->frames[this->i++];
        return TRUE;
    }
    return FALSE;
}


METHOD(backtrace_t, create_frame_enumerator, enumerator_t*,
    private_backtrace_t *this)
{
    frame_enumerator_t *enumerator;

    INIT(enumerator,
        .public = {
            .enumerate = enumerator_enumerate_default,
            .venumerate = _frame_enumerate,
            .destroy = (void*)free,
        },
        .bt = this,
    );
    return &enumerator->public;
}


METHOD(backtrace_t, destroy, void,
    private_backtrace_t *this)
{
    free(this);
}

METHOD(backtrace_t, clone_, backtrace_t*,
    private_backtrace_t *this)
{
    private_backtrace_t *clone;

    clone = malloc(sizeof(private_backtrace_t) +
                   this->frame_count * sizeof(void*));
    memcpy(clone->frames, this->frames, this->frame_count * sizeof(void*));
    clone->frame_count = this->frame_count;

    clone->public = get_methods();

    return &clone->public;
}

/**
 * 获取 backtrace_t 的实现方法
 */
static backtrace_t get_methods()
{
    return (backtrace_t) {
        .log = _log_,
        .contains_function = _contains_function,
        .equals = _equals,
        .clone = _clone_,
        .create_frame_enumerator = _create_frame_enumerator,
        .destroy = _destroy,
    };
}


backtrace_t *backtrace_create(int skip)
{
    private_backtrace_t *this;
    void *frames[50];
    int frame_count = 0;

    frame_count = backtrace(frames, countof(frames));

    frame_count = max(frame_count - skip, 0);
    this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));
    memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
    this->frame_count = frame_count;

    this->public = get_methods();

    return &this->public;
}

void backtrace_dump(char *label, FILE *file, bool detailed)
{
    backtrace_t *backtrace;

    backtrace = backtrace_create(2);

    if (label)
    {
        println(file, "Debug backtrace: %s", label);
    }
    backtrace->log(backtrace, file, detailed);
    backtrace->destroy(backtrace);
}
/**
  * hashtable_profile
  */
typedef struct hashtable_profile_t hashtable_profile_t;

struct hashtable_profile_t {

    /**
     * 表中概况查找的一些统计数据
     */
    struct {
        size_t count;
        size_t probes;
        size_t longest;
    } success, failure;

    /**
     * 统计表的内存使用情况
     */
    struct {
        size_t count;
        size_t size;
    } max;

    /**
     * 跟踪哈希表的创建位置
     */
    backtrace_t *backtrace;
};

/**
 * Print and cleanup profiling data
 */
static inline void profiler_cleanup(hashtable_profile_t *profile, u_int count,
                                    u_int size)
{
    if (profile->success.count || profile->failure.count)
    {
        fprintf(stderr, "%zu elements [max. %zu], %zu buckets [%zu], %zu "
                "successful / %zu failed lookups, %.4f [%zu] / %.4f "
                "[%zu] avg. probes in table created at:",
                count, profile->max.count, size, profile->max.size,
                profile->success.count, profile->failure.count,
                (double)profile->success.probes/profile->success.count,
                profile->success.longest,
                (double)profile->failure.probes/profile->failure.count,
                profile->failure.longest);
        profile->backtrace->log(profile->backtrace, stderr, TRUE);
    }
    profile->backtrace->destroy(profile->backtrace);
}


static inline void profiler_init(hashtable_profile_t *profile, int skip)
{
    profile->backtrace = backtrace_create(skip);
}

#define lookup_start() \
    u_int _lookup_probes = 0;

#define lookup_probing() \
    _lookup_probes++;

#define _lookup_done(profile, result) \
    (profile)->result.count++; \
    (profile)->result.probes += _lookup_probes; \
    (profile)->result.longest = max((profile)->result.longest, _lookup_probes);

#define lookup_success(profile) _lookup_done(profile, success);
#define lookup_failure(profile) _lookup_done(profile, failure);

static inline void profile_size(hashtable_profile_t *profile, u_int size)
{
    profile->max.size = max(profile->max.size, size);
}

static inline void profile_count(hashtable_profile_t *profile, u_int count)
{
    profile->max.count = max(profile->max.count, count);
}

/**
  * hash table
  */

/**
 *
 * 这个哈希表不是同步的.也即不是线程安全的,不支持多线程。
 *
 * 枚举条目时会保留插入顺序。
 */
struct hashtable_t {

    /**
     * 在哈希表键/值对上创建一个枚举器。
     *
     * @return			enumerator over (void *key, void *value)
     */
    enumerator_t *(*create_enumerator)(hashtable_t *this);

    /**
     * 如果哈希表中没有包含给定键值的条目,则将该键值添加到哈希表中。
     * 在这种情况下会返回 NULL。否则,现有值将被替换,函数返回 旧值。
     *
     * @param key		the key to store
     * @param value		the value to store
     * @return			NULL if no item was replaced, the old value otherwise
     */
    void *(*put)(hashtable_t *this, const void *key, void *value);

    /**
     * 如果哈希表中包含给定的键,则返回该键的值。否则返回 NULL。
     *
     * @param key		the key of the requested value
     * @return			the value, NULL if not found
     */
    void *(*get)(hashtable_t *this, const void *key);

    /**
     * 从哈希表中移除带有给定键值的值,并返回移除的值。值(如果不存在该值,则返回 NULL)。
     *
     * @param key		the key of the value to remove
     * @return			the removed value, NULL if not found
     */
    void *(*remove)(hashtable_t *this, const void *key);

    /**
     * 从哈希表中删除键和值对。枚举器当前指向的哈希表中删除键和值对。
     *
     * @param enumerator	enumerator, from create_enumerator
     */
    void (*remove_at)(hashtable_t *this, enumerator_t *enumerator);

    /**
     * 获取哈希表中的项目数。
     *
     * @return			number of items
     */
    uint32_t (*get_count)(hashtable_t *this);

    /**
     * 销毁一个哈希表对象。
     */
    void (*destroy)(hashtable_t *this);

    /**
     * 销毁散列表对象,并为散列表中的每个项及其键调用给定函数。
     *
     * @param function	function to call on each item and key
     */
    void (*destroy_function)(hashtable_t *this,
                             void (*)(void *val, const void *key));
};



typedef struct pair_t pair_t;

/**
 * 这对指针指向键及其代表的值。
 */
struct pair_t {

    /**
     * 哈希表项的键值。
     */
    const void *key;

    /**
     * 哈希表项的值。
     */
    void *value;

    /**
     * 缓存哈希值(调整大小时使用)。
     */
    uint32_t hash;
};

/**
 * 根据给定键值计算哈希值的函数原型。
 *
 * @param key			key to hash
 * @return				hash code
 */
typedef uint32_t (*hashtable_hash_t)(const void *key);

/**
 * 比较两个键是否相等的函数原型。
 *
 * @param key			first key (the one we are looking for/inserting)
 * @param other_key		second key
 * @return				TRUE if the keys are equal
 */
typedef bool (*hashtable_equals_t)(const void *key, const void *other_key);

typedef struct private_hashtable_t private_hashtable_t;
struct private_hashtable_t {

    /**
     * Public part of hash table.
     */
    hashtable_t public;

    /**
     * 哈希表中的项目数。
     */
    uint32_t count;

    /**
     * 哈希表的当前大小(总是 2 的幂次)。
     */
    uint32_t size;

    /**
     * 用于计算行索引的当前掩码(大小 - 1)。 (size - 1).
     */
    uint32_t mask;

    /**
     * 所有项目的插入顺序(移除的项目以 键设置为空,直至调整大小)。
     */
    pair_t *items;

    /**
     * 上述数组和整个表的可用槽数、 在初始化哈希表时设置为 CAPACITY(size)。
     */
    uint32_t capacity;

    /**
     * 上述数组中已使用插槽的数量。
     */
    uint32_t items_count;

    /**
     * 包含上述数组索引的哈希表。 类型取决于当前容量。
     */
    void *table;

    /**
     * 哈希函数
     */
    hashtable_hash_t hash;

    /**
     * 比较函数.
     */
    hashtable_equals_t equals;

    /**
     * 性能剖析数据
     */
    hashtable_profile_t profile;
};

/**
 * Macro gives back smaller of two values.
 */
#define min(x,y) ({ \
    typeof(x) _x = (x); \
    typeof(y) _y = (y); \
    _x < _y ? _x : _y; })

/**
 * 此函数返回给定数字的次高幂2。该算法的工作原理是将最高有效1右侧的所有位设置为1,
 * 然后递增整数,使其滚动到最接近的2次幂。注意:n=0时返回0
 *
 * Also used by hashlist_t.
 */
u_int hashtable_get_nearest_powerof2(u_int n)
{
    u_int i;

    --n;
    for (i = 1; i < sizeof(u_int) * 8; i <<= 1)
    {
        n |= n >> i;
    }
    return ++n;
}

/**
 * 将哈希表初始化为给定大小
 */
static void init_hashtable(private_hashtable_t *this, u_int size)
{
    u_int index_size = sizeof(u_int);

    this->size = max(MIN_SIZE, min(size, MAX_SIZE));
    this->size = hashtable_get_nearest_powerof2(this->size);
    this->mask = this->size - 1;
    profile_size(&this->profile, this->size);

    this->capacity = CAPACITY(this->size);
    this->items = calloc(this->capacity, sizeof(pair_t));
    this->items_count = 0;

    if (this->capacity <= 0xff)
    {
        index_size = sizeof(uint8_t);
    }
    else if (this->capacity <= 0xffff)
    {
        index_size = sizeof(uint16_t);
    }
    this->table = calloc(this->size, index_size);
}

/**
 * Calculate the next bucket using quadratic probing (the sequence is h(k) + 1,
 * h(k) + 3, h(k) + 6, h(k) + 10, ...).
 * 使用二次探测计算下一个桶(the sequence is h(k) + 1,h(k) + 3, h(k) + 6, h(k) + 10, ...)。
 */
static inline u_int get_next(private_hashtable_t *this, u_int row, u_int *p)
{
    *p += 1;
    return (row + *p) & this->mask;
}

/**
 * 返回存储在给定存储桶中的索引。如果存储桶为空,则返回 0.
 */
static inline u_int get_index(private_hashtable_t *this, u_int row)
{
    if (this->capacity <= 0xff)
    {
        return ((uint8_t*)this->table)[row];
    }
    else if (this->capacity <= 0xffff)
    {
        return ((uint16_t*)this->table)[row];
    }
    return ((u_int*)this->table)[row];
}

/**
 * 设置存储在给定存储桶中的索引。设置为 0 可清除存储桶。
 */
static inline void set_index(private_hashtable_t *this, u_int row, u_int index)
{
    if (this->capacity <= 0xff)
    {
        ((uint8_t*)this->table)[row] = index;
    }
    else if (this->capacity <= 0xffff)
    {
        ((uint16_t*)this->table)[row] = index;
    }
    else
    {
        ((u_int*)this->table)[row] = index;
    }
}

/**
 * Helper 将新项插入 table 和 items 数组,将其新索引返回到后者中。
 */
static inline u_int insert_item(private_hashtable_t *this, u_int row)
{
    u_int index = this->items_count++;

    /* 我们使用 0 来标记未使用的存储桶,因此增加索引 */
    set_index(this, row, index + 1);
    return index;
}

/**
 * 将哈希表的大小调整为给定的大小并重新哈希所有元素,大小可能更小,甚至相同
 *(例如,如果需要清除以前使用的存储桶)。
 */
static bool rehash(private_hashtable_t *this, u_int size)
{
    pair_t *old_items, *pair;
    u_int old_count, i, p, row, index;

    if (size > MAX_SIZE)
    {
        return FALSE;
    }

    old_items = this->items;
    old_count = this->items_count;
    //释放当前hash表,然后按新的size分配新的hash表空间(size*sizeof(pair_t*));新的items空间.
    free(this->table);
    init_hashtable(this, size);
    //注意此处hash表所有的桶都为空了


    /* 如果表是空的this->count=0,则无需执行任何动作,我们只是在清理以前使用过的项目 */
    //this->count > 0 表示原来有表项,表项数
    if (this->count)
    {
        //遍历old_items,存储的是所有插入的pair,由于hash表不能遍历,遍历使用items数组
        //但是这些pair[移除的项目键设置已经设为空,直至保持到调整表大小时候]所以下面要判断key
        for (i = 0; i < old_count; i++)
        {
            pair = &old_items[i];

            //该pair没有移除,则重新插入新表中
            if (pair->key)
            {
                //hash值掩码得到hash桶在hash表索引row
                row = pair->hash & this->mask;
                //返回该桶中保存的索引,为空时为0
                index = get_index(this, row);
                //若桶不空,则遍历找到空桶
                for (p = 0; index;)
                {
                    //下一个桶
                    row = get_next(this, row, &p);
                    //返回下一个桶是否为空
                    index = get_index(this, row);
                }

                //找到空桶后,标记该桶已经使用,标记值为this->items_count++,对应
                //this->items中的下标值+1
                //一个桶只能标记一次
                index = insert_item(this, row);

                //重新插入pair到items,index为this->items_count++,在old_count后面
                this->items[index] = *pair;
            }
        }
    }
    //释放之前的items
    free(old_items);
    return TRUE;
}

/**
 * 查找具有给定键的对,如果找不到键,可以选择返回哈希和第一个空行或以前使用的行。
 */
static inline pair_t *find_key(private_hashtable_t *this, const void *key,
                                u_int *out_hash, u_int *out_row)
{
    pair_t *pair;
    u_int hash, row, p = 0, removed = 0, index;
    bool found_removed = FALSE;

    //this->count=0 空表
    if (!this->count && !out_hash && !out_row)
    {
        return NULL;
    }

    lookup_start();

    hash = this->hash(key);
    row = hash & this->mask;
    index = get_index(this, row);
    while (index)
    {
        lookup_probing();
        pair = &this->items[index-1];

        if (!pair->key)
        {
            //key为0,表示表项删除
            if (!found_removed && out_row)
            {
                removed = row;
                found_removed = TRUE;
            }
        }
        else if (pair->hash == hash && this->equals(key, pair->key))
        {
            //比较key,查找成功遍历查找非空桶后比较
            lookup_success(&this->profile);
            return pair;
        }

        //桶碰撞,则向后,遇到index=0时跳出循环,返回该空行
        row = get_next(this, row, &p);
        index = get_index(this, row);
    }
    if (out_hash)
    {
        *out_hash = hash;
    }
    if (out_row)
    {
        *out_row = found_removed ? removed : row;
    }
    lookup_failure(&this->profile);
    return NULL;
}

METHOD(hashtable_t, put, void*,
    private_hashtable_t *this, const void *key, void *value)
{
    void *old_value = NULL;
    pair_t *pair;
    u_int index, hash = 0, row = 0;

    if (this->items_count >= this->capacity &&
        !rehash(this, this->count * RESIZE_FACTOR))
    {
        return NULL;
    }
    pair = find_key(this, key, &hash, &row);
    if (pair)
    {
        //若pair存在,则覆盖,返回之前的pair
        old_value = pair->value;
        pair->value = value;
        pair->key = key;
        return old_value;
    }
    //若不存在,则标记该桶,把pair保存在items中,桶和items配合得到pair
    index = insert_item(this, row);
    this->items[index] = (pair_t){
        .hash = hash,
        .key = key,
        .value = value,
    };
    //表项数增加
    this->count++;
    profile_count(&this->profile, this->count);
    return value;
}

METHOD(hashtable_t, get, void*,
    private_hashtable_t *this, const void *key)
{
    pair_t *pair = find_key(this, key, NULL, NULL);
    return pair ? pair->value : NULL;
}

/**
 * Remove the given item from the table, returns the currently stored value.
 */
static void *remove_internal(private_hashtable_t *this, pair_t *pair)
{
    void *value = NULL;

    if (pair)
    {	/* 这不会减少items项目计数,因为我们会保留以前使用的项目,
            直到重新哈希/调整表大小 */
        value = pair->value;

        //bug? no free
//        if (pair->key != pair->value){
//            free(pair->value);
//            pair->value = NULL;
//        }
//        free(pair->key);

        pair->key = NULL;
        this->count--;
    }
    return value;
}

METHOD(hashtable_t, remove_, void*,
    private_hashtable_t *this, const void *key)
{
    pair_t *pair = find_key(this, key, NULL, NULL);
    return remove_internal(this, pair);
}

typedef struct private_enumerator_t private_enumerator_t;
/**
 * Hash table enumerator implementation
 */
struct private_enumerator_t {

    /**
     * Implements enumerator interface
     */
    enumerator_t enumerator;

    /**
     * Associated hash table
     */
    private_hashtable_t *table;

    /**
     * Current index
     */
    u_int index;
};
METHOD(enumerator_t, enumerate, bool,
    private_enumerator_t *this, va_list args)
{
    const void **key;
    void **value;
    pair_t *pair;

    VA_ARGS_VGET(args, key, value);

    while (this->index < this->table->items_count)
    {
        pair = &this->table->items[this->index++];
        if (pair->key)
        {
            if (key)
            {
                *key = pair->key;
            }
            if (value)
            {
                *value = pair->value;
            }
            return TRUE;
        }
    }
    return FALSE;
}

METHOD(hashtable_t, create_enumerator, enumerator_t*,
    private_hashtable_t *this)
{
    private_enumerator_t *enumerator;

    INIT(enumerator,
        .enumerator = {
            .enumerate = enumerator_enumerate_default,
            .venumerate = _enumerate,
            .destroy = (void*)free,
        },
        .table = this,
    );
    return &enumerator->enumerator;
}

METHOD(hashtable_t, remove_at, void,
    private_hashtable_t *this, private_enumerator_t *enumerator)
{
    if (enumerator->table == this && enumerator->index)
    {
        printf("remove index: %d\n", enumerator->index);

        /* the index is already advanced by one */
        u_int index = enumerator->index - 1;
        remove_internal(this, &this->items[index]);
    }
}

METHOD(hashtable_t, get_count, u_int,
    private_hashtable_t *this)
{
    return this->count;
}

static void destroy_internal(private_hashtable_t *this,
                             void (*fn)(void*,const void*))
{
    pair_t *pair;
    u_int i;

    profiler_cleanup(&this->profile, this->count, this->size);

    if (fn)
    {
        //遍历items中的pair,使用fn函数destroy
        for (i = 0; i < this->items_count; i++)
        {
            pair = &this->items[i];
            if (pair->key)
            {
                fn(pair->value, pair->key);
            }

        }
    }
    free(this->items);
    free(this->table);
    free(this);
}

METHOD(hashtable_t, destroy_, void,
    private_hashtable_t *this)
{
    destroy_internal(this, NULL);
}

METHOD(hashtable_t, destroy_function, void,
    private_hashtable_t *this, void (*fn)(void*,const void*))
{
    destroy_internal(this, fn);
}

hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
                              u_int size)
{
    private_hashtable_t *this;

    INIT(this,
        .public = {
            .put = _put,
            .get = _get,
            .remove = _remove_,
            .remove_at = (void*)_remove_at,
            .get_count = _get_count,
            .create_enumerator = _create_enumerator,
            .destroy = _destroy_,
            .destroy_function = _destroy_function,
        },
        .hash = hash,
        .equals = equals,
    );

    init_hashtable(this, size);

    profiler_init(&this->profile, 2);

    return &this->public;
}
/**
 * test
 */

/**
 * Secret key allocated randomly with chunk_hash_seed().
 */
static u_char hash_key[16] = {};
void chunk_hash_seed()
{
    static bool seeded = FALSE;
    ssize_t len;
    size_t done = 0;
    int fd;

    if (seeded)
    {
        /* just once to have the same seed during the whole process lifetimes */
        return;
    }

    fd = open("/dev/urandom", O_RDONLY);
    if (fd >= 0)
    {
        //读取指定长度的随机数
        while (done < sizeof(hash_key))
        {
            len = read(fd, hash_key + done, sizeof(hash_key) - done);
            if (len < 0)
            {
                break;
            }
            done += len;
        }
        close(fd);
    }
    /* on error we use random() to generate the key (better than nothing) */
    if (done < sizeof(hash_key))
    {
        srandom(time(NULL) + getpid());
        for (; done < sizeof(hash_key); done++)
        {
            hash_key[done] = (u_char)random();
        }
    }
    seeded = TRUE;
}

typedef struct chunk_t chunk_t;
struct chunk_t {
    /** Pointer to start of data */
    u_char *ptr;
    /** Length of data in bytes */
    size_t len;
};

static inline uint64_t sipget(u_char *in)
{
    uint64_t v = 0;
    int i;

    for (i = 0; i < 64; i += 8, ++in)
    {
        v |= ((uint64_t)*in) << i;
    }
    return v;
}

static inline uint64_t siprotate(uint64_t v, int shift)
{
        return (v << shift) | (v >> (64 - shift));
}

static inline void sipround(uint64_t *v0, uint64_t *v1, uint64_t *v2,
                            uint64_t *v3)
{
    *v0 += *v1;
    *v1 = siprotate(*v1, 13);
    *v1 ^= *v0;
    *v0 = siprotate(*v0, 32);

    *v2 += *v3;
    *v3 = siprotate(*v3, 16);
    *v3 ^= *v2;

    *v2 += *v1;
    *v1 = siprotate(*v1, 17);
    *v1 ^= *v2;
    *v2 = siprotate(*v2, 32);

    *v0 += *v3;
    *v3 = siprotate(*v3, 21);
    *v3 ^= *v0;
}

static inline void sipcompress(uint64_t *v0, uint64_t *v1, uint64_t *v2,
                               uint64_t *v3, uint64_t m)
{
    *v3 ^= m;
    sipround(v0, v1, v2, v3);
    sipround(v0, v1, v2, v3);
    *v0 ^= m;
}

static inline uint64_t siplast(size_t len, u_char *pos)
{
    uint64_t b;
    int rem = len & 7;

    b = ((uint64_t)len) << 56;
    switch (rem)
    {
        case 7:
            b |= ((uint64_t)pos[6]) << 48;
        case 6:
            b |= ((uint64_t)pos[5]) << 40;
        case 5:
            b |= ((uint64_t)pos[4]) << 32;
        case 4:
            b |= ((uint64_t)pos[3]) << 24;
        case 3:
            b |= ((uint64_t)pos[2]) << 16;
        case 2:
            b |= ((uint64_t)pos[1]) <<  8;
        case 1:
            b |= ((uint64_t)pos[0]);
            break;
        case 0:
            break;
    }
    return b;
}

/**
 * Calculate SipHash-2-4 with an optional first block given as argument.
 */
static uint64_t chunk_mac_inc(chunk_t chunk, u_char *key, uint64_t m)
{
    uint64_t v0, v1, v2, v3, k0, k1;
    size_t len = chunk.len;
    u_char *pos = chunk.ptr, *end;

    end = chunk.ptr + len - (len % 8);

    k0 = sipget(key);
    k1 = sipget(key + 8);

    v0 = k0 ^ 0x736f6d6570736575ULL;
    v1 = k1 ^ 0x646f72616e646f6dULL;
    v2 = k0 ^ 0x6c7967656e657261ULL;
    v3 = k1 ^ 0x7465646279746573ULL;

    if (m)
    {
        sipcompress(&v0, &v1, &v2, &v3, m);
    }

    /* compression with c = 2 */
    for (; pos != end; pos += 8)
    {
        m = sipget(pos);
        sipcompress(&v0, &v1, &v2, &v3, m);
    }
    sipcompress(&v0, &v1, &v2, &v3, siplast(len, pos));

    /* finalization with d = 4 */
    v2 ^= 0xff;
    sipround(&v0, &v1, &v2, &v3);
    sipround(&v0, &v1, &v2, &v3);
    sipround(&v0, &v1, &v2, &v3);
    sipround(&v0, &v1, &v2, &v3);
    return v0 ^ v1 ^ v2  ^ v3;
}

uint32_t chunk_hash_inc(chunk_t chunk, uint32_t hash)
{
    /* we could use a mac of the previous hash, but this is faster */
    return chunk_mac_inc(chunk, hash_key, ((uint64_t)hash) << 32 | hash);
}

/**
 * Create a new chunk pointing to "ptr" with length "len"
 */
static inline chunk_t chunk_create(u_char *ptr, size_t len)
{
    chunk_t chunk = {ptr, len};
    return chunk;
}

uint64_t chunk_mac(chunk_t chunk, u_char *key)
{
    return chunk_mac_inc(chunk, key, 0);
}

/**
 * Initialize a chunk to point to a thing
 */
#define chunk_from_thing(thing) chunk_create((u_char*)&(thing), sizeof(thing))

uint32_t chunk_hash(chunk_t chunk)
{
    return chunk_mac(chunk, hash_key);
}

/**
 * Protocol ID of a proposal.
 */
enum protocol_id_t {
    PROTO_NONE = 0,
    PROTO_IKE = 1,
    PROTO_AH = 2,
    PROTO_ESP = 3,
    PROTO_IPCOMP = 4, /* IKEv1 only */
};

typedef enum protocol_id_t protocol_id_t;
typedef struct private_host_t private_host_t;

struct private_host_t {
    /**
     * low-lewel structure, which stores the address
     */
    union {
        /** generic type */
        struct sockaddr address;
        /** maximum sockaddr size */
        struct sockaddr_storage address_max;
        /** IPv4 address */
        struct sockaddr_in address4;
        /** IPv6 address */
        struct sockaddr_in6 address6;
    };
    /**
     * length of address structure
     */
    socklen_t socklen;
};

typedef struct {
    /** unique CHILD_SA identifier */
    uint32_t unique_id;
    /** inbound SPI */
    uint32_t spi_in;
    /** outbound SPI */
    uint32_t spi_out;
    /** inbound host address */
    private_host_t host_in;
    /** outbound host address and port */
    private_host_t host_out;
    /** IPsec protocol, AH|ESP */
    protocol_id_t proto;
} child_entry_t;


#define IPV6_LEN 6
#define IPV4_LEN 4
chunk_t chunk_empty = { NULL, 0 };
chunk_t get_address(private_host_t *this){
    chunk_t address = chunk_empty;

    switch (this->address.sa_family)
    {
        case AF_INET:
        {
            address.ptr = (char*)&(this->address4.sin_addr.s_addr);
            address.len = IPV4_LEN;
            return address;
        }
        case AF_INET6:
        {
            address.ptr = (char*)&(this->address6.sin6_addr.s6_addr);
            address.len = IPV6_LEN;
            return address;
        }
        default:
        {
            /* return empty chunk */
            return address;
        }
    }
}


/**
 * Hashtable hash function for inbound SAs
 */
static u_int hash_in(child_entry_t *entry)
{
    return chunk_hash_inc(chunk_from_thing(entry->spi_in),
            chunk_hash_inc(get_address(&entry->host_in),
             chunk_hash(chunk_from_thing(entry->proto))));
}

/**
 * Helper function that compares two binary blobs for equality
 */
static inline bool memeq(const void *x, const void *y, size_t len)
{
    return memcmp(x, y, len) == 0;
}


bool is_anyaddr(private_host_t *this){
    static const uint8_t zeroes[IPV6_LEN];

    switch (this->address.sa_family)
    {
        case AF_INET:
        {
            return memeq(zeroes, &(this->address4.sin_addr.s_addr), IPV4_LEN);
        }
        case AF_INET6:
        {
            return memeq(zeroes, &(this->address6.sin6_addr.s6_addr), IPV6_LEN);
        }
        default:
        {
            return FALSE;
        }
    }
}


/**
 * Implements host_t.ip_equals
 */
static bool ip_equals(private_host_t *this, private_host_t *other)
{
    if (this->address.sa_family != other->address.sa_family)
    {
        /* 0.0.0.0 and 0::0 are equal */
        return (is_anyaddr(this) && is_anyaddr(other));
    }

    switch (this->address.sa_family)
    {
        case AF_INET:
        {
            return memeq(&this->address4.sin_addr, &other->address4.sin_addr,
                         sizeof(this->address4.sin_addr));
        }
        case AF_INET6:
        {
            return memeq(&this->address6.sin6_addr, &other->address6.sin6_addr,
                         sizeof(this->address6.sin6_addr));
        }
        default:
            break;
    }
    return FALSE;
}

/**
 * Hashtable equals function for inbound SAs
 */
static bool equals_in(child_entry_t *a, child_entry_t *b)
{
    return a->spi_in == b->spi_in &&
           a->proto == b->proto &&
           ip_equals(&a->host_in, &b->host_in);
}

hashtable_t *child_sa_manager_create()
{
    hashtable_t *in;
    in = hashtable_create((hashtable_hash_t)hash_in,
                                   (hashtable_equals_t)equals_in, 8);

    return in;
}
int child_sa_put(hashtable_t *in){
    static uint32_t unique_id = 100;
    static uint32_t spi_in = 1;
    static uint32_t spi_out = 2;

    child_entry_t *entry;
    INIT(entry,
        .unique_id = unique_id++,
        .proto = PROTO_ESP,
        .spi_in = spi_in++,
        .spi_out = spi_out++,
    );
    entry->host_in.address4.sin_family = AF_INET;
    inet_pton(AF_INET, "192.168.1.250", &entry->host_in.address4.sin_addr);
    entry->host_out.address4.sin_family = AF_INET;
    inet_pton(AF_INET, "192.168.1.200", &entry->host_out.address4.sin_addr);

    child_entry_t *val;
    char buf[128];
    val = in->put(in, entry, entry);

    if (val){
        printf("unique_id: %d, spi_in: %d, spi_out: %d ",
               val->unique_id, val->spi_in, val->spi_out
        );
        printf("host_in:%s ",
               inet_ntop(AF_INET, &entry->host_in.address4.sin_addr, buf, sizeof(buf))
        );
        printf("host_out:%s\n",
               inet_ntop(AF_INET, &entry->host_out.address4.sin_addr, buf, sizeof(buf))
        );

    }else{
        printf("not find sa\n");
    }


    printf("count :%d\n", in->get_count(in));

    return 0;
}

//spi_in+host_in+proto+ hash[spi_in + host_in + proto]
child_entry_t *child_sa_get(hashtable_t *in, child_entry_t *entry){
    char buf[128];
    child_entry_t *val = in->get(in, entry);
    if (val){
        printf("get unique_id: %d, spi_in: %d, spi_out: %d ",
               val->unique_id, val->spi_in, val->spi_out
        );
        printf("host_in:%s ",
               inet_ntop(AF_INET, &val->host_in.address4.sin_addr, buf, sizeof(buf))
        );
        printf("host_out:%s\n",
               inet_ntop(AF_INET, &val->host_out.address4.sin_addr, buf, sizeof(buf))
        );

    }else{
        printf("not find sa\n");
    }

    printf("count :%d\n", in->get_count(in));

    return val;
}

//spi_in+host_in+proto+ hash[spi_in + host_in + proto]
child_entry_t *child_sa_remove(hashtable_t *in, child_entry_t *entry){
    char buf[128];
    child_entry_t *val = in->remove(in, entry);
    if (val){
        printf("remove unique_id: %d, spi_in: %d, spi_out: %d ",
               val->unique_id, val->spi_in, val->spi_out
        );
        printf("host_in:%s ",
               inet_ntop(AF_INET, &val->host_in.address4.sin_addr, buf, sizeof(buf))
        );
        printf("host_out:%s\n",
               inet_ntop(AF_INET, &val->host_out.address4.sin_addr, buf, sizeof(buf))
        );

    }else{
        printf("not find sa\n");
    }

    printf("count :%d\n", in->get_count(in));

    return val;
}


void child_sa_destroy(void* val, const void *key){
    if (val == key){
        free(key);
        val = NULL;
    }else{
        free(val);
        val = NULL;
        free(key);
        val = NULL;
    }
}

int main()
{
    hashtable_t *in;
    in = child_sa_manager_create();

    printf("count :%d\n", in->get_count(in));

    for (int i = 0; i < 100; i++){
        child_sa_put(in);
    }

    //屏蔽部分实际不参与比较
    child_entry_t entry = {
//        .unique_id = 101,
        .proto = PROTO_ESP,
        .spi_in = 5,
//        .spi_out = 6,
    };
    entry.host_in.address4.sin_family = AF_INET;
    inet_pton(AF_INET, "192.168.1.250", &entry.host_in.address4.sin_addr);
//    entry.host_out.address4.sin_family = AF_INET;
//    inet_pton(AF_INET, "192.168.1.200", &entry.host_out.address4.sin_addr);
    child_sa_get(in, &entry);

    child_sa_remove(in, &entry);
    child_sa_get(in, &entry);

    enumerator_t *enumerator;
    child_entry_t *key, *val;
    char buf[128];
    enumerator = in->create_enumerator(in);
    while(enumerator->enumerate(enumerator, &key, &val)){
        if (val){
            printf("enumerate unique_id: %d, spi_in: %d, spi_out: %d ",
                   val->unique_id, val->spi_in, val->spi_out
            );
            printf("host_in:%s ",
                   inet_ntop(AF_INET, &val->host_in.address4.sin_addr, buf, sizeof(buf))
            );
            printf("host_out:%s\n",
                   inet_ntop(AF_INET, &val->host_out.address4.sin_addr, buf, sizeof(buf))
            );

        }

        if (((private_enumerator_t *)enumerator)->index == 10){
            child_sa_get(in, key);
            in->remove_at(in, enumerator);
            child_sa_get(in, key);
        }
    }
    enumerator->destroy(enumerator);


    in->destroy_function(in, child_sa_destroy);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值