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