#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);