ts-ip2region2 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,272 @@
1
+ // Copyright 2022 The Ip2Region Authors. All rights reserved.
2
+ // Use of this source code is governed by a Apache2.0-style
3
+ // license that can be found in the LICENSE file.
4
+
5
+ // ---
6
+ // @Author Lion <chenxin619315@gmail.com>
7
+ // @Date 2022/06/27
8
+
9
+ #ifndef C_IP2REGION_XDB_H
10
+ #define C_IP2REGION_XDB_H
11
+
12
+ #include <stdio.h>
13
+ #include <stdlib.h>
14
+ #include <string.h>
15
+
16
+ #if ( defined(WIN32) || defined(_WIN32) || defined(__WINDOWS_) || defined(WINNT) )
17
+ # define XDB_PUBLIC(type) extern __declspec(dllexport) type
18
+ # define XDB_PRIVATE(type) static type
19
+ # define XDB_WINDOWS
20
+ #ifndef WIN32_LEAN_AND_MEAN
21
+ #define WIN32_LEAN_AND_MEAN
22
+ #endif
23
+ #include <winsock2.h>
24
+ #include <ws2tcpip.h>
25
+ #include <windows.h>
26
+ #pragma comment(lib, "ws2_32.lib")
27
+ #elif ( defined(linux) || defined(_UNIX) || defined(__APPLE__) )
28
+ # define XDB_PUBLIC(type) extern type
29
+ # define XDB_PRIVATE(type) static inline type
30
+ # define XDB_LINUX
31
+ #include <sys/socket.h>
32
+ #include <netinet/in.h>
33
+ #include <arpa/inet.h>
34
+ #endif
35
+
36
+ #define xdb_calloc( _blocks, _bytes ) calloc( _blocks, _bytes )
37
+ #define xdb_malloc( _bytes ) malloc( _bytes )
38
+ #define xdb_free( _ptr ) free( _ptr )
39
+
40
+ // public constants define
41
+ #define xdb_structure_20 2
42
+ #define xdb_structure_30 3
43
+ #define xdb_header_info_length 256
44
+ #define xdb_vector_index_rows 256
45
+ #define xdb_vector_index_cols 256
46
+ #define xdb_vector_index_size 8
47
+ #define xdb_v4_index_size 14 // 4 + 4 + 2 + 4
48
+ #define xdb_v6_index_size 38 // 16 + 16 + 2 + 4
49
+
50
+ // --- ip version info
51
+ #define xdb_ipv4_id 4
52
+ #define xdb_ipv6_id 6
53
+ #define xdb_ipv4_bytes 4
54
+ #define xdb_ipv6_bytes 16
55
+ // cache of vector_index_row × vector_index_rows × vector_index_size
56
+ #define xdb_vector_index_length 524288
57
+
58
+ // --- xdb buffer functions
59
+
60
+ // use the following buffer struct to wrap the binary buffer data
61
+ // since the buffer data could not be operated with the string API.
62
+ struct xdb_header {
63
+ unsigned short version;
64
+ unsigned short index_policy;
65
+ unsigned int created_at;
66
+ unsigned int start_index_ptr;
67
+ unsigned int end_index_ptr;
68
+
69
+ // since 3.0+ with IPv6 supporting
70
+ unsigned short ip_version;
71
+ unsigned short runtime_ptr_bytes;
72
+
73
+ // the original buffer
74
+ unsigned int length;
75
+ char buffer[xdb_header_info_length];
76
+ };
77
+ typedef struct xdb_header xdb_header_t;
78
+
79
+ XDB_PUBLIC(xdb_header_t *) xdb_load_header(FILE *);
80
+
81
+ XDB_PUBLIC(xdb_header_t *) xdb_load_header_from_file(const char *);
82
+
83
+ XDB_PUBLIC(void) xdb_free_header(void *);
84
+
85
+
86
+ // --- vector index buffer
87
+ struct xdb_vector_index {
88
+ unsigned int length;
89
+ char buffer[xdb_vector_index_length];
90
+ };
91
+ typedef struct xdb_vector_index xdb_vector_index_t;
92
+
93
+ XDB_PUBLIC(xdb_vector_index_t *) xdb_load_vector_index(FILE *);
94
+
95
+ XDB_PUBLIC(xdb_vector_index_t *) xdb_load_vector_index_from_file(const char *);
96
+
97
+ XDB_PUBLIC(void) xdb_free_vector_index(void *);
98
+
99
+
100
+ // --- content buffer
101
+ struct xdb_content {
102
+ unsigned int length;
103
+ char *buffer;
104
+ };
105
+ typedef struct xdb_content xdb_content_t;
106
+
107
+ XDB_PUBLIC(xdb_content_t *) xdb_load_content(FILE *);
108
+
109
+ XDB_PUBLIC(xdb_content_t *) xdb_load_content_from_file(const char *);
110
+
111
+ XDB_PUBLIC(void) xdb_free_content(void *);
112
+
113
+ // --- xdb verify
114
+
115
+ // Verify if the current Searcher could be used to search the specified xdb file.
116
+ // Why do we need this check ?
117
+ // The future features of the xdb impl may cause the current searcher not able to work properly.
118
+ //
119
+ // @Note: You Just need to check this ONCE when the service starts
120
+ // Or use another process (eg, A command) to check once Just to confirm the suitability.
121
+ XDB_PUBLIC(int) xdb_verify(FILE *);
122
+
123
+ XDB_PUBLIC(int) xdb_verify_from_header(FILE *handle, xdb_header_t *);
124
+
125
+ XDB_PUBLIC(int) xdb_verify_from_file(const char *);
126
+
127
+ // --- End xdb buffer
128
+
129
+
130
+ // types type define
131
+ typedef char string_ip_t;
132
+ typedef unsigned char bytes_ip_t;
133
+
134
+ // --- ip version
135
+ #define XDB_IPv4 (xdb_version_v4())
136
+ #define XDB_IPv6 (xdb_version_v6())
137
+ typedef int (* ip_compare_fn_t) (const bytes_ip_t *, int, const char *, int);
138
+ struct xdb_ip_version_entry {
139
+ int id; // version id
140
+ char *name; // version name
141
+ int bytes; // ip bytes number
142
+ int segment_index_size; // segment index size in bytes
143
+
144
+ // function to compare two ips
145
+ ip_compare_fn_t ip_compare;
146
+ };
147
+ typedef struct xdb_ip_version_entry xdb_version_t;
148
+
149
+ XDB_PUBLIC(xdb_version_t *) xdb_version_v4();
150
+ XDB_PUBLIC(xdb_version_t *) xdb_version_v6();
151
+
152
+ XDB_PUBLIC(int) xdb_version_is_v4(const xdb_version_t *);
153
+ XDB_PUBLIC(int) xdb_version_is_v6(const xdb_version_t *);
154
+
155
+ XDB_PUBLIC(xdb_version_t *) xdb_version_from_name(char *);
156
+ XDB_PUBLIC(xdb_version_t *) xdb_version_from_header(xdb_header_t *);
157
+
158
+ // --- END ip version
159
+
160
+ // --- xdb util functions
161
+
162
+ // to compatiable with the windows
163
+ // returns: 0 for ok and -1 for failed
164
+ XDB_PUBLIC(int) xdb_init_winsock();
165
+ XDB_PUBLIC(void) xdb_clean_winsock();
166
+
167
+ // get the current time in microseconds
168
+ XDB_PUBLIC(long) xdb_now();
169
+
170
+ // get unsigned long (4bytes) from a specified buffer start from the specified offset with little-endian
171
+ XDB_PUBLIC(unsigned int) xdb_le_get_uint32(const char *, int);
172
+
173
+ // get unsigned short (2bytes) from a specified buffer start from the specified offset with little-endian
174
+ XDB_PUBLIC(int) xdb_le_get_uint16(const char *, int);
175
+
176
+
177
+ // parse the specified IP address to byte array.
178
+ // returns: xdb_version_t for valid ipv4 / ipv6, or NULL for failed
179
+ XDB_PUBLIC(xdb_version_t *) xdb_parse_ip(const string_ip_t *, bytes_ip_t *, size_t);
180
+
181
+ // parse the specified IPv4 address to byte array
182
+ // returns: xdb_version_t for valid ipv4, or NULL for failed
183
+ XDB_PUBLIC(xdb_version_t *) xdb_parse_v4_ip(const string_ip_t *, bytes_ip_t *, size_t);
184
+
185
+ // parse the specified IPv6 address to byte array
186
+ // returns: xdb_version_t for valid ipv6, or NULL for failed
187
+ XDB_PUBLIC(xdb_version_t *) xdb_parse_v6_ip(const string_ip_t *, bytes_ip_t *, size_t);
188
+
189
+ // convert a specified ip bytes to humen-readable string.
190
+ // returns: 0 for success or -1 for failed.
191
+ XDB_PUBLIC(int) xdb_ip_to_string(const bytes_ip_t *, int, char *, size_t);
192
+
193
+ // ipv4 bytes to string
194
+ XDB_PUBLIC(int) xdb_v4_ip_to_string(const bytes_ip_t *, char *, size_t);
195
+
196
+ // ipv6 bytes to string
197
+ XDB_PUBLIC(int) xdb_v6_ip_to_string(const bytes_ip_t *, char *, size_t);
198
+
199
+ // compare the specified ip bytes with another ip bytes in the specified buff from offset.
200
+ // ip args must be the return value from #xdb_parse_ip.
201
+ // returns: -1 if ip1 < ip2, 1 if ip1 > ip2 or 0
202
+ XDB_PUBLIC(int) xdb_ip_sub_compare(const bytes_ip_t *, int, const char *, int);
203
+
204
+ // --- END xdb utils
205
+
206
+
207
+ // --- xdb searcher api
208
+
209
+ // xdb region info structure
210
+ #define xdb_region_buffer_wrapper 1
211
+ #define xdb_region_buffer_auto 2
212
+ struct xdb_region_buffer_entry {
213
+ int type; // buffer type
214
+ char *value; // region value
215
+ size_t length; // buffer length
216
+ };
217
+ typedef struct xdb_region_buffer_entry xdb_region_buffer_t;
218
+
219
+ // wrapper the region from a local stack buffer.
220
+ // returns: 0 for succeed or failed
221
+ XDB_PUBLIC(int) xdb_region_buffer_init(xdb_region_buffer_t *, char *, size_t);
222
+
223
+ // do the buffer alloc.
224
+ // returns: 0 for ok or failed
225
+ XDB_PUBLIC(int) xdb_region_buffer_alloc(xdb_region_buffer_t *, int);
226
+
227
+ XDB_PUBLIC(void) xdb_region_buffer_free(xdb_region_buffer_t *);
228
+
229
+ // xdb searcher structure
230
+ struct xdb_searcher_entry {
231
+ // ip version
232
+ xdb_version_t *version;
233
+
234
+ // xdb file handle
235
+ FILE *handle;
236
+
237
+ // header info
238
+ const char *header;
239
+ int io_count;
240
+
241
+ // vector index buffer cache.
242
+ // preload the vector index will reduce the number of IO operations
243
+ // thus speedup the search process.
244
+ const xdb_vector_index_t *v_index;
245
+
246
+ // content buffer.
247
+ // cache the whole xdb content.
248
+ const xdb_content_t *content;
249
+ };
250
+ typedef struct xdb_searcher_entry xdb_searcher_t;
251
+
252
+ // xdb searcher new api define
253
+ XDB_PUBLIC(int) xdb_new_with_file_only(xdb_version_t *, xdb_searcher_t *, const char *);
254
+
255
+ XDB_PUBLIC(int) xdb_new_with_vector_index(xdb_version_t *, xdb_searcher_t *, const char *, const xdb_vector_index_t *);
256
+
257
+ XDB_PUBLIC(int) xdb_new_with_buffer(xdb_version_t *, xdb_searcher_t *, const xdb_content_t *);
258
+
259
+ XDB_PUBLIC(void) xdb_close(void *);
260
+
261
+ // xdb searcher search api define
262
+ XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *, const string_ip_t *, xdb_region_buffer_t *);
263
+
264
+ XDB_PUBLIC(int) xdb_search(xdb_searcher_t *, const bytes_ip_t *, int, xdb_region_buffer_t *);
265
+
266
+ XDB_PUBLIC(xdb_version_t *) xdb_get_version(xdb_searcher_t *);
267
+
268
+ XDB_PUBLIC(int) xdb_get_io_count(xdb_searcher_t *);
269
+
270
+ // --- END xdb searcher api
271
+
272
+ #endif // C_IP2REGION_XDB_H
@@ -0,0 +1,242 @@
1
+ // Copyright 2022 The Ip2Region Authors. All rights reserved.
2
+ // Use of this source code is governed by a Apache2.0-style
3
+ // license that can be found in the LICENSE file.
4
+
5
+ // ---
6
+ // @Author Lion <chenxin619315@gmail.com>
7
+ // @Date 2022/06/27
8
+
9
+ #include "xdb_api.h"
10
+
11
+ // --- region buffer
12
+ XDB_PUBLIC(int) xdb_region_buffer_init(xdb_region_buffer_t *region, char *buffer, size_t length) {
13
+ if (buffer == NULL) {
14
+ region->type = xdb_region_buffer_auto;
15
+ region->length = 0;
16
+ } else if (length <= 0) {
17
+ return 1;
18
+ } else {
19
+ region->type = xdb_region_buffer_wrapper;
20
+ region->length = length;
21
+ memset(buffer, 0x00, length); // zero-fill the buffer
22
+ }
23
+
24
+ region->value = buffer;
25
+ return 0;
26
+ }
27
+
28
+ XDB_PUBLIC(int) xdb_region_buffer_alloc(xdb_region_buffer_t *region, int length) {
29
+ if (length <= 0) {
30
+ return 1;
31
+ }
32
+
33
+ // no allocation supports for the buffer wapper
34
+ if (region->type == xdb_region_buffer_wrapper) {
35
+ if (length >= region->length) {
36
+ return 2;
37
+ }
38
+
39
+ region->value[length] = '\0';
40
+ return 0;
41
+ }
42
+
43
+ // ensure that the value were freed
44
+ // by calling #xdb_region_buffer_free
45
+ if (region->value != NULL) {
46
+ return 3;
47
+ }
48
+
49
+ char *ptr = (char *) xdb_malloc(length + 1);
50
+ if (ptr == NULL) {
51
+ return 4;
52
+ }
53
+
54
+ ptr[length] = '\0'; // NULL-end
55
+ region->value = ptr;
56
+ region->length = length;
57
+ return 0;
58
+ }
59
+
60
+ XDB_PUBLIC(void) xdb_region_buffer_free(xdb_region_buffer_t *region) {
61
+ if (region->type == xdb_region_buffer_auto) {
62
+ xdb_free(region->value);
63
+ region->value = NULL;
64
+ }
65
+ }
66
+
67
+ // --- END region buffer
68
+
69
+ // internal function prototype define
70
+ XDB_PRIVATE(int) read(xdb_searcher_t *, long offset, char *, size_t length);
71
+
72
+ XDB_PRIVATE(int) xdb_new_base(xdb_version_t *version, xdb_searcher_t *xdb, const char *db_path, const xdb_vector_index_t *v_index, const xdb_content_t *c_buffer) {
73
+ memset(xdb, 0x00, sizeof(xdb_searcher_t));
74
+
75
+ // set the version
76
+ xdb->version = version;
77
+
78
+ // check the content buffer first
79
+ if (c_buffer != NULL) {
80
+ xdb->v_index = NULL;
81
+ xdb->content = c_buffer;
82
+ return 0;
83
+ }
84
+
85
+ // open the xdb binary file
86
+ FILE *handle = fopen(db_path, "rb");
87
+ if (handle == NULL) {
88
+ return 1;
89
+ }
90
+
91
+ xdb->handle = handle;
92
+ xdb->v_index = v_index;
93
+
94
+ return 0;
95
+ }
96
+
97
+ // xdb searcher new api define
98
+ XDB_PUBLIC(int) xdb_new_with_file_only(xdb_version_t *version, xdb_searcher_t *xdb, const char *db_path) {
99
+ return xdb_new_base(version, xdb, db_path, NULL, NULL);
100
+ }
101
+
102
+ XDB_PUBLIC(int) xdb_new_with_vector_index(xdb_version_t *version, xdb_searcher_t *xdb, const char *db_path, const xdb_vector_index_t *v_index) {
103
+ return xdb_new_base(version, xdb, db_path, v_index, NULL);
104
+ }
105
+
106
+ XDB_PUBLIC(int) xdb_new_with_buffer(xdb_version_t *version, xdb_searcher_t *xdb, const xdb_content_t *c_buffer) {
107
+ return xdb_new_base(version, xdb, NULL, NULL, c_buffer);
108
+ }
109
+
110
+ XDB_PUBLIC(void) xdb_close(void *ptr) {
111
+ xdb_searcher_t *xdb = (xdb_searcher_t *) ptr;
112
+ if (xdb->handle != NULL) {
113
+ fclose(xdb->handle);
114
+ xdb->handle = NULL;
115
+ }
116
+ }
117
+
118
+ // --- xdb searcher search api define
119
+
120
+ XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *xdb, const string_ip_t *ip_string, xdb_region_buffer_t *region) {
121
+ bytes_ip_t ip_bytes[16] = {'\0'};
122
+ xdb_version_t *version = xdb_parse_ip(ip_string, ip_bytes, sizeof(ip_bytes));
123
+ if (version == NULL) {
124
+ return 10;
125
+ } else {
126
+ return xdb_search(xdb, ip_bytes, version->bytes, region);
127
+ }
128
+ }
129
+
130
+ XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int ip_len, xdb_region_buffer_t *region) {
131
+ int il0, il1, idx, err, bytes, d_bytes;
132
+ register int seg_index_size, l, h, m, p;
133
+ unsigned int s_ptr, e_ptr, data_ptr, data_len;
134
+ char vector_buffer[xdb_vector_index_size];
135
+ char segment_buffer[xdb_v6_index_size];
136
+
137
+ // ip version check
138
+ if (ip_len != xdb->version->bytes) {
139
+ return -1;
140
+ }
141
+
142
+ // some resets
143
+ err = 0;
144
+ data_len = 0;
145
+ bytes = xdb->version->bytes;
146
+ d_bytes = xdb->version->bytes << 1;
147
+ xdb->io_count = 0;
148
+
149
+ // locate the segment index block based on the vector index
150
+ il0 = (int) (ip_bytes[0]);
151
+ il1 = (int) (ip_bytes[1]);
152
+ idx = il0 * xdb_vector_index_cols * xdb_vector_index_size + il1 * xdb_vector_index_size;
153
+ if (xdb->v_index != NULL) {
154
+ s_ptr = xdb_le_get_uint32(xdb->v_index->buffer, idx);
155
+ e_ptr = xdb_le_get_uint32(xdb->v_index->buffer, idx + 4);
156
+ } else if (xdb->content != NULL) {
157
+ s_ptr = xdb_le_get_uint32(xdb->content->buffer, xdb_header_info_length + idx);
158
+ e_ptr = xdb_le_get_uint32(xdb->content->buffer, xdb_header_info_length + idx + 4);
159
+ } else {
160
+ err = read(xdb, xdb_header_info_length + idx, vector_buffer, sizeof(vector_buffer));
161
+ if (err != 0) {
162
+ return 10 + err;
163
+ }
164
+
165
+ s_ptr = xdb_le_get_uint32(vector_buffer, 0);
166
+ e_ptr = xdb_le_get_uint32(vector_buffer, 4);
167
+ }
168
+
169
+ // printf("s_ptr=%u, e_ptr=%u\n", s_ptr, e_ptr);
170
+ // binary search to get the final region info
171
+ // segment_buffer = xdb_malloc(seg_index_size);
172
+ seg_index_size = xdb->version->segment_index_size;
173
+ data_len = 0, data_ptr = 0;
174
+ l = 0, h = ((int) (e_ptr - s_ptr)) / seg_index_size;
175
+ while (l <= h) {
176
+ m = (l + h) >> 1;
177
+ p = s_ptr + m * seg_index_size;
178
+
179
+ // read the segment index item
180
+ err = read(xdb, p, segment_buffer, seg_index_size);
181
+ if (err != 0) {
182
+ return 20 + err;
183
+ }
184
+
185
+ // decode the data fields as needed
186
+ if (xdb->version->ip_compare(ip_bytes, bytes, segment_buffer, 0) < 0) {
187
+ h = m - 1;
188
+ } else if (xdb->version->ip_compare(ip_bytes, bytes, segment_buffer, bytes) > 0) {
189
+ l = m + 1;
190
+ } else {
191
+ data_len = xdb_le_get_uint16(segment_buffer, d_bytes);
192
+ data_ptr = xdb_le_get_uint32(segment_buffer, d_bytes + 2);
193
+ break;
194
+ }
195
+ }
196
+
197
+ // printf("data_len=%u, data_ptr=%u\n", data_len, data_ptr);
198
+ if (data_len == 0) {
199
+ return 100;
200
+ }
201
+
202
+ // buffer alloc checking
203
+ err = xdb_region_buffer_alloc(region, data_len);
204
+ if (err != 0) {
205
+ return 100 + err;
206
+ }
207
+
208
+ err = read(xdb, data_ptr, region->value, data_len);
209
+ if (err != 0) {
210
+ return 30 + err;
211
+ }
212
+
213
+ return err;
214
+ }
215
+
216
+ XDB_PRIVATE(int) read(xdb_searcher_t *xdb, long offset, char *buffer, size_t length) {
217
+ // check the xdb content cache first
218
+ if (xdb->content != NULL) {
219
+ memcpy(buffer, xdb->content->buffer + offset, length);
220
+ return 0;
221
+ }
222
+
223
+ // seek to the offset
224
+ if (fseek(xdb->handle, offset, SEEK_SET) == -1) {
225
+ return 1;
226
+ }
227
+
228
+ xdb->io_count++;
229
+ if (fread(buffer, 1, length, xdb->handle) != length) {
230
+ return 2;
231
+ }
232
+
233
+ return 0;
234
+ }
235
+
236
+ XDB_PUBLIC(xdb_version_t *) xdb_get_version(xdb_searcher_t *xdb) {
237
+ return xdb->version;
238
+ }
239
+
240
+ XDB_PUBLIC(int) xdb_get_io_count(xdb_searcher_t *xdb) {
241
+ return xdb->io_count;
242
+ }