diff --git a/cbp/ModMMDB.cbp b/cbp/ModMMDB.cbp
index e8c7cc5b..127c5ea0 100644
--- a/cbp/ModMMDB.cbp
+++ b/cbp/ModMMDB.cbp
@@ -410,8 +410,8 @@
-
+
@@ -421,6 +421,10 @@
+
+
+
+
@@ -445,7 +449,7 @@
-
+
@@ -456,6 +460,7 @@
+
diff --git a/config/common/maxminddb_config.h b/config/common/maxminddb_config.h
new file mode 100644
index 00000000..4404e776
--- /dev/null
+++ b/config/common/maxminddb_config.h
@@ -0,0 +1,14 @@
+#ifndef MAXMINDDB_CONFIG_H
+#define MAXMINDDB_CONFIG_H
+
+#ifndef MMDB_UINT128_USING_MODE
+/* Define as 1 if we we use unsigned int __atribute__ ((__mode__(TI))) for uint128 values */
+#define MMDB_UINT128_USING_MODE 1
+#endif
+
+#ifndef MMDB_UINT128_IS_BYTE_ARRAY
+/* Define as 1 if we don't have an unsigned __int128 type */
+#undef MMDB_UINT128_IS_BYTE_ARRAY
+#endif
+
+#endif /* MAXMINDDB_CONFIG_H */
diff --git a/config/mingw32/maxminddb_config.h b/config/mingw32/maxminddb_config.h
deleted file mode 100644
index 8330403b..00000000
--- a/config/mingw32/maxminddb_config.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/* include/maxminddb_config.h. Generated from maxminddb_config.h.in by configure. */
-#ifndef MAXMINDDB_CONFIG_H
-#define MAXMINDDB_CONFIG_H
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_ARPA_INET_H */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_ASSERT_H 1
-
-/* Define to 1 if the system has the type `boolean'. */
-/* #undef HAVE_BOOLEAN */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_DLFCN_H */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define to 1 if you have the `getpagesize' function. */
-#define HAVE_GETPAGESIZE 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_LIBGEN_H 1
-
-/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
- to 0 otherwise. */
-#define HAVE_MALLOC 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_MATH_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have a working `mmap' system call. */
-/* #undef HAVE_MMAP */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_NETDB_H */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_NETINET_IN_H */
-
-/* Has an open_memstream() function */
-/* #undef HAVE_OPEN_MEMSTREAM */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDARG_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDBOOL_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDIO_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_SYS_MMAN_H */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_SYS_PARAM_H 1
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_SYS_SOCKET_H */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_UNISTD_H 1
-
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
- */
-#define LT_OBJDIR ".libs/"
-
-/* Missing the unsigned __int128 type */
-#define MMDB_UINT128_IS_BYTE_ARRAY 1
-
-/* int128 types are available with __attribute__((mode(TI))) */
-/* #undef MMDB_UINT128_USING_MODE */
-
-/* Name of package */
-#define PACKAGE "libmaxminddb"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "support@maxmind.com"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "libmaxminddb"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libmaxminddb 1.2.1"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "libmaxminddb"
-
-/* Define to the home page for this package. */
-#define PACKAGE_URL ""
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.2.1"
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Version number of package */
-#define VERSION "1.2.1"
-
-/* Define for Solaris 2.5.1 so the uint32_t typedef from ,
- , or is not used. If the typedef were allowed, the
- #define below would cause a syntax error. */
-/* #undef _UINT32_T */
-
-/* Define for Solaris 2.5.1 so the uint64_t typedef from ,
- , or is not used. If the typedef were allowed, the
- #define below would cause a syntax error. */
-/* #undef _UINT64_T */
-
-/* Define for Solaris 2.5.1 so the uint8_t typedef from ,
- , or is not used. If the typedef were allowed, the
- #define below would cause a syntax error. */
-/* #undef _UINT8_T */
-
-/* Define to rpl_malloc if the replacement function should be used. */
-/* #undef malloc */
-
-/* Define to `long int' if does not define. */
-/* #undef off_t */
-
-/* Define to the equivalent of the C99 'restrict' keyword, or to
- nothing if this is not supported. Do not define if restrict is
- supported directly. */
-#define restrict __restrict
-/* Work around a bug in Sun C++: it does not support _Restrict or
- __restrict__, even though the corresponding Sun C compiler ends up with
- "#define restrict _Restrict" or "#define restrict __restrict__" in the
- previous line. Perhaps some future version of Sun C++ will work with
- restrict; if so, hopefully it defines __RESTRICT like Sun C does. */
-#if defined __SUNPRO_CC && !defined __RESTRICT
-# define _Restrict
-# define __restrict__
-#endif
-
-/* Define to `unsigned int' if does not define. */
-/* #undef size_t */
-
-/* Define to `int' if does not define. */
-/* #undef ssize_t */
-
-/* Define to the type of an unsigned integer type of width exactly 32 bits if
- such a type exists and the standard includes do not define it. */
-/* #undef uint32_t */
-
-/* Define to the type of an unsigned integer type of width exactly 64 bits if
- such a type exists and the standard includes do not define it. */
-/* #undef uint64_t */
-
-/* Define to the type of an unsigned integer type of width exactly 8 bits if
- such a type exists and the standard includes do not define it. */
-/* #undef uint8_t */
-
-#ifndef MMDB_UINT128_USING_MODE
-/* Define as 1 if we we use unsigned int __atribute__ ((__mode__(TI))) for uint128 values */
-#define MMDB_UINT128_USING_MODE 0
-#endif
-
-#ifndef MMDB_UINT128_IS_BYTE_ARRAY
-/* Define as 1 if we don't have an unsigned __int128 type */
-#define MMDB_UINT128_IS_BYTE_ARRAY 0
-#endif
-
-#endif /* MAXMINDDB_CONFIG_H */
diff --git a/config/mingw64/maxminddb_config.h b/config/mingw64/maxminddb_config.h
deleted file mode 100644
index 40753cb0..00000000
--- a/config/mingw64/maxminddb_config.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/* include/maxminddb_config.h. Generated from maxminddb_config.h.in by configure. */
-#ifndef MAXMINDDB_CONFIG_H
-#define MAXMINDDB_CONFIG_H
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_ARPA_INET_H */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_ASSERT_H 1
-
-/* Define to 1 if the system has the type `boolean'. */
-/* #undef HAVE_BOOLEAN */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_DLFCN_H */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define to 1 if you have the `getpagesize' function. */
-#define HAVE_GETPAGESIZE 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_LIBGEN_H 1
-
-/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
- to 0 otherwise. */
-#define HAVE_MALLOC 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_MATH_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have a working `mmap' system call. */
-/* #undef HAVE_MMAP */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_NETDB_H */
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_NETINET_IN_H */
-
-/* Has an open_memstream() function */
-/* #undef HAVE_OPEN_MEMSTREAM */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDARG_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDBOOL_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDINT_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDIO_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_SYS_MMAN_H */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_SYS_PARAM_H 1
-
-/* Define to 1 if you have the header file. */
-/* #undef HAVE_SYS_SOCKET_H */
-
-/* Define to 1 if you have the header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the header file. */
-#define HAVE_UNISTD_H 1
-
-/* Define to the sub-directory in which libtool stores uninstalled libraries.
- */
-#define LT_OBJDIR ".libs/"
-
-/* Missing the unsigned __int128 type */
-#define MMDB_UINT128_IS_BYTE_ARRAY 0
-
-/* int128 types are available with __attribute__((mode(TI))) */
-/* #undef MMDB_UINT128_USING_MODE */
-
-/* Name of package */
-#define PACKAGE "libmaxminddb"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "support@maxmind.com"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "libmaxminddb"
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "libmaxminddb 1.2.1"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "libmaxminddb"
-
-/* Define to the home page for this package. */
-#define PACKAGE_URL ""
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.2.1"
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Version number of package */
-#define VERSION "1.2.1"
-
-/* Define for Solaris 2.5.1 so the uint32_t typedef from ,
- , or is not used. If the typedef were allowed, the
- #define below would cause a syntax error. */
-/* #undef _UINT32_T */
-
-/* Define for Solaris 2.5.1 so the uint64_t typedef from ,
- , or is not used. If the typedef were allowed, the
- #define below would cause a syntax error. */
-/* #undef _UINT64_T */
-
-/* Define for Solaris 2.5.1 so the uint8_t typedef from ,
- , or is not used. If the typedef were allowed, the
- #define below would cause a syntax error. */
-/* #undef _UINT8_T */
-
-/* Define to rpl_malloc if the replacement function should be used. */
-/* #undef malloc */
-
-/* Define to `long int' if does not define. */
-/* #undef off_t */
-
-/* Define to the equivalent of the C99 'restrict' keyword, or to
- nothing if this is not supported. Do not define if restrict is
- supported directly. */
-#define restrict __restrict
-/* Work around a bug in Sun C++: it does not support _Restrict or
- __restrict__, even though the corresponding Sun C compiler ends up with
- "#define restrict _Restrict" or "#define restrict __restrict__" in the
- previous line. Perhaps some future version of Sun C++ will work with
- restrict; if so, hopefully it defines __RESTRICT like Sun C does. */
-#if defined __SUNPRO_CC && !defined __RESTRICT
-# define _Restrict
-# define __restrict__
-#endif
-
-/* Define to `unsigned int' if does not define. */
-/* #undef size_t */
-
-/* Define to `int' if does not define. */
-/* #undef ssize_t */
-
-/* Define to the type of an unsigned integer type of width exactly 32 bits if
- such a type exists and the standard includes do not define it. */
-/* #undef uint32_t */
-
-/* Define to the type of an unsigned integer type of width exactly 64 bits if
- such a type exists and the standard includes do not define it. */
-/* #undef uint64_t */
-
-/* Define to the type of an unsigned integer type of width exactly 8 bits if
- such a type exists and the standard includes do not define it. */
-/* #undef uint8_t */
-
-#ifndef MMDB_UINT128_USING_MODE
-/* Define as 1 if we we use unsigned int __atribute__ ((__mode__(TI))) for uint128 values */
-#define MMDB_UINT128_USING_MODE 0
-#endif
-
-#ifndef MMDB_UINT128_IS_BYTE_ARRAY
-/* Define as 1 if we don't have an unsigned __int128 type */
-#define MMDB_UINT128_IS_BYTE_ARRAY 0
-#endif
-
-#endif /* MAXMINDDB_CONFIG_H */
diff --git a/external/MaxmindDB/data-pool.c b/external/MaxmindDB/data-pool.c
new file mode 100644
index 00000000..48521b64
--- /dev/null
+++ b/external/MaxmindDB/data-pool.c
@@ -0,0 +1,180 @@
+#include "data-pool.h"
+#include "maxminddb.h"
+
+#include
+#include
+#include
+
+static bool can_multiply(size_t const, size_t const, size_t const);
+
+// Allocate an MMDB_data_pool_s. It initially has space for size
+// MMDB_entry_data_list_s structs.
+MMDB_data_pool_s *data_pool_new(size_t const size)
+{
+ MMDB_data_pool_s *const pool = calloc(1, sizeof(MMDB_data_pool_s));
+ if (!pool) {
+ return NULL;
+ }
+
+ if (size == 0 ||
+ !can_multiply(SIZE_MAX, size, sizeof(MMDB_entry_data_list_s))) {
+ data_pool_destroy(pool);
+ return NULL;
+ }
+ pool->size = size;
+ pool->blocks[0] = calloc(pool->size, sizeof(MMDB_entry_data_list_s));
+ if (!pool->blocks[0]) {
+ data_pool_destroy(pool);
+ return NULL;
+ }
+ pool->blocks[0]->pool = pool;
+
+ pool->sizes[0] = size;
+
+ pool->block = pool->blocks[0];
+
+ return pool;
+}
+
+// Determine if we can multiply m*n. We can do this if the result will be below
+// the given max. max will typically be SIZE_MAX.
+//
+// We want to know if we'll wrap around.
+static bool can_multiply(size_t const max, size_t const m, size_t const n)
+{
+ if (m == 0) {
+ return false;
+ }
+
+ return n <= max / m;
+}
+
+// Clean up the data pool.
+void data_pool_destroy(MMDB_data_pool_s *const pool)
+{
+ if (!pool) {
+ return;
+ }
+
+ for (size_t i = 0; i <= pool->index; i++) {
+ free(pool->blocks[i]);
+ }
+
+ free(pool);
+}
+
+// Claim a new struct from the pool. Doing this may cause the pool's size to
+// grow.
+MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const pool)
+{
+ if (!pool) {
+ return NULL;
+ }
+
+ if (pool->used < pool->size) {
+ MMDB_entry_data_list_s *const element = pool->block + pool->used;
+ pool->used++;
+ return element;
+ }
+
+ // Take it from a new block of memory.
+
+ size_t const new_index = pool->index + 1;
+ if (new_index == DATA_POOL_NUM_BLOCKS) {
+ // See the comment about not growing this on DATA_POOL_NUM_BLOCKS.
+ return NULL;
+ }
+
+ if (!can_multiply(SIZE_MAX, pool->size, 2)) {
+ return NULL;
+ }
+ size_t const new_size = pool->size * 2;
+
+ if (!can_multiply(SIZE_MAX, new_size, sizeof(MMDB_entry_data_list_s))) {
+ return NULL;
+ }
+ pool->blocks[new_index] = calloc(new_size, sizeof(MMDB_entry_data_list_s));
+ if (!pool->blocks[new_index]) {
+ return NULL;
+ }
+
+ // We don't need to set this, but it's useful for introspection in tests.
+ pool->blocks[new_index]->pool = pool;
+
+ pool->index = new_index;
+ pool->block = pool->blocks[pool->index];
+
+ pool->size = new_size;
+ pool->sizes[pool->index] = pool->size;
+
+ MMDB_entry_data_list_s *const element = pool->block;
+ pool->used = 1;
+ return element;
+}
+
+// Turn the structs in the array-like pool into a linked list.
+//
+// Before calling this function, the list isn't linked up.
+MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const pool)
+{
+ if (!pool) {
+ return NULL;
+ }
+
+ if (pool->index == 0 && pool->used == 0) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i <= pool->index; i++) {
+ MMDB_entry_data_list_s *const block = pool->blocks[i];
+
+ size_t size = pool->sizes[i];
+ if (i == pool->index) {
+ size = pool->used;
+ }
+
+ for (size_t j = 0; j < size - 1; j++) {
+ MMDB_entry_data_list_s *const cur = block + j;
+ cur->next = block + j + 1;
+ }
+
+ if (i < pool->index) {
+ MMDB_entry_data_list_s *const last = block + size - 1;
+ last->next = pool->blocks[i + 1];
+ }
+ }
+
+ return pool->blocks[0];
+}
+
+#ifdef TEST_DATA_POOL
+
+#include
+#include
+
+static void test_can_multiply(void);
+
+int main(void)
+{
+ plan(NO_PLAN);
+ test_can_multiply();
+ done_testing();
+}
+
+static void test_can_multiply(void)
+{
+ {
+ ok(can_multiply(SIZE_MAX, 1, SIZE_MAX), "1*SIZE_MAX is ok");
+ }
+
+ {
+ ok(!can_multiply(SIZE_MAX, 2, SIZE_MAX), "2*SIZE_MAX is not ok");
+ }
+
+ {
+ ok(can_multiply(SIZE_MAX, 10240, sizeof(MMDB_entry_data_list_s)),
+ "1024 entry_data_list_s's are okay");
+ }
+}
+
+#endif
diff --git a/external/MaxmindDB/data-pool.h b/external/MaxmindDB/data-pool.h
new file mode 100644
index 00000000..25d09923
--- /dev/null
+++ b/external/MaxmindDB/data-pool.h
@@ -0,0 +1,52 @@
+#ifndef DATA_POOL_H
+#define DATA_POOL_H
+
+#include "maxminddb.h"
+
+#include
+#include
+
+// This should be large enough that we never need to grow the array of pointers
+// to blocks. 32 is enough. Even starting out of with size 1 (1 struct), the
+// 32nd element alone will provide 2**32 structs as we exponentially increase
+// the number in each block. Being confident that we do not have to grow the
+// array lets us avoid writing code to do that. That code would be risky as it
+// would rarely be hit and likely not be well tested.
+#define DATA_POOL_NUM_BLOCKS 32
+
+// A pool of memory for MMDB_entry_data_list_s structs. This is so we can
+// allocate multiple up front rather than one at a time for performance
+// reasons.
+//
+// The order you add elements to it (by calling data_pool_alloc()) ends up as
+// the order of the list.
+//
+// The memory only grows. There is no support for releasing an element you take
+// back to the pool.
+typedef struct MMDB_data_pool_s {
+ // Index of the current block we're allocating out of.
+ size_t index;
+
+ // The size of the current block, counting by structs.
+ size_t size;
+
+ // How many used in the current block, counting by structs.
+ size_t used;
+
+ // The current block we're allocating out of.
+ MMDB_entry_data_list_s *block;
+
+ // The size of each block.
+ size_t sizes[DATA_POOL_NUM_BLOCKS];
+
+ // An array of pointers to blocks of memory holding space for list
+ // elements.
+ MMDB_entry_data_list_s *blocks[DATA_POOL_NUM_BLOCKS];
+} MMDB_data_pool_s;
+
+MMDB_data_pool_s *data_pool_new(size_t const);
+void data_pool_destroy(MMDB_data_pool_s *const);
+MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const);
+MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const);
+
+#endif
diff --git a/external/MaxmindDB/maxminddb.c b/external/MaxmindDB/maxminddb.c
index 8dbe4a74..f1d51746 100644
--- a/external/MaxmindDB/maxminddb.c
+++ b/external/MaxmindDB/maxminddb.c
@@ -1,6 +1,7 @@
#if HAVE_CONFIG_H
#include
#endif
+#include "data-pool.h"
#include "maxminddb.h"
#include "maxminddb-compat-util.h"
#include
@@ -13,6 +14,9 @@
#include
#ifdef _WIN32
+#ifndef UNICODE
+#define UNICODE
+#endif
#include
#include
#else
@@ -26,8 +30,6 @@
#ifdef MMDB_DEBUG
#define LOCAL
-#define NO_PROTO
-#define DEBUG_FUNC
#define DEBUG_MSG(msg) fprintf(stderr, msg "\n")
#define DEBUG_MSGF(fmt, ...) fprintf(stderr, fmt "\n", __VA_ARGS__)
#define DEBUG_BINARY(fmt, byte) \
@@ -43,7 +45,6 @@
#define DEBUG_NL fprintf(stderr, "\n")
#else
#define LOCAL static
-#define NO_PROTO static
#define DEBUG_MSG(...)
#define DEBUG_MSGF(...)
#define DEBUG_BINARY(...)
@@ -51,7 +52,7 @@
#endif
#ifdef MMDB_DEBUG
-DEBUG_FUNC char *byte_to_binary(uint8_t byte)
+char *byte_to_binary(uint8_t byte)
{
char *bits = malloc(sizeof(char) * 9);
if (NULL == bits) {
@@ -66,7 +67,7 @@ DEBUG_FUNC char *byte_to_binary(uint8_t byte)
return bits;
}
-DEBUG_FUNC char *type_num_to_name(uint8_t num)
+char *type_num_to_name(uint8_t num)
{
switch (num) {
case 0:
@@ -130,13 +131,14 @@ typedef struct record_info_s {
/* This is 128kb */
#define METADATA_BLOCK_MAX_SIZE 131072
-/* *INDENT-OFF* */
-/* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */
+// 64 leads us to allocating 4 KiB on a 64bit system.
+#define MMDB_POOL_INIT_SIZE 64
+
LOCAL int map_file(MMDB_s *const mmdb);
LOCAL const uint8_t *find_metadata(const uint8_t *file_content,
ssize_t file_size, uint32_t *metadata_size);
LOCAL int read_metadata(MMDB_s *mmdb);
-LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb);
+LOCAL MMDB_s make_fake_metadata_db(const MMDB_s *const mmdb);
LOCAL int value_for_key_as_uint16(MMDB_entry_s *start, char *key,
uint16_t *value);
LOCAL int value_for_key_as_uint32(MMDB_entry_s *start, char *key,
@@ -150,34 +152,38 @@ LOCAL int populate_languages_metadata(MMDB_s *mmdb, MMDB_s *metadata_db,
LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db,
MMDB_entry_s *metadata_start);
LOCAL int resolve_any_address(const char *ipstr, struct addrinfo **addresses);
-LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address,
+LOCAL int find_address_in_search_tree(const MMDB_s *const mmdb,
+ uint8_t *address,
sa_family_t address_family,
MMDB_lookup_result_s *result);
-LOCAL record_info_s record_info_for_database(MMDB_s *mmdb);
-LOCAL int find_ipv4_start_node(MMDB_s *mmdb);
-LOCAL uint8_t maybe_populate_result(MMDB_s *mmdb, uint32_t record,
+LOCAL record_info_s record_info_for_database(const MMDB_s *const mmdb);
+LOCAL int find_ipv4_start_node(MMDB_s *const mmdb);
+LOCAL uint8_t maybe_populate_result(const MMDB_s *const mmdb, uint32_t record,
uint16_t netmask,
MMDB_lookup_result_s *result);
-LOCAL uint8_t record_type(MMDB_s *const mmdb, uint64_t record);
+LOCAL uint8_t record_type(const MMDB_s *const mmdb, uint64_t record);
LOCAL uint32_t get_left_28_bit_record(const uint8_t *record);
LOCAL uint32_t get_right_28_bit_record(const uint8_t *record);
-LOCAL uint32_t data_section_offset_for_record(MMDB_s *const mmdb,
+LOCAL uint32_t data_section_offset_for_record(const MMDB_s *const mmdb,
uint64_t record);
LOCAL int path_length(va_list va_path);
-LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb,
+LOCAL int lookup_path_in_array(const char *path_elem, const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data);
-LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb,
+LOCAL int lookup_path_in_map(const char *path_elem, const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data);
-LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data);
-LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset,
+LOCAL int skip_map_or_array(const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data);
-LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset,
+LOCAL int decode_one_follow(const MMDB_s *const mmdb, uint32_t offset,
+ MMDB_entry_data_s *entry_data);
+LOCAL int decode_one(const MMDB_s *const mmdb, uint32_t offset,
MMDB_entry_data_s *entry_data);
LOCAL int get_ext_type(int raw_ext_type);
LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr,
int ptr_size);
-LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
+LOCAL int get_entry_data_list(const MMDB_s *const mmdb,
+ uint32_t offset,
MMDB_entry_data_list_s *const entry_data_list,
+ MMDB_data_pool_s *const pool,
int depth);
LOCAL float get_ieee754_float(const uint8_t *restrict p);
LOCAL double get_ieee754_double(const uint8_t *restrict p);
@@ -186,7 +192,6 @@ LOCAL uint32_t get_uint24(const uint8_t *p);
LOCAL uint32_t get_uint16(const uint8_t *p);
LOCAL uint64_t get_uintX(const uint8_t *p, int length);
LOCAL int32_t get_sintX(const uint8_t *p, int length);
-LOCAL MMDB_entry_data_list_s *new_entry_data_list(void);
LOCAL void free_mmdb_struct(MMDB_s *const mmdb);
LOCAL void free_languages_metadata(MMDB_s *mmdb);
LOCAL void free_descriptions_metadata(MMDB_s *mmdb);
@@ -195,8 +200,6 @@ LOCAL MMDB_entry_data_list_s *dump_entry_data_list(
int *status);
LOCAL void print_indentation(FILE *stream, int i);
LOCAL char *bytes_to_hex(uint8_t *bytes, uint32_t size);
-/* --prototypes end - don't remove this comment-- */
-/* *INDENT-ON* */
#define CHECKED_DECODE_ONE(mmdb, offset, entry_data) \
do { \
@@ -228,6 +231,7 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
mmdb->data_section = NULL;
mmdb->metadata.database_type = NULL;
mmdb->metadata.languages.count = 0;
+ mmdb->metadata.languages.names = NULL;
mmdb->metadata.description.count = 0;
mmdb->filename = mmdb_strdup(filename);
@@ -241,7 +245,7 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
}
mmdb->flags = flags;
- if (MMDB_SUCCESS != (status = map_file(mmdb)) ) {
+ if (MMDB_SUCCESS != (status = map_file(mmdb))) {
goto cleanup;
}
@@ -297,6 +301,15 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
mmdb->ipv4_start_node.node_value = 0;
mmdb->ipv4_start_node.netmask = 0;
+ // We do this immediately as otherwise there is a race to set
+ // ipv4_start_node.node_value and ipv4_start_node.netmask.
+ if (mmdb->metadata.ip_version == 6) {
+ status = find_ipv4_start_node(mmdb);
+ if (status != MMDB_SUCCESS) {
+ goto cleanup;
+ }
+ }
+
cleanup:
if (MMDB_SUCCESS != status) {
int saved_errno = errno;
@@ -308,13 +321,33 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
#ifdef _WIN32
+LOCAL LPWSTR utf8_to_utf16(const char *utf8_str)
+{
+ int wide_chars = MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, NULL, 0);
+ wchar_t *utf16_str = (wchar_t *)malloc(wide_chars * sizeof(wchar_t));
+
+ if (MultiByteToWideChar(CP_UTF8, 0, utf8_str, -1, utf16_str,
+ wide_chars) < 1) {
+ free(utf16_str);
+ return NULL;
+ }
+
+ return utf16_str;
+}
+
LOCAL int map_file(MMDB_s *const mmdb)
{
DWORD size;
int status = MMDB_SUCCESS;
HANDLE mmh = NULL;
- HANDLE fd = CreateFileA(mmdb->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ HANDLE fd = INVALID_HANDLE_VALUE;
+ LPWSTR utf16_filename = utf8_to_utf16(mmdb->filename);
+ if (!utf16_filename) {
+ status = MMDB_FILE_OPEN_ERROR;
+ goto cleanup;
+ }
+ fd = CreateFile(utf16_filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fd == INVALID_HANDLE_VALUE) {
status = MMDB_FILE_OPEN_ERROR;
goto cleanup;
@@ -324,7 +357,7 @@ LOCAL int map_file(MMDB_s *const mmdb)
status = MMDB_FILE_OPEN_ERROR;
goto cleanup;
}
- mmh = CreateFileMappingA(fd, NULL, PAGE_READONLY, 0, size, NULL);
+ mmh = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, size, NULL);
/* Microsoft documentation for CreateFileMapping indicates this returns
NULL not INVALID_HANDLE_VALUE on error */
if (NULL == mmh) {
@@ -350,18 +383,23 @@ LOCAL int map_file(MMDB_s *const mmdb)
CloseHandle(mmh);
}
errno = saved_errno;
+ free(utf16_filename);
return status;
}
-#else
+#else // _WIN32
LOCAL int map_file(MMDB_s *const mmdb)
{
ssize_t size;
int status = MMDB_SUCCESS;
- int fd = open(mmdb->filename, O_RDONLY);
+ int flags = O_RDONLY;
+#ifdef O_CLOEXEC
+ flags |= O_CLOEXEC;
+#endif
+ int fd = open(mmdb->filename, flags);
struct stat s;
if (fd < 0 || fstat(fd, &s)) {
status = MMDB_FILE_OPEN_ERROR;
@@ -398,7 +436,7 @@ LOCAL int map_file(MMDB_s *const mmdb)
return status;
}
-#endif
+#endif // _WIN32
LOCAL const uint8_t *find_metadata(const uint8_t *file_content,
ssize_t file_size, uint32_t *metadata_size)
@@ -548,7 +586,7 @@ LOCAL int read_metadata(MMDB_s *mmdb)
return MMDB_SUCCESS;
}
-LOCAL MMDB_s make_fake_metadata_db(MMDB_s *mmdb)
+LOCAL MMDB_s make_fake_metadata_db(const MMDB_s *const mmdb)
{
MMDB_s fake_metadata_db = {
.data_section = mmdb->metadata_section,
@@ -796,7 +834,7 @@ LOCAL int populate_description_metadata(MMDB_s *mmdb, MMDB_s *metadata_db,
return status;
}
-MMDB_lookup_result_s MMDB_lookup_string(MMDB_s *const mmdb,
+MMDB_lookup_result_s MMDB_lookup_string(const MMDB_s *const mmdb,
const char *const ipstr,
int *const gai_error,
int *const mmdb_error)
@@ -842,7 +880,7 @@ LOCAL int resolve_any_address(const char *ipstr, struct addrinfo **addresses)
}
MMDB_lookup_result_s MMDB_lookup_sockaddr(
- MMDB_s *const mmdb,
+ const MMDB_s *const mmdb,
const struct sockaddr *const sockaddr,
int *const mmdb_error)
{
@@ -882,7 +920,8 @@ MMDB_lookup_result_s MMDB_lookup_sockaddr(
return result;
}
-LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address,
+LOCAL int find_address_in_search_tree(const MMDB_s *const mmdb,
+ uint8_t *address,
sa_family_t address_family,
MMDB_lookup_result_s *result)
{
@@ -899,10 +938,7 @@ LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address,
uint16_t start_bit = max_depth0;
if (mmdb->metadata.ip_version == 6 && address_family == AF_INET) {
- int mmdb_error = find_ipv4_start_node(mmdb);
- if (MMDB_SUCCESS != mmdb_error) {
- return mmdb_error;
- }
+ /* ipv4 start node values set at open */
DEBUG_MSGF("IPv4 start node is %u (netmask %u)",
mmdb->ipv4_start_node.node_value,
mmdb->ipv4_start_node.netmask);
@@ -966,7 +1002,7 @@ LOCAL int find_address_in_search_tree(MMDB_s *mmdb, uint8_t *address,
return MMDB_CORRUPT_SEARCH_TREE_ERROR;
}
-LOCAL record_info_s record_info_for_database(MMDB_s *mmdb)
+LOCAL record_info_s record_info_for_database(const MMDB_s *const mmdb)
{
record_info_s record_info = {
.record_length = mmdb->full_record_byte_size,
@@ -992,7 +1028,7 @@ LOCAL record_info_s record_info_for_database(MMDB_s *mmdb)
return record_info;
}
-LOCAL int find_ipv4_start_node(MMDB_s *mmdb)
+LOCAL int find_ipv4_start_node(MMDB_s *const mmdb)
{
/* In a pathological case of a database with a single node search tree,
* this check will be true even after we've found the IPv4 start node, but
@@ -1026,7 +1062,7 @@ LOCAL int find_ipv4_start_node(MMDB_s *mmdb)
return MMDB_SUCCESS;
}
-LOCAL uint8_t maybe_populate_result(MMDB_s *mmdb, uint32_t record,
+LOCAL uint8_t maybe_populate_result(const MMDB_s *const mmdb, uint32_t record,
uint16_t netmask,
MMDB_lookup_result_s *result)
{
@@ -1048,7 +1084,7 @@ LOCAL uint8_t maybe_populate_result(MMDB_s *mmdb, uint32_t record,
return type;
}
-LOCAL uint8_t record_type(MMDB_s *const mmdb, uint64_t record)
+LOCAL uint8_t record_type(const MMDB_s *const mmdb, uint64_t record)
{
uint32_t node_count = mmdb->metadata.node_count;
@@ -1088,7 +1124,7 @@ LOCAL uint32_t get_right_28_bit_record(const uint8_t *record)
return value & 0xfffffff;
}
-int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number,
+int MMDB_read_node(const MMDB_s *const mmdb, uint32_t node_number,
MMDB_search_node_s *const node)
{
record_info_s record_info = record_info_for_database(mmdb);
@@ -1125,7 +1161,7 @@ int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number,
return MMDB_SUCCESS;
}
-LOCAL uint32_t data_section_offset_for_record(MMDB_s *const mmdb,
+LOCAL uint32_t data_section_offset_for_record(const MMDB_s *const mmdb,
uint64_t record)
{
return (uint32_t)record - mmdb->metadata.node_count -
@@ -1192,7 +1228,7 @@ int MMDB_aget_value(MMDB_entry_s *const start,
MMDB_entry_data_s *const entry_data,
const char *const *const path)
{
- MMDB_s *mmdb = start->mmdb;
+ const MMDB_s *const mmdb = start->mmdb;
uint32_t offset = start->offset;
memset(entry_data, 0, sizeof(MMDB_entry_data_s));
@@ -1245,7 +1281,8 @@ int MMDB_aget_value(MMDB_entry_s *const start,
return MMDB_SUCCESS;
}
-LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb,
+LOCAL int lookup_path_in_array(const char *path_elem,
+ const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data)
{
uint32_t size = entry_data->data_size;
@@ -1254,12 +1291,20 @@ LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb,
int saved_errno = errno;
errno = 0;
int array_index = strtol(path_elem, &first_invalid, 10);
- if (array_index < 0 || ERANGE == errno) {
+ if (ERANGE == errno) {
errno = saved_errno;
return MMDB_INVALID_LOOKUP_PATH_ERROR;
}
errno = saved_errno;
+ if (array_index < 0) {
+ array_index += size;
+
+ if (array_index < 0) {
+ return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
+ }
+ }
+
if (*first_invalid || (uint32_t)array_index >= size) {
return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
}
@@ -1281,7 +1326,8 @@ LOCAL int lookup_path_in_array(const char *path_elem, MMDB_s *mmdb,
return MMDB_SUCCESS;
}
-LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb,
+LOCAL int lookup_path_in_map(const char *path_elem,
+ const MMDB_s *const mmdb,
MMDB_entry_data_s *entry_data)
{
uint32_t size = entry_data->data_size;
@@ -1322,7 +1368,8 @@ LOCAL int lookup_path_in_map(const char *path_elem, MMDB_s *mmdb,
return MMDB_LOOKUP_PATH_DOES_NOT_MATCH_DATA_ERROR;
}
-LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data)
+LOCAL int skip_map_or_array(const MMDB_s *const mmdb,
+ MMDB_entry_data_s *entry_data)
{
if (entry_data->type == MMDB_DATA_TYPE_MAP) {
uint32_t size = entry_data->data_size;
@@ -1348,7 +1395,7 @@ LOCAL int skip_map_or_array(MMDB_s *mmdb, MMDB_entry_data_s *entry_data)
return MMDB_SUCCESS;
}
-LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset,
+LOCAL int decode_one_follow(const MMDB_s *const mmdb, uint32_t offset,
MMDB_entry_data_s *entry_data)
{
CHECKED_DECODE_ONE(mmdb, offset, entry_data);
@@ -1378,7 +1425,7 @@ LOCAL int decode_one_follow(MMDB_s *mmdb, uint32_t offset,
}
#if !MMDB_UINT128_IS_BYTE_ARRAY
-NO_PROTO mmdb_uint128_t get_uint128(const uint8_t *p, int length)
+LOCAL mmdb_uint128_t get_uint128(const uint8_t *p, int length)
{
mmdb_uint128_t value = 0;
while (length-- > 0) {
@@ -1389,7 +1436,7 @@ NO_PROTO mmdb_uint128_t get_uint128(const uint8_t *p, int length)
}
#endif
-LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset,
+LOCAL int decode_one(const MMDB_s *const mmdb, uint32_t offset,
MMDB_entry_data_s *entry_data)
{
const uint8_t *mem = mmdb->data_section;
@@ -1619,7 +1666,7 @@ LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr,
}
int MMDB_get_metadata_as_entry_data_list(
- MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list)
+ const MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list)
{
MMDB_s metadata_db = make_fake_metadata_db(mmdb);
@@ -1634,15 +1681,33 @@ int MMDB_get_metadata_as_entry_data_list(
int MMDB_get_entry_data_list(
MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list)
{
- *entry_data_list = new_entry_data_list();
- if (NULL == *entry_data_list) {
+ MMDB_data_pool_s *const pool = data_pool_new(MMDB_POOL_INIT_SIZE);
+ if (!pool) {
return MMDB_OUT_OF_MEMORY_ERROR;
}
- return get_entry_data_list(start->mmdb, start->offset, *entry_data_list, 0);
+
+ MMDB_entry_data_list_s *const list = data_pool_alloc(pool);
+ if (!list) {
+ data_pool_destroy(pool);
+ return MMDB_OUT_OF_MEMORY_ERROR;
+ }
+
+ int const status = get_entry_data_list(start->mmdb, start->offset, list,
+ pool, 0);
+
+ *entry_data_list = data_pool_to_list(pool);
+ if (!*entry_data_list) {
+ data_pool_destroy(pool);
+ return MMDB_OUT_OF_MEMORY_ERROR;
+ }
+
+ return status;
}
-LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
+LOCAL int get_entry_data_list(const MMDB_s *const mmdb,
+ uint32_t offset,
MMDB_entry_data_list_s *const entry_data_list,
+ MMDB_data_pool_s *const pool,
int depth)
{
if (depth >= MAXIMUM_DATA_STRUCTURE_DEPTH) {
@@ -1672,7 +1737,7 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
int status =
get_entry_data_list(mmdb, last_offset, entry_data_list,
- depth);
+ pool, depth);
if (MMDB_SUCCESS != status) {
DEBUG_MSG("get_entry_data_list on pointer failed.");
return status;
@@ -1685,26 +1750,22 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
{
uint32_t array_size = entry_data_list->entry_data.data_size;
uint32_t array_offset = entry_data_list->entry_data.offset_to_next;
- MMDB_entry_data_list_s *previous = entry_data_list;
while (array_size-- > 0) {
- MMDB_entry_data_list_s *entry_data_list_to = previous->next =
- new_entry_data_list();
- if (NULL == entry_data_list_to) {
+ MMDB_entry_data_list_s *entry_data_list_to =
+ data_pool_alloc(pool);
+ if (!entry_data_list_to) {
return MMDB_OUT_OF_MEMORY_ERROR;
}
int status =
get_entry_data_list(mmdb, array_offset, entry_data_list_to,
- depth);
+ pool, depth);
if (MMDB_SUCCESS != status) {
DEBUG_MSG("get_entry_data_list on array element failed.");
return status;
}
array_offset = entry_data_list_to->entry_data.offset_to_next;
- while (previous->next) {
- previous = previous->next;
- }
}
entry_data_list->entry_data.offset_to_next = array_offset;
@@ -1715,45 +1776,33 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
uint32_t size = entry_data_list->entry_data.data_size;
offset = entry_data_list->entry_data.offset_to_next;
- MMDB_entry_data_list_s *previous = entry_data_list;
while (size-- > 0) {
- MMDB_entry_data_list_s *entry_data_list_to = previous->next =
- new_entry_data_list();
- if (NULL == entry_data_list_to) {
+ MMDB_entry_data_list_s *list_key = data_pool_alloc(pool);
+ if (!list_key) {
return MMDB_OUT_OF_MEMORY_ERROR;
}
int status =
- get_entry_data_list(mmdb, offset, entry_data_list_to,
- depth);
+ get_entry_data_list(mmdb, offset, list_key, pool, depth);
if (MMDB_SUCCESS != status) {
DEBUG_MSG("get_entry_data_list on map key failed.");
return status;
}
- while (previous->next) {
- previous = previous->next;
- }
+ offset = list_key->entry_data.offset_to_next;
- offset = entry_data_list_to->entry_data.offset_to_next;
- entry_data_list_to = previous->next =
- new_entry_data_list();
-
- if (NULL == entry_data_list_to) {
+ MMDB_entry_data_list_s *list_value = data_pool_alloc(pool);
+ if (!list_value) {
return MMDB_OUT_OF_MEMORY_ERROR;
}
- status = get_entry_data_list(mmdb, offset, entry_data_list_to,
+ status = get_entry_data_list(mmdb, offset, list_value, pool,
depth);
if (MMDB_SUCCESS != status) {
DEBUG_MSG("get_entry_data_list on map element failed.");
return status;
}
-
- while (previous->next) {
- previous = previous->next;
- }
- offset = entry_data_list_to->entry_data.offset_to_next;
+ offset = list_value->entry_data.offset_to_next;
}
entry_data_list->entry_data.offset_to_next = offset;
}
@@ -1832,22 +1881,12 @@ LOCAL int32_t get_sintX(const uint8_t *p, int length)
return (int32_t)get_uintX(p, length);
}
-LOCAL MMDB_entry_data_list_s *new_entry_data_list(void)
-{
- /* We need calloc here in order to ensure that the ->next pointer in the
- * struct doesn't point to some random address. */
- return calloc(1, sizeof(MMDB_entry_data_list_s));
-}
-
void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list)
{
if (entry_data_list == NULL) {
return;
}
- if (entry_data_list->next) {
- MMDB_free_entry_data_list(entry_data_list->next);
- }
- free(entry_data_list);
+ data_pool_destroy(entry_data_list->pool);
}
void MMDB_close(MMDB_s *const mmdb)
@@ -1885,7 +1924,7 @@ LOCAL void free_mmdb_struct(MMDB_s *const mmdb)
LOCAL void free_languages_metadata(MMDB_s *mmdb)
{
- if (!mmdb->metadata.languages.count) {
+ if (!mmdb->metadata.languages.names) {
return;
}
diff --git a/include/maxminddb.h b/include/maxminddb.h
index a6f0e93c..6e6c615c 100644
--- a/include/maxminddb.h
+++ b/include/maxminddb.h
@@ -5,8 +5,16 @@ extern "C" {
#ifndef MAXMINDDB_H
#define MAXMINDDB_H
+/* Request POSIX.1-2008. However, we want to remain compatible with
+ * POSIX.1-2001 (since we have been historically and see no reason to drop
+ * compatibility). By requesting POSIX.1-2008, we can conditionally use
+ * features provided by that standard if the implementation provides it. We can
+ * check for what the implementation provides by checking the _POSIX_VERSION
+ * macro after including unistd.h. If a feature is in POSIX.1-2008 but not
+ * POSIX.1-2001, check that macro before using the feature (or check for the
+ * feature directly if possible). */
#ifndef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 200112L
+#define _POSIX_C_SOURCE 200809L
#endif
#include "maxminddb_config.h"
@@ -20,7 +28,7 @@ extern "C" {
#include
#include
/* libmaxminddb package version from configure */
-#define PACKAGE_VERSION "1.2.1"
+#define PACKAGE_VERSION "1.3.2"
typedef ADDRESS_FAMILY sa_family_t;
@@ -87,7 +95,7 @@ typedef unsigned __int128 mmdb_uint128_t;
/* This is a pointer into the data section for a given IP address lookup */
typedef struct MMDB_entry_s {
- struct MMDB_s *mmdb;
+ const struct MMDB_s *mmdb;
uint32_t offset;
} MMDB_entry_s;
@@ -135,6 +143,7 @@ typedef struct MMDB_entry_data_s {
typedef struct MMDB_entry_data_list_s {
MMDB_entry_data_s entry_data;
struct MMDB_entry_data_list_s *next;
+ void *pool;
} MMDB_entry_data_list_s;
typedef struct MMDB_description_s {
@@ -189,41 +198,40 @@ typedef struct MMDB_search_node_s {
MMDB_entry_s right_record_entry;
} MMDB_search_node_s;
- /* *INDENT-OFF* */
- /* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */
- extern int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb);
- extern MMDB_lookup_result_s MMDB_lookup_string(MMDB_s *const mmdb,
- const char *const ipstr,
- int *const gai_error,
- int *const mmdb_error);
- extern MMDB_lookup_result_s MMDB_lookup_sockaddr(
- MMDB_s *const mmdb,
- const struct sockaddr *const sockaddr,
- int *const mmdb_error);
- extern int MMDB_read_node(MMDB_s *const mmdb, uint32_t node_number,
- MMDB_search_node_s *const node);
- extern int MMDB_get_value(MMDB_entry_s *const start,
- MMDB_entry_data_s *const entry_data,
- ...);
- extern int MMDB_vget_value(MMDB_entry_s *const start,
- MMDB_entry_data_s *const entry_data,
- va_list va_path);
- extern int MMDB_aget_value(MMDB_entry_s *const start,
- MMDB_entry_data_s *const entry_data,
- const char *const *const path);
- extern int MMDB_get_metadata_as_entry_data_list(
- MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list);
- extern int MMDB_get_entry_data_list(
- MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list);
- extern void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list);
- extern void MMDB_close(MMDB_s *const mmdb);
- extern const char *MMDB_lib_version(void);
- extern int MMDB_dump_entry_data_list(FILE *const stream,
- MMDB_entry_data_list_s *const entry_data_list,
- int indent);
- extern const char *MMDB_strerror(int error_code);
- /* --prototypes end - don't remove this comment-- */
- /* *INDENT-ON* */
+extern int MMDB_open(const char *const filename, uint32_t flags,
+ MMDB_s *const mmdb);
+extern MMDB_lookup_result_s MMDB_lookup_string(const MMDB_s *const mmdb,
+ const char *const ipstr,
+ int *const gai_error,
+ int *const mmdb_error);
+extern MMDB_lookup_result_s MMDB_lookup_sockaddr(
+ const MMDB_s *const mmdb,
+ const struct sockaddr *const sockaddr,
+ int *const mmdb_error);
+extern int MMDB_read_node(const MMDB_s *const mmdb,
+ uint32_t node_number,
+ MMDB_search_node_s *const node);
+extern int MMDB_get_value(MMDB_entry_s *const start,
+ MMDB_entry_data_s *const entry_data,
+ ...);
+extern int MMDB_vget_value(MMDB_entry_s *const start,
+ MMDB_entry_data_s *const entry_data,
+ va_list va_path);
+extern int MMDB_aget_value(MMDB_entry_s *const start,
+ MMDB_entry_data_s *const entry_data,
+ const char *const *const path);
+extern int MMDB_get_metadata_as_entry_data_list(
+ const MMDB_s *const mmdb, MMDB_entry_data_list_s **const entry_data_list);
+extern int MMDB_get_entry_data_list(
+ MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list);
+extern void MMDB_free_entry_data_list(
+ MMDB_entry_data_list_s *const entry_data_list);
+extern void MMDB_close(MMDB_s *const mmdb);
+extern const char *MMDB_lib_version(void);
+extern int MMDB_dump_entry_data_list(FILE *const stream,
+ MMDB_entry_data_list_s *const entry_data_list,
+ int indent);
+extern const char *MMDB_strerror(int error_code);
#endif /* MAXMINDDB_H */