mirror of
				https://github.com/VCMP-SqMod/SqMod.git
				synced 2025-11-01 14:57:18 +01:00 
			
		
		
		
	Update MaxMind DB library to current master.
This commit is contained in:
		
							
								
								
									
										180
									
								
								external/MaxmindDB/data-pool.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								external/MaxmindDB/data-pool.c
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,180 @@ | ||||
| #include "data-pool.h" | ||||
| #include "maxminddb.h" | ||||
|  | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| 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 <libtap/tap.h> | ||||
| #include <maxminddb_test_helper.h> | ||||
|  | ||||
| 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 | ||||
							
								
								
									
										52
									
								
								external/MaxmindDB/data-pool.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								external/MaxmindDB/data-pool.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| #ifndef DATA_POOL_H | ||||
| #define DATA_POOL_H | ||||
|  | ||||
| #include "maxminddb.h" | ||||
|  | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
|  | ||||
| // 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 | ||||
							
								
								
									
										235
									
								
								external/MaxmindDB/maxminddb.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										235
									
								
								external/MaxmindDB/maxminddb.c
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,7 @@ | ||||
| #if HAVE_CONFIG_H | ||||
| #include <config.h> | ||||
| #endif | ||||
| #include "data-pool.h" | ||||
| #include "maxminddb.h" | ||||
| #include "maxminddb-compat-util.h" | ||||
| #include <assert.h> | ||||
| @@ -13,6 +14,9 @@ | ||||
| #include <sys/stat.h> | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| #ifndef UNICODE | ||||
| #define UNICODE | ||||
| #endif | ||||
| #include <windows.h> | ||||
| #include <ws2ipdef.h> | ||||
| #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; | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user