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.
Files changed (132) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ubuntu.yml +33 -0
  3. data/.github/workflows/windows.yml +52 -0
  4. data/README.md +22 -10
  5. data/docker-compose.yml +22 -1
  6. data/dockerfiles/{Dockerfile-ruby2.3 → Dockerfile-ruby2.5} +1 -1
  7. data/dockerfiles/{Dockerfile-ruby2.1 → Dockerfile-ruby2.6} +1 -1
  8. data/dockerfiles/{Dockerfile-ruby2.2 → Dockerfile-ruby2.7} +1 -1
  9. data/ext/geoip2/extconf.rb +11 -4
  10. data/ext/geoip2/geoip2.c +63 -18
  11. data/ext/geoip2/libmaxminddb/.gitignore +3 -0
  12. data/ext/geoip2/libmaxminddb/.travis.yml +24 -2
  13. data/ext/geoip2/libmaxminddb/Changes.md +39 -0
  14. data/ext/geoip2/libmaxminddb/README.dev.md +41 -30
  15. data/ext/geoip2/libmaxminddb/README.md +3 -3
  16. data/ext/geoip2/libmaxminddb/bin/Makefile.am +5 -0
  17. data/ext/geoip2/libmaxminddb/bin/mmdblookup.c +333 -15
  18. data/ext/geoip2/libmaxminddb/configure.ac +5 -5
  19. data/ext/geoip2/libmaxminddb/dev-bin/ppa-release.sh +8 -5
  20. data/ext/geoip2/libmaxminddb/dev-bin/release.sh +7 -0
  21. data/ext/geoip2/libmaxminddb/dev-bin/valgrind-all.pl +10 -3
  22. data/ext/geoip2/libmaxminddb/include/maxminddb.h +11 -2
  23. data/ext/geoip2/libmaxminddb/projects/VS12/libmaxminddb.vcxproj +3 -1
  24. data/ext/geoip2/libmaxminddb/projects/VS12/libmaxminddb.vcxproj.filters +7 -1
  25. data/ext/geoip2/libmaxminddb/src/Makefile.am +18 -2
  26. data/ext/geoip2/libmaxminddb/src/data-pool.c +180 -0
  27. data/ext/geoip2/libmaxminddb/src/data-pool.h +52 -0
  28. data/ext/geoip2/libmaxminddb/src/maxminddb.c +58 -48
  29. data/ext/geoip2/libmaxminddb/t/Makefile.am +6 -2
  30. data/ext/geoip2/libmaxminddb/t/bad_databases_t.c +1 -0
  31. data/ext/geoip2/libmaxminddb/t/basic_lookup_t.c +35 -0
  32. data/ext/geoip2/libmaxminddb/t/data-pool-t.c +374 -0
  33. data/ext/geoip2/libmaxminddb/t/external_symbols_t.pl +106 -0
  34. data/ext/geoip2/libmaxminddb/t/libtap/.gitignore +13 -0
  35. data/ext/geoip2/libmaxminddb/t/libtap/.travis.yml +13 -0
  36. data/ext/geoip2/libmaxminddb/t/libtap/COPYING +165 -0
  37. data/ext/geoip2/libmaxminddb/t/libtap/INSTALL +41 -0
  38. data/ext/geoip2/libmaxminddb/t/libtap/Makefile +72 -0
  39. data/ext/geoip2/libmaxminddb/t/libtap/Makefile.win +37 -0
  40. data/ext/geoip2/libmaxminddb/t/libtap/README.md +268 -0
  41. data/ext/geoip2/libmaxminddb/t/libtap/t/cmp_mem.c +20 -0
  42. data/ext/geoip2/libmaxminddb/t/libtap/t/cmp_mem.expected +28 -0
  43. data/ext/geoip2/libmaxminddb/t/libtap/t/cmpok.c +16 -0
  44. data/ext/geoip2/libmaxminddb/t/libtap/t/cmpok.expected +37 -0
  45. data/ext/geoip2/libmaxminddb/t/libtap/t/diag.c +10 -0
  46. data/ext/geoip2/libmaxminddb/t/libtap/t/diag.expected +2 -0
  47. data/ext/geoip2/libmaxminddb/t/libtap/t/diesok.c +14 -0
  48. data/ext/geoip2/libmaxminddb/t/libtap/t/diesok.expected +6 -0
  49. data/ext/geoip2/libmaxminddb/t/libtap/t/is.c +24 -0
  50. data/ext/geoip2/libmaxminddb/t/libtap/t/is.expected +58 -0
  51. data/ext/geoip2/libmaxminddb/t/libtap/t/like.c +10 -0
  52. data/ext/geoip2/libmaxminddb/t/libtap/t/like.expected +4 -0
  53. data/ext/geoip2/libmaxminddb/t/libtap/t/simple.c +31 -0
  54. data/ext/geoip2/libmaxminddb/t/libtap/t/simple.expected +32 -0
  55. data/ext/geoip2/libmaxminddb/t/libtap/t/skip.c +23 -0
  56. data/ext/geoip2/libmaxminddb/t/libtap/t/skip.expected +9 -0
  57. data/ext/geoip2/libmaxminddb/t/libtap/t/synopsis.c +13 -0
  58. data/ext/geoip2/libmaxminddb/t/libtap/t/synopsis.expected +9 -0
  59. data/ext/geoip2/libmaxminddb/t/libtap/t/test.c +28 -0
  60. data/ext/geoip2/libmaxminddb/t/libtap/t/todo.c +17 -0
  61. data/ext/geoip2/libmaxminddb/t/libtap/t/todo.expected +11 -0
  62. data/ext/geoip2/libmaxminddb/t/libtap/tap.c +354 -0
  63. data/ext/geoip2/libmaxminddb/t/libtap/tap.h +115 -0
  64. data/ext/geoip2/libmaxminddb/t/maxmind-db/.gitattributes +1 -0
  65. data/ext/geoip2/libmaxminddb/t/maxmind-db/.gitconfig +2 -0
  66. data/ext/geoip2/libmaxminddb/t/maxmind-db/.gitignore +2 -0
  67. data/ext/geoip2/libmaxminddb/t/maxmind-db/.perltidyallrc +11 -0
  68. data/ext/geoip2/libmaxminddb/t/maxmind-db/.tidyallrc +7 -0
  69. data/ext/geoip2/libmaxminddb/t/maxmind-db/LICENSE +4 -0
  70. data/ext/geoip2/libmaxminddb/t/maxmind-db/MaxMind-DB-spec.md +558 -0
  71. data/ext/geoip2/libmaxminddb/t/maxmind-db/README.md +4 -0
  72. data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/README.md +7 -0
  73. data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/libmaxminddb/libmaxminddb-offset-integer-overflow.mmdb +0 -0
  74. data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/cyclic-data-structure.mmdb +0 -0
  75. data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/invalid-bytes-length.mmdb +1 -0
  76. data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/invalid-data-record-offset.mmdb +0 -0
  77. data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/invalid-map-key-length.mmdb +0 -0
  78. data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/invalid-string-length.mmdb +1 -0
  79. data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/metadata-is-an-uint128.mmdb +1 -0
  80. data/ext/geoip2/libmaxminddb/t/maxmind-db/bad-data/maxminddb-golang/unexpected-bytes.mmdb +0 -0
  81. data/ext/geoip2/libmaxminddb/t/maxmind-db/perltidyrc +12 -0
  82. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Anonymous-IP-Test.json +32 -0
  83. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-City-Test.json +12616 -0
  84. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Connection-Type-Test.json +102 -0
  85. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Country-Test.json +10975 -0
  86. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-DensityIncome-Test.json +14 -0
  87. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Domain-Test.json +452 -0
  88. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Enterprise-Test.json +666 -0
  89. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-ISP-Test.json +12585 -0
  90. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoIP2-Precision-Enterprise-Test.json +1035 -0
  91. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/GeoLite2-ASN-Test.json +37 -0
  92. data/ext/geoip2/libmaxminddb/t/maxmind-db/source-data/README +13 -0
  93. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Anonymous-IP-Test.mmdb +0 -0
  94. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-City-Test-Broken-Double-Format.mmdb +0 -0
  95. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-City-Test-Invalid-Node-Count.mmdb +0 -0
  96. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-City-Test.mmdb +0 -0
  97. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Connection-Type-Test.mmdb +0 -0
  98. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Country-Test.mmdb +0 -0
  99. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-DensityIncome-Test.mmdb +0 -0
  100. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Domain-Test.mmdb +0 -0
  101. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Enterprise-Test.mmdb +0 -0
  102. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-ISP-Test.mmdb +0 -0
  103. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoIP2-Precision-Enterprise-Test.mmdb +0 -0
  104. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/GeoLite2-ASN-Test.mmdb +0 -0
  105. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-no-ipv4-search-tree.mmdb +0 -0
  106. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-string-value-entries.mmdb +0 -0
  107. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-broken-pointers-24.mmdb +0 -0
  108. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-broken-search-tree-24.mmdb +0 -0
  109. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-decoder.mmdb +0 -0
  110. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv4-24.mmdb +0 -0
  111. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv4-28.mmdb +0 -0
  112. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv4-32.mmdb +0 -0
  113. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv6-24.mmdb +0 -0
  114. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv6-28.mmdb +0 -0
  115. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-ipv6-32.mmdb +0 -0
  116. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-metadata-pointers.mmdb +0 -0
  117. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-mixed-24.mmdb +0 -0
  118. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-mixed-28.mmdb +0 -0
  119. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-mixed-32.mmdb +0 -0
  120. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/MaxMind-DB-test-nested.mmdb +0 -0
  121. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/README.md +26 -0
  122. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/maps-with-pointers.raw +0 -0
  123. data/ext/geoip2/libmaxminddb/t/maxmind-db/test-data/write-test-data.pl +614 -0
  124. data/ext/geoip2/libmaxminddb/t/maxmind-db/tidyall.ini +5 -0
  125. data/geoip2_c.gemspec +2 -3
  126. data/lib/geoip2/database.rb +4 -0
  127. data/lib/geoip2/version.rb +1 -1
  128. metadata +114 -22
  129. data/.travis.yml +0 -31
  130. data/Appraisals +0 -7
  131. data/gemfiles/ruby_2.1.gemfile +0 -7
  132. 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, uint32_t offset,
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 fd = open(mmdb->filename, O_RDONLY);
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
- *entry_data_list = new_entry_data_list();
1638
- if (NULL == *entry_data_list) {
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
- return get_entry_data_list(start->mmdb, start->offset, *entry_data_list, 0);
1674
+
1675
+ return status;
1642
1676
  }
1643
1677
 
1644
- LOCAL int get_entry_data_list(MMDB_s *mmdb, uint32_t offset,
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 = previous->next =
1691
- new_entry_data_list();
1692
- if (NULL == entry_data_list_to) {
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 *entry_data_list_to = previous->next =
1721
- new_entry_data_list();
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, entry_data_list_to,
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
- while (previous->next) {
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
- if (NULL == entry_data_list_to) {
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, entry_data_list_to,
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
- if (entry_data_list->next) {
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
@@ -26,6 +26,7 @@ int test_read(const char *path, const struct stat *UNUSED(
26
26
 
27
27
  if (status != MMDB_SUCCESS) {
28
28
  ok(1, "received error when opening %s", path);
29
+ free(mmdb);
29
30
  return 0;
30
31
  }
31
32
 
@@ -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
  }