geoip2_c 0.3.2 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ubuntu.yml +33 -0
- data/.github/workflows/windows.yml +52 -0
- data/README.md +22 -10
- data/docker-compose.yml +22 -1
- data/dockerfiles/{Dockerfile-ruby2.3 → Dockerfile-ruby2.5} +1 -1
- data/dockerfiles/{Dockerfile-ruby2.1 → Dockerfile-ruby2.6} +1 -1
- data/dockerfiles/{Dockerfile-ruby2.2 → Dockerfile-ruby2.7} +1 -1
- data/ext/geoip2/extconf.rb +11 -4
- data/ext/geoip2/geoip2.c +63 -18
- data/ext/geoip2/libmaxminddb/.gitignore +3 -0
- data/ext/geoip2/libmaxminddb/.travis.yml +24 -2
- data/ext/geoip2/libmaxminddb/Changes.md +39 -0
- data/ext/geoip2/libmaxminddb/README.dev.md +41 -30
- data/ext/geoip2/libmaxminddb/README.md +3 -3
- data/ext/geoip2/libmaxminddb/bin/Makefile.am +5 -0
- data/ext/geoip2/libmaxminddb/bin/mmdblookup.c +333 -15
- data/ext/geoip2/libmaxminddb/configure.ac +5 -5
- data/ext/geoip2/libmaxminddb/dev-bin/ppa-release.sh +8 -5
- data/ext/geoip2/libmaxminddb/dev-bin/release.sh +7 -0
- data/ext/geoip2/libmaxminddb/dev-bin/valgrind-all.pl +10 -3
- data/ext/geoip2/libmaxminddb/include/maxminddb.h +11 -2
- data/ext/geoip2/libmaxminddb/projects/VS12/libmaxminddb.vcxproj +3 -1
- data/ext/geoip2/libmaxminddb/projects/VS12/libmaxminddb.vcxproj.filters +7 -1
- data/ext/geoip2/libmaxminddb/src/Makefile.am +18 -2
- data/ext/geoip2/libmaxminddb/src/data-pool.c +180 -0
- data/ext/geoip2/libmaxminddb/src/data-pool.h +52 -0
- data/ext/geoip2/libmaxminddb/src/maxminddb.c +58 -48
- data/ext/geoip2/libmaxminddb/t/Makefile.am +6 -2
- data/ext/geoip2/libmaxminddb/t/bad_databases_t.c +1 -0
- data/ext/geoip2/libmaxminddb/t/basic_lookup_t.c +35 -0
- data/ext/geoip2/libmaxminddb/t/data-pool-t.c +374 -0
- data/ext/geoip2/libmaxminddb/t/external_symbols_t.pl +106 -0
- data/ext/geoip2/libmaxminddb/t/libtap/.gitignore +13 -0
- data/ext/geoip2/libmaxminddb/t/libtap/.travis.yml +13 -0
- data/ext/geoip2/libmaxminddb/t/libtap/COPYING +165 -0
- data/ext/geoip2/libmaxminddb/t/libtap/INSTALL +41 -0
- data/ext/geoip2/libmaxminddb/t/libtap/Makefile +72 -0
- data/ext/geoip2/libmaxminddb/t/libtap/Makefile.win +37 -0
- data/ext/geoip2/libmaxminddb/t/libtap/README.md +268 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/cmp_mem.c +20 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/cmp_mem.expected +28 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/cmpok.c +16 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/cmpok.expected +37 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/diag.c +10 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/diag.expected +2 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/diesok.c +14 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/diesok.expected +6 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/is.c +24 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/is.expected +58 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/like.c +10 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/like.expected +4 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/simple.c +31 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/simple.expected +32 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/skip.c +23 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/skip.expected +9 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/synopsis.c +13 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/synopsis.expected +9 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/test.c +28 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/todo.c +17 -0
- data/ext/geoip2/libmaxminddb/t/libtap/t/todo.expected +11 -0
- data/ext/geoip2/libmaxminddb/t/libtap/tap.c +354 -0
- data/ext/geoip2/libmaxminddb/t/libtap/tap.h +115 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/.gitattributes +1 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/.gitconfig +2 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/.gitignore +2 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/.perltidyallrc +11 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/.tidyallrc +7 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/LICENSE +4 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/MaxMind-DB-spec.md +558 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/README.md +4 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/README.md +7 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/libmaxminddb/libmaxminddb-offset-integer-overflow.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/cyclic-data-structure.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/invalid-bytes-length.mmdb +1 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/invalid-data-record-offset.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/invalid-map-key-length.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/invalid-string-length.mmdb +1 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/metadata-is-an-uint128.mmdb +1 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/unexpected-bytes.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/perltidyrc +12 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Anonymous-IP-Test.json +32 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-City-Test.json +12616 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Connection-Type-Test.json +102 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Country-Test.json +10975 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-DensityIncome-Test.json +14 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Domain-Test.json +452 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Enterprise-Test.json +666 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-ISP-Test.json +12585 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Precision-Enterprise-Test.json +1035 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoLite2-ASN-Test.json +37 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/README +13 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-City-Test.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Country-Test.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Domain-Test.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-ISP-Test.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoLite2-ASN-Test.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-nested.mmdb +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/README.md +26 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/maps-with-pointers.raw +0 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/write-test-data.pl +614 -0
- data/ext/geoip2/libmaxminddb/t/maxmind-db/tidyall.ini +5 -0
- data/geoip2_c.gemspec +2 -3
- data/lib/geoip2/database.rb +4 -0
- data/lib/geoip2/version.rb +1 -1
- metadata +114 -22
- data/.travis.yml +0 -31
- data/Appraisals +0 -7
- data/gemfiles/ruby_2.1.gemfile +0 -7
- data/gemfiles/ruby_2.2.gemfile +0 -7
@@ -0,0 +1,180 @@
|
|
1
|
+
#include "data-pool.h"
|
2
|
+
#include "maxminddb.h"
|
3
|
+
|
4
|
+
#include <stdbool.h>
|
5
|
+
#include <stddef.h>
|
6
|
+
#include <stdlib.h>
|
7
|
+
|
8
|
+
static bool can_multiply(size_t const, size_t const, size_t const);
|
9
|
+
|
10
|
+
// Allocate an MMDB_data_pool_s. It initially has space for size
|
11
|
+
// MMDB_entry_data_list_s structs.
|
12
|
+
MMDB_data_pool_s *data_pool_new(size_t const size)
|
13
|
+
{
|
14
|
+
MMDB_data_pool_s *const pool = calloc(1, sizeof(MMDB_data_pool_s));
|
15
|
+
if (!pool) {
|
16
|
+
return NULL;
|
17
|
+
}
|
18
|
+
|
19
|
+
if (size == 0 ||
|
20
|
+
!can_multiply(SIZE_MAX, size, sizeof(MMDB_entry_data_list_s))) {
|
21
|
+
data_pool_destroy(pool);
|
22
|
+
return NULL;
|
23
|
+
}
|
24
|
+
pool->size = size;
|
25
|
+
pool->blocks[0] = calloc(pool->size, sizeof(MMDB_entry_data_list_s));
|
26
|
+
if (!pool->blocks[0]) {
|
27
|
+
data_pool_destroy(pool);
|
28
|
+
return NULL;
|
29
|
+
}
|
30
|
+
pool->blocks[0]->pool = pool;
|
31
|
+
|
32
|
+
pool->sizes[0] = size;
|
33
|
+
|
34
|
+
pool->block = pool->blocks[0];
|
35
|
+
|
36
|
+
return pool;
|
37
|
+
}
|
38
|
+
|
39
|
+
// Determine if we can multiply m*n. We can do this if the result will be below
|
40
|
+
// the given max. max will typically be SIZE_MAX.
|
41
|
+
//
|
42
|
+
// We want to know if we'll wrap around.
|
43
|
+
static bool can_multiply(size_t const max, size_t const m, size_t const n)
|
44
|
+
{
|
45
|
+
if (m == 0) {
|
46
|
+
return false;
|
47
|
+
}
|
48
|
+
|
49
|
+
return n <= max / m;
|
50
|
+
}
|
51
|
+
|
52
|
+
// Clean up the data pool.
|
53
|
+
void data_pool_destroy(MMDB_data_pool_s *const pool)
|
54
|
+
{
|
55
|
+
if (!pool) {
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
|
59
|
+
for (size_t i = 0; i <= pool->index; i++) {
|
60
|
+
free(pool->blocks[i]);
|
61
|
+
}
|
62
|
+
|
63
|
+
free(pool);
|
64
|
+
}
|
65
|
+
|
66
|
+
// Claim a new struct from the pool. Doing this may cause the pool's size to
|
67
|
+
// grow.
|
68
|
+
MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const pool)
|
69
|
+
{
|
70
|
+
if (!pool) {
|
71
|
+
return NULL;
|
72
|
+
}
|
73
|
+
|
74
|
+
if (pool->used < pool->size) {
|
75
|
+
MMDB_entry_data_list_s *const element = pool->block + pool->used;
|
76
|
+
pool->used++;
|
77
|
+
return element;
|
78
|
+
}
|
79
|
+
|
80
|
+
// Take it from a new block of memory.
|
81
|
+
|
82
|
+
size_t const new_index = pool->index + 1;
|
83
|
+
if (new_index == DATA_POOL_NUM_BLOCKS) {
|
84
|
+
// See the comment about not growing this on DATA_POOL_NUM_BLOCKS.
|
85
|
+
return NULL;
|
86
|
+
}
|
87
|
+
|
88
|
+
if (!can_multiply(SIZE_MAX, pool->size, 2)) {
|
89
|
+
return NULL;
|
90
|
+
}
|
91
|
+
size_t const new_size = pool->size * 2;
|
92
|
+
|
93
|
+
if (!can_multiply(SIZE_MAX, new_size, sizeof(MMDB_entry_data_list_s))) {
|
94
|
+
return NULL;
|
95
|
+
}
|
96
|
+
pool->blocks[new_index] = calloc(new_size, sizeof(MMDB_entry_data_list_s));
|
97
|
+
if (!pool->blocks[new_index]) {
|
98
|
+
return NULL;
|
99
|
+
}
|
100
|
+
|
101
|
+
// We don't need to set this, but it's useful for introspection in tests.
|
102
|
+
pool->blocks[new_index]->pool = pool;
|
103
|
+
|
104
|
+
pool->index = new_index;
|
105
|
+
pool->block = pool->blocks[pool->index];
|
106
|
+
|
107
|
+
pool->size = new_size;
|
108
|
+
pool->sizes[pool->index] = pool->size;
|
109
|
+
|
110
|
+
MMDB_entry_data_list_s *const element = pool->block;
|
111
|
+
pool->used = 1;
|
112
|
+
return element;
|
113
|
+
}
|
114
|
+
|
115
|
+
// Turn the structs in the array-like pool into a linked list.
|
116
|
+
//
|
117
|
+
// Before calling this function, the list isn't linked up.
|
118
|
+
MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const pool)
|
119
|
+
{
|
120
|
+
if (!pool) {
|
121
|
+
return NULL;
|
122
|
+
}
|
123
|
+
|
124
|
+
if (pool->index == 0 && pool->used == 0) {
|
125
|
+
return NULL;
|
126
|
+
}
|
127
|
+
|
128
|
+
for (size_t i = 0; i <= pool->index; i++) {
|
129
|
+
MMDB_entry_data_list_s *const block = pool->blocks[i];
|
130
|
+
|
131
|
+
size_t size = pool->sizes[i];
|
132
|
+
if (i == pool->index) {
|
133
|
+
size = pool->used;
|
134
|
+
}
|
135
|
+
|
136
|
+
for (size_t j = 0; j < size - 1; j++) {
|
137
|
+
MMDB_entry_data_list_s *const cur = block + j;
|
138
|
+
cur->next = block + j + 1;
|
139
|
+
}
|
140
|
+
|
141
|
+
if (i < pool->index) {
|
142
|
+
MMDB_entry_data_list_s *const last = block + size - 1;
|
143
|
+
last->next = pool->blocks[i + 1];
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
return pool->blocks[0];
|
148
|
+
}
|
149
|
+
|
150
|
+
#ifdef TEST_DATA_POOL
|
151
|
+
|
152
|
+
#include <libtap/tap.h>
|
153
|
+
#include <maxminddb_test_helper.h>
|
154
|
+
|
155
|
+
static void test_can_multiply(void);
|
156
|
+
|
157
|
+
int main(void)
|
158
|
+
{
|
159
|
+
plan(NO_PLAN);
|
160
|
+
test_can_multiply();
|
161
|
+
done_testing();
|
162
|
+
}
|
163
|
+
|
164
|
+
static void test_can_multiply(void)
|
165
|
+
{
|
166
|
+
{
|
167
|
+
ok(can_multiply(SIZE_MAX, 1, SIZE_MAX), "1*SIZE_MAX is ok");
|
168
|
+
}
|
169
|
+
|
170
|
+
{
|
171
|
+
ok(!can_multiply(SIZE_MAX, 2, SIZE_MAX), "2*SIZE_MAX is not ok");
|
172
|
+
}
|
173
|
+
|
174
|
+
{
|
175
|
+
ok(can_multiply(SIZE_MAX, 10240, sizeof(MMDB_entry_data_list_s)),
|
176
|
+
"1024 entry_data_list_s's are okay");
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
#endif
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#ifndef DATA_POOL_H
|
2
|
+
#define DATA_POOL_H
|
3
|
+
|
4
|
+
#include "maxminddb.h"
|
5
|
+
|
6
|
+
#include <stdbool.h>
|
7
|
+
#include <stddef.h>
|
8
|
+
|
9
|
+
// This should be large enough that we never need to grow the array of pointers
|
10
|
+
// to blocks. 32 is enough. Even starting out of with size 1 (1 struct), the
|
11
|
+
// 32nd element alone will provide 2**32 structs as we exponentially increase
|
12
|
+
// the number in each block. Being confident that we do not have to grow the
|
13
|
+
// array lets us avoid writing code to do that. That code would be risky as it
|
14
|
+
// would rarely be hit and likely not be well tested.
|
15
|
+
#define DATA_POOL_NUM_BLOCKS 32
|
16
|
+
|
17
|
+
// A pool of memory for MMDB_entry_data_list_s structs. This is so we can
|
18
|
+
// allocate multiple up front rather than one at a time for performance
|
19
|
+
// reasons.
|
20
|
+
//
|
21
|
+
// The order you add elements to it (by calling data_pool_alloc()) ends up as
|
22
|
+
// the order of the list.
|
23
|
+
//
|
24
|
+
// The memory only grows. There is no support for releasing an element you take
|
25
|
+
// back to the pool.
|
26
|
+
typedef struct MMDB_data_pool_s {
|
27
|
+
// Index of the current block we're allocating out of.
|
28
|
+
size_t index;
|
29
|
+
|
30
|
+
// The size of the current block, counting by structs.
|
31
|
+
size_t size;
|
32
|
+
|
33
|
+
// How many used in the current block, counting by structs.
|
34
|
+
size_t used;
|
35
|
+
|
36
|
+
// The current block we're allocating out of.
|
37
|
+
MMDB_entry_data_list_s *block;
|
38
|
+
|
39
|
+
// The size of each block.
|
40
|
+
size_t sizes[DATA_POOL_NUM_BLOCKS];
|
41
|
+
|
42
|
+
// An array of pointers to blocks of memory holding space for list
|
43
|
+
// elements.
|
44
|
+
MMDB_entry_data_list_s *blocks[DATA_POOL_NUM_BLOCKS];
|
45
|
+
} MMDB_data_pool_s;
|
46
|
+
|
47
|
+
MMDB_data_pool_s *data_pool_new(size_t const);
|
48
|
+
void data_pool_destroy(MMDB_data_pool_s *const);
|
49
|
+
MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const);
|
50
|
+
MMDB_entry_data_list_s *data_pool_to_list(MMDB_data_pool_s *const);
|
51
|
+
|
52
|
+
#endif
|
@@ -1,6 +1,7 @@
|
|
1
1
|
#if HAVE_CONFIG_H
|
2
2
|
#include <config.h>
|
3
3
|
#endif
|
4
|
+
#include "data-pool.h"
|
4
5
|
#include "maxminddb.h"
|
5
6
|
#include "maxminddb-compat-util.h"
|
6
7
|
#include <assert.h>
|
@@ -130,6 +131,9 @@ typedef struct record_info_s {
|
|
130
131
|
/* This is 128kb */
|
131
132
|
#define METADATA_BLOCK_MAX_SIZE 131072
|
132
133
|
|
134
|
+
// 64 leads us to allocating 4 KiB on a 64bit system.
|
135
|
+
#define MMDB_POOL_INIT_SIZE 64
|
136
|
+
|
133
137
|
/* *INDENT-OFF* */
|
134
138
|
/* --prototypes automatically generated by dev-bin/regen-prototypes.pl - don't remove this comment */
|
135
139
|
LOCAL int map_file(MMDB_s *const mmdb);
|
@@ -176,8 +180,10 @@ LOCAL int decode_one(MMDB_s *mmdb, uint32_t offset,
|
|
176
180
|
LOCAL int get_ext_type(int raw_ext_type);
|
177
181
|
LOCAL uint32_t get_ptr_from(uint8_t ctrl, uint8_t const *const ptr,
|
178
182
|
int ptr_size);
|
179
|
-
LOCAL int get_entry_data_list(MMDB_s *mmdb,
|
183
|
+
LOCAL int get_entry_data_list(MMDB_s *mmdb,
|
184
|
+
uint32_t offset,
|
180
185
|
MMDB_entry_data_list_s *const entry_data_list,
|
186
|
+
MMDB_data_pool_s *const pool,
|
181
187
|
int depth);
|
182
188
|
LOCAL float get_ieee754_float(const uint8_t *restrict p);
|
183
189
|
LOCAL double get_ieee754_double(const uint8_t *restrict p);
|
@@ -186,7 +192,6 @@ LOCAL uint32_t get_uint24(const uint8_t *p);
|
|
186
192
|
LOCAL uint32_t get_uint16(const uint8_t *p);
|
187
193
|
LOCAL uint64_t get_uintX(const uint8_t *p, int length);
|
188
194
|
LOCAL int32_t get_sintX(const uint8_t *p, int length);
|
189
|
-
LOCAL MMDB_entry_data_list_s *new_entry_data_list(void);
|
190
195
|
LOCAL void free_mmdb_struct(MMDB_s *const mmdb);
|
191
196
|
LOCAL void free_languages_metadata(MMDB_s *mmdb);
|
192
197
|
LOCAL void free_descriptions_metadata(MMDB_s *mmdb);
|
@@ -241,7 +246,7 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
|
|
241
246
|
}
|
242
247
|
mmdb->flags = flags;
|
243
248
|
|
244
|
-
if (MMDB_SUCCESS != (status = map_file(mmdb))
|
249
|
+
if (MMDB_SUCCESS != (status = map_file(mmdb))) {
|
245
250
|
goto cleanup;
|
246
251
|
}
|
247
252
|
|
@@ -297,6 +302,15 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
|
|
297
302
|
mmdb->ipv4_start_node.node_value = 0;
|
298
303
|
mmdb->ipv4_start_node.netmask = 0;
|
299
304
|
|
305
|
+
// We do this immediately as otherwise there is a race to set
|
306
|
+
// ipv4_start_node.node_value and ipv4_start_node.netmask.
|
307
|
+
if (mmdb->metadata.ip_version == 6) {
|
308
|
+
status = find_ipv4_start_node(mmdb);
|
309
|
+
if (status != MMDB_SUCCESS) {
|
310
|
+
goto cleanup;
|
311
|
+
}
|
312
|
+
}
|
313
|
+
|
300
314
|
cleanup:
|
301
315
|
if (MMDB_SUCCESS != status) {
|
302
316
|
int saved_errno = errno;
|
@@ -361,7 +375,11 @@ LOCAL int map_file(MMDB_s *const mmdb)
|
|
361
375
|
ssize_t size;
|
362
376
|
int status = MMDB_SUCCESS;
|
363
377
|
|
364
|
-
int
|
378
|
+
int flags = O_RDONLY;
|
379
|
+
#ifdef O_CLOEXEC
|
380
|
+
flags |= O_CLOEXEC;
|
381
|
+
#endif
|
382
|
+
int fd = open(mmdb->filename, flags);
|
365
383
|
struct stat s;
|
366
384
|
if (fd < 0 || fstat(fd, &s)) {
|
367
385
|
status = MMDB_FILE_OPEN_ERROR;
|
@@ -1634,15 +1652,33 @@ int MMDB_get_metadata_as_entry_data_list(
|
|
1634
1652
|
int MMDB_get_entry_data_list(
|
1635
1653
|
MMDB_entry_s *start, MMDB_entry_data_list_s **const entry_data_list)
|
1636
1654
|
{
|
1637
|
-
*
|
1638
|
-
if (
|
1655
|
+
MMDB_data_pool_s *const pool = data_pool_new(MMDB_POOL_INIT_SIZE);
|
1656
|
+
if (!pool) {
|
1657
|
+
return MMDB_OUT_OF_MEMORY_ERROR;
|
1658
|
+
}
|
1659
|
+
|
1660
|
+
MMDB_entry_data_list_s *const list = data_pool_alloc(pool);
|
1661
|
+
if (!list) {
|
1662
|
+
data_pool_destroy(pool);
|
1663
|
+
return MMDB_OUT_OF_MEMORY_ERROR;
|
1664
|
+
}
|
1665
|
+
|
1666
|
+
int const status = get_entry_data_list(start->mmdb, start->offset, list,
|
1667
|
+
pool, 0);
|
1668
|
+
|
1669
|
+
*entry_data_list = data_pool_to_list(pool);
|
1670
|
+
if (!*entry_data_list) {
|
1671
|
+
data_pool_destroy(pool);
|
1639
1672
|
return MMDB_OUT_OF_MEMORY_ERROR;
|
1640
1673
|
}
|
1641
|
-
|
1674
|
+
|
1675
|
+
return status;
|
1642
1676
|
}
|
1643
1677
|
|
1644
|
-
LOCAL int get_entry_data_list(MMDB_s *mmdb,
|
1678
|
+
LOCAL int get_entry_data_list(MMDB_s *mmdb,
|
1679
|
+
uint32_t offset,
|
1645
1680
|
MMDB_entry_data_list_s *const entry_data_list,
|
1681
|
+
MMDB_data_pool_s *const pool,
|
1646
1682
|
int depth)
|
1647
1683
|
{
|
1648
1684
|
if (depth >= MAXIMUM_DATA_STRUCTURE_DEPTH) {
|
@@ -1672,7 +1708,7 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
|
|
1672
1708
|
|
1673
1709
|
int status =
|
1674
1710
|
get_entry_data_list(mmdb, last_offset, entry_data_list,
|
1675
|
-
depth);
|
1711
|
+
pool, depth);
|
1676
1712
|
if (MMDB_SUCCESS != status) {
|
1677
1713
|
DEBUG_MSG("get_entry_data_list on pointer failed.");
|
1678
1714
|
return status;
|
@@ -1685,26 +1721,22 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
|
|
1685
1721
|
{
|
1686
1722
|
uint32_t array_size = entry_data_list->entry_data.data_size;
|
1687
1723
|
uint32_t array_offset = entry_data_list->entry_data.offset_to_next;
|
1688
|
-
MMDB_entry_data_list_s *previous = entry_data_list;
|
1689
1724
|
while (array_size-- > 0) {
|
1690
|
-
MMDB_entry_data_list_s *entry_data_list_to =
|
1691
|
-
|
1692
|
-
if (
|
1725
|
+
MMDB_entry_data_list_s *entry_data_list_to =
|
1726
|
+
data_pool_alloc(pool);
|
1727
|
+
if (!entry_data_list_to) {
|
1693
1728
|
return MMDB_OUT_OF_MEMORY_ERROR;
|
1694
1729
|
}
|
1695
1730
|
|
1696
1731
|
int status =
|
1697
1732
|
get_entry_data_list(mmdb, array_offset, entry_data_list_to,
|
1698
|
-
depth);
|
1733
|
+
pool, depth);
|
1699
1734
|
if (MMDB_SUCCESS != status) {
|
1700
1735
|
DEBUG_MSG("get_entry_data_list on array element failed.");
|
1701
1736
|
return status;
|
1702
1737
|
}
|
1703
1738
|
|
1704
1739
|
array_offset = entry_data_list_to->entry_data.offset_to_next;
|
1705
|
-
while (previous->next) {
|
1706
|
-
previous = previous->next;
|
1707
|
-
}
|
1708
1740
|
}
|
1709
1741
|
entry_data_list->entry_data.offset_to_next = array_offset;
|
1710
1742
|
|
@@ -1715,45 +1747,33 @@ LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
|
|
1715
1747
|
uint32_t size = entry_data_list->entry_data.data_size;
|
1716
1748
|
|
1717
1749
|
offset = entry_data_list->entry_data.offset_to_next;
|
1718
|
-
MMDB_entry_data_list_s *previous = entry_data_list;
|
1719
1750
|
while (size-- > 0) {
|
1720
|
-
MMDB_entry_data_list_s *
|
1721
|
-
|
1722
|
-
if (NULL == entry_data_list_to) {
|
1751
|
+
MMDB_entry_data_list_s *list_key = data_pool_alloc(pool);
|
1752
|
+
if (!list_key) {
|
1723
1753
|
return MMDB_OUT_OF_MEMORY_ERROR;
|
1724
1754
|
}
|
1725
1755
|
|
1726
1756
|
int status =
|
1727
|
-
get_entry_data_list(mmdb, offset,
|
1728
|
-
depth);
|
1757
|
+
get_entry_data_list(mmdb, offset, list_key, pool, depth);
|
1729
1758
|
if (MMDB_SUCCESS != status) {
|
1730
1759
|
DEBUG_MSG("get_entry_data_list on map key failed.");
|
1731
1760
|
return status;
|
1732
1761
|
}
|
1733
1762
|
|
1734
|
-
|
1735
|
-
previous = previous->next;
|
1736
|
-
}
|
1737
|
-
|
1738
|
-
offset = entry_data_list_to->entry_data.offset_to_next;
|
1739
|
-
entry_data_list_to = previous->next =
|
1740
|
-
new_entry_data_list();
|
1763
|
+
offset = list_key->entry_data.offset_to_next;
|
1741
1764
|
|
1742
|
-
|
1765
|
+
MMDB_entry_data_list_s *list_value = data_pool_alloc(pool);
|
1766
|
+
if (!list_value) {
|
1743
1767
|
return MMDB_OUT_OF_MEMORY_ERROR;
|
1744
1768
|
}
|
1745
1769
|
|
1746
|
-
status = get_entry_data_list(mmdb, offset,
|
1770
|
+
status = get_entry_data_list(mmdb, offset, list_value, pool,
|
1747
1771
|
depth);
|
1748
1772
|
if (MMDB_SUCCESS != status) {
|
1749
1773
|
DEBUG_MSG("get_entry_data_list on map element failed.");
|
1750
1774
|
return status;
|
1751
1775
|
}
|
1752
|
-
|
1753
|
-
while (previous->next) {
|
1754
|
-
previous = previous->next;
|
1755
|
-
}
|
1756
|
-
offset = entry_data_list_to->entry_data.offset_to_next;
|
1776
|
+
offset = list_value->entry_data.offset_to_next;
|
1757
1777
|
}
|
1758
1778
|
entry_data_list->entry_data.offset_to_next = offset;
|
1759
1779
|
}
|
@@ -1832,22 +1852,12 @@ LOCAL int32_t get_sintX(const uint8_t *p, int length)
|
|
1832
1852
|
return (int32_t)get_uintX(p, length);
|
1833
1853
|
}
|
1834
1854
|
|
1835
|
-
LOCAL MMDB_entry_data_list_s *new_entry_data_list(void)
|
1836
|
-
{
|
1837
|
-
/* We need calloc here in order to ensure that the ->next pointer in the
|
1838
|
-
* struct doesn't point to some random address. */
|
1839
|
-
return calloc(1, sizeof(MMDB_entry_data_list_s));
|
1840
|
-
}
|
1841
|
-
|
1842
1855
|
void MMDB_free_entry_data_list(MMDB_entry_data_list_s *const entry_data_list)
|
1843
1856
|
{
|
1844
1857
|
if (entry_data_list == NULL) {
|
1845
1858
|
return;
|
1846
1859
|
}
|
1847
|
-
|
1848
|
-
MMDB_free_entry_data_list(entry_data_list->next);
|
1849
|
-
}
|
1850
|
-
free(entry_data_list);
|
1860
|
+
data_pool_destroy(entry_data_list->pool);
|
1851
1861
|
}
|
1852
1862
|
|
1853
1863
|
void MMDB_close(MMDB_s *const mmdb)
|
@@ -12,12 +12,16 @@ libmmdbtest_la_SOURCES = maxminddb_test_helper.c
|
|
12
12
|
|
13
13
|
check_PROGRAMS = \
|
14
14
|
bad_pointers_t bad_databases_t basic_lookup_t data_entry_list_t \
|
15
|
-
data_types_t dump_t get_value_t get_value_pointer_bug_t \
|
15
|
+
data-pool-t data_types_t dump_t get_value_t get_value_pointer_bug_t \
|
16
16
|
ipv4_start_cache_t ipv6_lookup_in_ipv4_t metadata_t metadata_pointers_t \
|
17
17
|
no_map_get_value_t read_node_t threads_t version_t
|
18
18
|
|
19
|
+
data_pool_t_CFLAGS = $(CFLAGS) -I$(top_srcdir)/src
|
20
|
+
data_pool_t_LDFLAGS = $(AM_LDFLAGS) -lm
|
21
|
+
data_pool_t_SOURCES = data-pool-t.c ../src/data-pool.c
|
22
|
+
|
19
23
|
threads_t_CFLAGS = $(CFLAGS) -pthread
|
20
24
|
|
21
|
-
TESTS = $(check_PROGRAMS) compile_c++_t.pl mmdblookup_t.pl
|
25
|
+
TESTS = $(check_PROGRAMS) compile_c++_t.pl external_symbols_t.pl mmdblookup_t.pl
|
22
26
|
|
23
27
|
LDADD = libmmdbtest.la libtap/libtap.a
|
@@ -1,5 +1,7 @@
|
|
1
1
|
#include "maxminddb_test_helper.h"
|
2
2
|
|
3
|
+
static void test_big_lookup(void);
|
4
|
+
|
3
5
|
/* These globals are gross but it's the easiest way to mix calling
|
4
6
|
* for_all_modes() and for_all_record_sizes() */
|
5
7
|
static int Current_Mode;
|
@@ -164,9 +166,42 @@ void all_record_sizes(int mode, const char *description)
|
|
164
166
|
}
|
165
167
|
}
|
166
168
|
|
169
|
+
static void test_big_lookup(void)
|
170
|
+
{
|
171
|
+
const char *const db_filename = "GeoIP2-Precision-Enterprise-Test.mmdb";
|
172
|
+
const char *const db_path = test_database_path(db_filename);
|
173
|
+
ok(db_path != NULL, "got database path");
|
174
|
+
|
175
|
+
MMDB_s * const mmdb = open_ok(db_path, MMDB_MODE_MMAP, "mmap mode");
|
176
|
+
ok(mmdb != NULL, "opened MMDB");
|
177
|
+
free((char *)db_path);
|
178
|
+
|
179
|
+
int gai_err = 0, mmdb_err = 0;
|
180
|
+
const char *const ip_address = "81.2.69.160";
|
181
|
+
MMDB_lookup_result_s result = MMDB_lookup_string(mmdb, ip_address, &gai_err,
|
182
|
+
&mmdb_err);
|
183
|
+
ok(gai_err == 0, "no getaddrinfo error");
|
184
|
+
ok(mmdb_err == MMDB_SUCCESS, "no error from maxminddb library");
|
185
|
+
ok(result.found_entry, "found IP");
|
186
|
+
|
187
|
+
MMDB_entry_data_list_s *entry_data_list = NULL;
|
188
|
+
ok(
|
189
|
+
MMDB_get_entry_data_list(&result.entry,
|
190
|
+
&entry_data_list) == MMDB_SUCCESS,
|
191
|
+
"successfully looked up entry data list"
|
192
|
+
);
|
193
|
+
ok(entry_data_list != NULL, "got an entry_data_list");
|
194
|
+
|
195
|
+
MMDB_free_entry_data_list(entry_data_list);
|
196
|
+
|
197
|
+
MMDB_close(mmdb);
|
198
|
+
free(mmdb);
|
199
|
+
}
|
200
|
+
|
167
201
|
int main(void)
|
168
202
|
{
|
169
203
|
plan(NO_PLAN);
|
170
204
|
for_all_modes(&all_record_sizes);
|
205
|
+
test_big_lookup();
|
171
206
|
done_testing();
|
172
207
|
}
|