1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
#include "EXTERN.h"
#include "perl.h"
// It is crucial that XSUB.h comes after perl.h.
#include "XSUB.h"
#include <stdbool.h>
#include <stdint.h>
#include <uthash.h>
#ifdef INT64_T
#define HAVE_INT64
#endif
#ifdef __INT64
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#define HAVE_INT64
#endif
#ifdef INT64_DI
typedef int int64_t __attribute__((__mode__(DI)));
typedef unsigned int uint64_t __attribute__((__mode__(DTI)));
#define HAVE_INT64
#endif
#ifndef HAVE_INT64
#error "No int64 type define was passed to the compiler!"
#endif
#ifdef INT128_TI
typedef int int128_t __attribute__((__mode__(TI)));
typedef unsigned int uint128_t __attribute__((__mode__(TI)));
#define HAVE_INT128
#endif
#ifdef __INT128
typedef __int128 int128_t;
typedef unsigned __int128 uint128_t;
#define HAVE_INT128
#endif
#ifndef HAVE_INT128
#error "No int128 type define was passed to the compiler!"
#endif
/* perl memory allocator does not guarantee 16-byte alignment */
typedef int128_t int128_t_a8 __attribute__((aligned(8)));
typedef uint128_t uint128_t_a8 __attribute__((aligned(8)));
#define MATH_INT64_NATIVE_IF_AVAILABLE
#include "perl_math_int128.h"
#include "perl_math_int64.h"
typedef enum {
MMDBW_SUCCESS,
MMDBW_INSERT_INTO_ALIAS_NODE_ERROR,
MMDBW_INSERT_INVALID_RECORD_TYPE_ERROR,
MMDBW_FREED_ALIAS_NODE_ERROR,
MMDBW_FREED_FIXED_EMPTY_ERROR,
MMDBW_FREED_FIXED_NODE_ERROR,
MMDBW_ALIAS_OVERWRITE_ATTEMPT_ERROR,
MMDBW_FIXED_NODE_OVERWRITE_ATTEMPT_ERROR,
MMDBW_RESOLVING_IP_ERROR,
} MMDBW_status;
typedef enum {
MMDBW_RECORD_TYPE_EMPTY,
// Fixed empty records are like empty records in that they say there is no
// information. They are also immutable. And similar to alias records, you
// can't replace them, insert networks containing them, or insert networks
// belonging to them.
//
// We can't use EMPTY because they are not immutable. We can't use
// FIXED_NODE because they allow children (adding sub-networks). We can't
// use ALIAS as it has a special meaning, and we don't permit lookups to
// work (although that is only used in test code apparently). They also
// raise errors in some cases where FIXED_EMPTY currently does not.
MMDBW_RECORD_TYPE_FIXED_EMPTY,
MMDBW_RECORD_TYPE_DATA,
MMDBW_RECORD_TYPE_NODE,
// Fixed nodes are used for nodes that other nodes alias; they cannot be
// removed without corrupting the tree. Unlike FIXED_EMPTY, they can have
// children.
MMDBW_RECORD_TYPE_FIXED_NODE,
MMDBW_RECORD_TYPE_ALIAS,
} MMDBW_record_type;
typedef enum {
MMDBW_MERGE_STRATEGY_UNKNOWN,
MMDBW_MERGE_STRATEGY_NONE,
MMDBW_MERGE_STRATEGY_TOPLEVEL,
MMDBW_MERGE_STRATEGY_RECURSE,
MMDBW_MERGE_STRATEGY_ADD_ONLY_IF_PARENT_EXISTS
} MMDBW_merge_strategy;
typedef struct MMDBW_record_s {
union {
// Data records have a key into the tree's data table, a hash.
const char *key;
struct MMDBW_node_s *node;
} value;
MMDBW_record_type type;
} MMDBW_record_s;
typedef struct MMDBW_node_s {
MMDBW_record_s left_record;
MMDBW_record_s right_record;
uint32_t number;
} MMDBW_node_s;
typedef struct MMDBW_data_hash_s {
SV *data_sv;
const char *key;
uint32_t reference_count;
UT_hash_handle hh;
} MMDBW_data_hash_s;
typedef struct MMDBW_merge_cache_s {
const char *key;
const char *value;
UT_hash_handle hh;
} MMDBW_merge_cache_s;
typedef struct MMDBW_tree_s {
uint8_t ip_version;
uint8_t record_size;
MMDBW_merge_strategy merge_strategy;
MMDBW_data_hash_s *data_table;
MMDBW_merge_cache_s *merge_cache;
MMDBW_record_s root_record;
uint32_t node_count;
} MMDBW_tree_s;
typedef struct MMDBW_network_s {
const uint8_t *const bytes;
const uint8_t prefix_length;
} MMDBW_network_s;
typedef void(MMDBW_iterator_callback)(MMDBW_tree_s *tree,
MMDBW_node_s *node,
uint128_t network,
uint8_t depth,
void *args);
extern MMDBW_tree_s *new_tree(const uint8_t ip_version,
uint8_t record_size,
MMDBW_merge_strategy merge_strategy,
const bool alias_ipv6,
const bool remove_reserved_networks);
extern void insert_network(MMDBW_tree_s *tree,
const char *ipstr,
const uint8_t prefix_length,
SV *key_sv,
SV *data,
MMDBW_merge_strategy merge_strategy);
extern void insert_range(MMDBW_tree_s *tree,
const char *start_ipstr,
const char *end_ipstr,
SV *key_sv,
SV *data_sv,
MMDBW_merge_strategy merge_strategy);
extern void remove_network(MMDBW_tree_s *tree,
const char *ipstr,
const uint8_t prefix_length);
extern SV *merge_hashes_for_keys(MMDBW_tree_s *tree,
const char *const key_from,
const char *const key_into,
MMDBW_network_s *network,
MMDBW_merge_strategy merge_strategy);
extern SV *lookup_ip_address(MMDBW_tree_s *tree, const char *const ipstr);
extern MMDBW_node_s *new_node();
extern void assign_node_numbers(MMDBW_tree_s *tree);
extern void freeze_tree(MMDBW_tree_s *tree,
char *filename,
char *frozen_params,
size_t frozen_params_size);
extern MMDBW_tree_s *thaw_tree(char *filename,
uint32_t initial_offset,
uint8_t ip_version,
uint8_t record_size,
MMDBW_merge_strategy merge_strategy,
const bool alias_ipv6,
const bool remove_reserved_networks);
extern void write_search_tree(MMDBW_tree_s *tree,
SV *output,
SV *root_data_type,
SV *serializer);
extern uint32_t max_record_value(MMDBW_tree_s *tree);
extern void start_iteration(MMDBW_tree_s *tree,
bool depth_first,
void *args,
MMDBW_iterator_callback callback);
extern uint128_t
flip_network_bit(MMDBW_tree_s *tree, uint128_t network, uint8_t depth);
extern SV *data_for_key(MMDBW_tree_s *tree, const char *const key);
extern void free_tree(MMDBW_tree_s *tree);
extern void free_merge_cache(MMDBW_tree_s *tree);
|