* Add support for Maxmind GeoIP2 database files (#913). * Copy/paste error. * Mark GeoipCode3 as deprecated. * Fix build when compiling with AMBuild. * Replace loose libmaxminddb files with submodule. * Fix Linux build. * One more hack for submodule. * Actually fix Linux build. * GeoIP2 extension to sourcemod * Update basevotes When a player leaves during a voteban, he will be banned anyway. Also added a cvar with a ban time setting. * Update basevotes.sp * Update AMBuilder * ke::AString to std::string * Update extension.cpp * Update AMBuilder * Added coordination natives Added GeoipLatitude, GeoipLongitude, GeoipDistance natives. * Create osdefs.h * Update maxminddb_config.h * Update extension.cpp * Update extension.cpp * Added automatic search for database file * Fix automatic search for database file * Update extension.cpp * Update geoip.inc * .gitmodules revert * Update geoip.inc * Update libmaxminddb to version 1.5.2 * Update extension.cpp * Check language in the DB * Removed langCount variable * Determination of the client's language * Update geoip.inc * Update geoip.inc * Update extension.cpp * Update geoip.inc * Update extension.cpp * space instead of tab in .inc * Update extension.cpp * Update geoip.inc * Optimizing length measurement region code * Update package script to fetch the new GeoLite2 database This package is the last CC-BY-SA licensed GeoLite2-City database extracted from https://src.fedoraproject.org/rpms/geolite2 from december 2019. This doubles the download size for SM packages, but it's what we have to deal with atm :( * Fix potentially returning uninitialized memory in GeoipRegionCode If the lookup failed, we'd copy back whatever is on the stack in the ccode buffer. Co-authored-by: Nick Hastings <nshastings@gmail.com> Co-authored-by: Headline <michaelwflaherty@me.com> Co-authored-by: Accelerator74 <dmitry@447751-accele74.tmweb.ru> Co-authored-by: Peace-Maker <peace-maker@wcfan.de>
		
			
				
	
	
		
			170 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #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
 |