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