mirror of
https://github.com/lionsoul2014/ip2region.git
synced 2025-12-08 19:25:22 +00:00
IPv6 search and docs is ready
This commit is contained in:
parent
73c8b20d3a
commit
8fbdf82797
@ -3,6 +3,40 @@
|
||||
|
||||
# 使用方式
|
||||
|
||||
### 关于 IPv4 和 IPv6
|
||||
该 xdb 查询客户端实现同时支持对 IPv4 和 IPv6 的查询,使用方式如下:
|
||||
```c
|
||||
#include "xdb_api.h";
|
||||
|
||||
// 如果是 IPv4: 设置 xdb 路径为 v4 的 xdb 文件,IP版本指定为 IPv4
|
||||
const char *db_path = "../../data/ip2region_v4.xdb"; // 或者你的 ipv4 xdb 的路径
|
||||
xdb_version_t *version = XDB_IPv4;
|
||||
|
||||
// 如果是 IPv6: 设置 xdb 路径为 v6 的 xdb 文件,IP版本指定为 IPv6
|
||||
const char *db_path = "../../data/ip2region_v6.xdb"; // 或者你的 ipv6 xdb 路径
|
||||
xdb_version_t *version = XDB_IPv6;
|
||||
|
||||
// db_path 指定的 xdb 的 IP 版本必须和 version 指定的一致,不然查询执行的时候会报错
|
||||
// 备注:以下演示直接使用 db_path 和 version 变量
|
||||
```
|
||||
|
||||
### XDB 文件验证
|
||||
建议您主动去验证 xdb 文件的适用性,因为后期的一些新功能可能会导致目前的 Searcher 版本无法适用你使用的 xdb 文件,验证可以避免运行过程中的一些不可预测的错误。 你不需要每次都去验证,例如在服务启动的时候,或者手动调用命令验证确认版本匹配即可,不要在每次创建的 Searcher 的时候运行验证,这样会影响查询的响应速度,尤其是高并发的使用场景。
|
||||
```c
|
||||
#include "xdb_api.h";
|
||||
|
||||
int errcode = xdb_verify(db_path);
|
||||
if ($err != 0) {
|
||||
// 适用性验证失败!!!
|
||||
// 当前查询客户端实现不适用于 db_path 指定的 xdb 文件的查询.
|
||||
// 应该停止启动服务,使用合适的 xdb 文件或者升级到适合 db_path 的 Searcher 实现。
|
||||
printf("failed to verify xdb file `%s`, errcode: %d\n", db_path, errcode);
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证通过,当前使用的 Searcher 可以安全的用于对 dbPath 指向的 xdb 的查询操作
|
||||
```
|
||||
|
||||
### 完全基于文件的查询
|
||||
|
||||
```c
|
||||
@ -10,32 +44,43 @@
|
||||
#include "xdb_api.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *db_path = "ip2region.xdb file path";
|
||||
xdb_searcher_t searcher;
|
||||
char region_buffer[256], ip_buffer[16], *ip = "1.2.3.4";
|
||||
long s_time;
|
||||
char region_buffer[512] = {'\0'};
|
||||
|
||||
// 1、从 db_path 初始化 xdb 查询对象
|
||||
int err = xdb_new_with_file_only(&searcher, db_path);
|
||||
// 在服务启动的时候初始化 winsock,不需要重复调用,只需要在 windows 系统下调用
|
||||
int err = xdb_init_winsock();
|
||||
if (err != 0) {
|
||||
printf("failed to init the winsock with errno=%d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 1、从 db_path 初始化 xdb 查询对象.
|
||||
// @Note: 使用顶部描述的 db_path 和 version 来创建 searcher
|
||||
err = xdb_new_with_file_only(version, &searcher, db_path);
|
||||
if (err != 0) {
|
||||
printf("failed to create xdb searcher from `%s` with errno=%d\n", db_path, err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 2、调用 search API 查询
|
||||
// 2、调用 search API 查询,IPv4 和 IPv6 都支持.
|
||||
// 得到的 region 信息会存储到 region_buffer 里面,如果你自定义了数据,请确保给足 buffer 的空间。
|
||||
s_time = xdb_now();
|
||||
err = xdb_search_by_string(&searcher, ip, region_buffer, sizeof(region_buffer));
|
||||
const char *ip_string = "1.2.3.4";
|
||||
// ip_string = "2001:4:112:ffff:ffff:ffff:ffff:ffff"; // IPv6
|
||||
|
||||
long cost_time = 0, s_time = xdb_now();
|
||||
err = xdb_search_by_string(&searcher, ip_string, region_buffer, sizeof(region_buffer));
|
||||
cost_time = (int) (xdb_now() - s_time);
|
||||
if (err != 0) {
|
||||
printf("failed search(%s) with errno=%d\n", ip, err);
|
||||
printf("failed search(%s) with errno=%d\n", ip_string, err);
|
||||
} else {
|
||||
printf("{region: %s, took: %d μs}", region_buffer, (int)(xdb_now() - s_time));
|
||||
printf("{region: %s, took: %d μs}", region_buffer, cost_time);
|
||||
}
|
||||
|
||||
// 备注:并发使用,没一个线程需要单独定义并且初始化一个 searcher 查询对象。
|
||||
// 备注:并发使用,每一个线程需要单独定义并且初始化一个 searcher 查询对象。
|
||||
|
||||
// 3、关闭 xdb 查询器
|
||||
xdb_close(&searcher);
|
||||
xdb_clean_winsock(); // windows 下调用
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
@ -48,13 +93,18 @@ int main(int argc, char *argv[]) {
|
||||
#include "xdb_api.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *db_path = "ip2region.xdb file path";
|
||||
xdb_vector_index_t *v_index;
|
||||
xdb_searcher_t searcher;
|
||||
char region_buffer[256], ip_buffer[16], *ip = "1.2.3.4";
|
||||
long s_time;
|
||||
char region_buffer[512];
|
||||
|
||||
// 1、从 db_path 加载 VectorIndex 索引。
|
||||
// 在服务启动的时候初始化 winsock,不需要重复调用,只需要在 windows 系统下调用
|
||||
int err = xdb_init_winsock();
|
||||
if (err != 0) {
|
||||
printf("failed to init the winsock with errno=%d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 1、从顶部描述的 db_path 加载 VectorIndex 索引。
|
||||
// 得到 v_index 做成全局缓存,便于后续反复使用。
|
||||
// 注意:v_index 不需要每次都加载,建议在服务启动的时候加载一次,然后做成全局资源。
|
||||
v_index = xdb_load_vector_index_from_file(db_path);
|
||||
@ -63,68 +113,86 @@ int main(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 2、使用全局的 VectorIndex 变量创建带 VectorIndex 缓存的 xdb 查询对象
|
||||
int err = xdb_new_with_vector_index(&searcher, db_path, v_index);
|
||||
// 2、使用全局的 VectorIndex 变量创建带 VectorIndex 缓存的 xdb 查询对象.
|
||||
// @Note: 使用顶部描述的 db_path 和 version 来创建 searcher
|
||||
err = xdb_new_with_vector_index(version, &searcher, db_path, v_index);
|
||||
if (err != 0) {
|
||||
printf("failed to create vector index cached searcher with errcode=%d\n", err);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// 3、调用 search API 查询
|
||||
|
||||
// 3、调用 search API 查询,IPv4 和 IPv6 都支持
|
||||
// 得到的 region 信息会存储到 region_buffer 里面,如果你自定义了数据,请确保给足 buffer 的空间。
|
||||
s_time = xdb_now();
|
||||
err = xdb_search_by_string(&searcher, ip, region_buffer, sizeof(region_buffer));
|
||||
const char *ip_string = "1.2.3.4";
|
||||
// ip_string = "2001:4:112:ffff:ffff:ffff:ffff:ffff"; // IPv6
|
||||
|
||||
long cost_time = 0, s_time = xdb_now();
|
||||
err = xdb_search_by_string(&searcher, ip_string, region_buffer, sizeof(region_buffer));
|
||||
cost_time = (int) (xdb_now() - s_time);
|
||||
if (err != 0) {
|
||||
printf("failed search(%s) with errno=%d\n", ip, err);
|
||||
printf("failed search(%s) with errno=%d\n", ip_string, err);
|
||||
} else {
|
||||
printf("{region: %s, took: %d μs}", region_buffer, (int)(xdb_now() - s_time));
|
||||
printf("{region: %s, took: %d μs}", region_buffer, cost_time);
|
||||
}
|
||||
|
||||
// 备注:并发使用,没一个线程需要单独定义并且初始化一个 searcher 查询对象。
|
||||
// 备注:并发使用,每一个线程需要单独定义并且初始化一个 searcher 查询对象。
|
||||
|
||||
// 4、关闭 xdb 查询器,如果是要关闭服务,也需要释放 v_index 的内存。
|
||||
xdb_close(&searcher);
|
||||
xdb_close_vector_index(v_index);
|
||||
xdb_clean_winsock();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 缓存整个 `xdb` 数据
|
||||
|
||||
我们也可以预先加载整个 ip2region.xdb 的数据到内存,然后基于这个数据创建查询对象来实现完全基于文件的查询,类似之前的 memory search。
|
||||
我们也可以预先加载整个 xdb 文件到内存,然后基于这个数据创建查询对象来实现完全基于内存的查询,类似之前的 memory search。
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include "xdb_api.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *db_path = "ip2region.xdb file path";
|
||||
xdb_content_t *c_buffer;
|
||||
xdb_searcher_t searcher;
|
||||
char region_buffer[256], ip_buffer[16], *ip = "1.2.3.4";
|
||||
long s_time;
|
||||
char region_buffer[512] = {'\0'};
|
||||
|
||||
// 1、从 db_path 加载整个 xdb 的数据。
|
||||
|
||||
// 在服务启动的时候初始化 winsock,不需要重复调用,只需要在 windows 系统下调用
|
||||
int err = xdb_init_winsock();
|
||||
if (err != 0) {
|
||||
printf("failed to init the winsock with errno=%d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 1、从 顶部描述的 db_path 加载整个 xdb 的数据。
|
||||
c_buffer = xdb_load_content_from_file(db_path);
|
||||
if (v_index == NULL) {
|
||||
printf("failed to load xdb content from `%s`\n", db_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 2、使用全局的 c_buffer 变量创建一个完全基于内存的 xdb 查询对象
|
||||
err = xdb_new_with_buffer(&searcher, c_buffer);
|
||||
// 2、使用全局的 c_buffer 变量创建一个完全基于内存的 xdb 查询对象.
|
||||
// @Note: 使用顶部描述的 version 来创建 searcher.
|
||||
err = xdb_new_with_buffer(version, &searcher, c_buffer);
|
||||
if (err != 0) {
|
||||
printf("failed to create content cached searcher with errcode=%d\n", err);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// 3、调用 search API 查询
|
||||
// 3、调用 search API 查询,IPv4 和 IPv6 都支持
|
||||
// 得到的 region 信息会存储到 region_buffer 里面,如果你自定义了数据,请确保给足 buffer 的空间。
|
||||
s_time = xdb_now();
|
||||
err = xdb_search_by_string(&searcher, ip, region_buffer, sizeof(region_buffer));
|
||||
const char *ip_string = "1.2.3.4";
|
||||
// ip_string = "2001:4:112:ffff:ffff:ffff:ffff:ffff"; // IPv6
|
||||
|
||||
long cost_time = 0, s_time = xdb_now();
|
||||
err = xdb_search_by_string(&searcher, ip_string, region_buffer, sizeof(region_buffer));
|
||||
cost_time = (int) (xdb_now() - s_time);
|
||||
if (err != 0) {
|
||||
printf("failed search(%s) with errno=%d\n", ip, err);
|
||||
printf("failed search(%s) with errno=%d\n", ip_string, err);
|
||||
} else {
|
||||
printf("{region: %s, took: %d μs}", region_buffer, (int)(xdb_now() - s_time));
|
||||
printf("{region: %s, took: %d μs}", region_buffer, cost_time);
|
||||
}
|
||||
|
||||
// 备注:并发使用,使用这种方式创建的 xdb 查询对象可以安全用于并发。
|
||||
@ -133,6 +201,7 @@ int main(int argc, char *argv[]) {
|
||||
// 4、关闭 xdb 查询器,关闭服务的时候需要释放 c_buffer 的内存。
|
||||
xdb_close(&searcher);
|
||||
xdb_close_content(c_buffer);
|
||||
xdb_clean_winsock();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
@ -143,29 +212,43 @@ int main(int argc, char *argv[]) {
|
||||
通过如下方式编译得到 xdb_searcher 可执行程序:
|
||||
```bash
|
||||
# cd 到 c binding 根目录
|
||||
make
|
||||
➜ c git:(fr_c_ipv6) ✗ make
|
||||
gcc -O2 -I./ xdb_util.c xdb_searcher.c main.c -o xdb_searcher
|
||||
gcc -O2 -I./ xdb_util.c test_util.c -o test_util
|
||||
```
|
||||
|
||||
|
||||
# 查询测试
|
||||
|
||||
通过 `xdb_searcher search` 命令来测试对 ip2region.xdb 的查询:
|
||||
通过 `xdb_searcher search` 命令来测试对 xdb 的查询:
|
||||
```bash
|
||||
➜ c git:(c_binding) ✗ ./xdb_searcher search
|
||||
➜ c git:(fr_c_ipv6) ✗ ./xdb_searcher search
|
||||
./xdb_searcher search [command options]
|
||||
options:
|
||||
--db string ip2region binary xdb file path
|
||||
--cache-policy string cache policy: file/vectorIndex/content
|
||||
```
|
||||
|
||||
例如:使用默认的 data/ip2region.xdb 进行查询测试:
|
||||
例如:使用默认的 data/ip2region_v4.xdb 进行 IPv4 查询测试:
|
||||
```bash
|
||||
➜ c git:(c_binding) ✗ ./xdb_searcher search --db=../../data/ip2region.xdb --cache-policy=vectorIndex
|
||||
ip2region xdb searcher test program, cache_policy: vectorIndex
|
||||
➜ c git:(fr_c_ipv6) ✗ ./xdb_searcher search --db=../../data/ip2region_v4.xdb
|
||||
ip2region xdb searcher test program
|
||||
source xdb: ../../data/ip2region_v4.xdb (IPv4, vectorIndex)
|
||||
type 'quit' to exit
|
||||
ip2region>> 1.2.3.4
|
||||
{region: 美国|0|华盛顿|0|谷歌, io_count: 7, took: 13 μs}
|
||||
ip2region>>
|
||||
ip2region>> 120.229.45.2
|
||||
{region: 中国|广东省|深圳市|移动, io_count: 3, took: 29 μs}
|
||||
```
|
||||
|
||||
例如:使用默认的 data/ip2region_v6.xdb 进行 IPv6 查询测试:
|
||||
```bash
|
||||
➜ c git:(fr_c_ipv6) ✗ ./xdb_searcher search --db=../../data/ip2region_v6.xdb
|
||||
ip2region xdb searcher test program
|
||||
source xdb: ../../data/ip2region_v6.xdb (IPv6, vectorIndex)
|
||||
type 'quit' to exit
|
||||
ip2region>> ::
|
||||
{region: |||, io_count: 2, took: 38 μs}
|
||||
ip2region>> 2604:bc80:8001:11a4:ffff:ffff:ffff:ffff
|
||||
{region: 中国|广东省|深圳市|数据中心, io_count: 13, took: 77 μs}
|
||||
```
|
||||
|
||||
输入 ip 即可进行查询,输入 quit 即可退出测试程序。也可以分别设置 `cache-policy` 为 file/vectorIndex/content 来测试三种不同的缓存实现的效率。
|
||||
@ -176,7 +259,7 @@ ip2region>>
|
||||
|
||||
通过 `xdb_searcher bench` 命令来进行 bench 测试,一方面确保查询程序和 `xdb` 文件没有错误,另一方面可以通过大量的查询得到评价的查询性能:
|
||||
```bash
|
||||
➜ c git:(c_binding) ✗ ./xdb_searcher bench
|
||||
➜ c git:(fr_c_ipv6) ✗ ./xdb_searcher bench
|
||||
./xdb_searcher bench [command options]
|
||||
options:
|
||||
--db string ip2region binary xdb file path
|
||||
@ -184,10 +267,16 @@ options:
|
||||
--cache-policy string cache policy: file/vectorIndex/content
|
||||
```
|
||||
|
||||
例如:通过默认的 data/ip2region.xdb 和 data/ip.merge.txt 来进行 bench 测试:
|
||||
例如:通过默认的 data/ip2region_v4.xdb 和 data/ipv4_source.txt 来进行 IPv4 的 bench 测试:
|
||||
```bash
|
||||
➜ c git:(c_binding) ✗ ./xdb_searcher bench --db=../../data/ip2region.xdb --src=../../data/ip.merge.txt --cache-policy=vectorIndex
|
||||
Bench finished, {cache_policy: vectorIndex, total: 3417955, took: 4.233s, cost: 1 μs/op}
|
||||
➜ c git:(fr_c_ipv6) ✗ ./xdb_searcher bench --db=../../data/ip2region_v4.xdb --src=../../data/ipv4_source.txt
|
||||
Bench finished, {cache_policy: vectorIndex, total: 1367686, took: 7.640s, cost: 5 μs/op}
|
||||
```
|
||||
|
||||
例如:通过默认的 data/ip2region_v6.xdb 和 data/ipv6_source.txt 来进行 IPv6 的 bench 测试:
|
||||
```bash
|
||||
➜ c git:(fr_c_ipv6) ✗ ./xdb_searcher bench --db=../../data/ip2region_v6.xdb --src=../../data/ipv6_source.txt
|
||||
Bench finished, {cache_policy: vectorIndex, total: 34159862, took: 857.750s, cost: 24 μs/op}
|
||||
```
|
||||
|
||||
可以设置 `cache-policy` 参数来分别测试 file/vectorIndex/content 不同缓存实现机制的效率。 @Note:请注意 bench 使用的 src 文件需要是生成对应的 xdb 文件相同的源文件。
|
||||
|
||||
@ -18,7 +18,22 @@ typedef struct searcher_test_entry searcher_test_t;
|
||||
|
||||
int init_searcher_test(searcher_test_t *test, char *db_path, char *cache_policy) {
|
||||
int err;
|
||||
xdb_ip_version_t *version = XDB_IPv4;
|
||||
|
||||
// auto detect the version from the xdb header
|
||||
xdb_header_t *header = xdb_load_header_from_file(db_path);
|
||||
if (header == NULL) {
|
||||
printf("failed to load header from `%s`\n", db_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
xdb_version_t *version = xdb_version_from_header(header);
|
||||
if (version == NULL) {
|
||||
printf("failed to load version from header\n");
|
||||
xdb_free_header(header);
|
||||
return 1;
|
||||
}
|
||||
|
||||
xdb_free_header(header);
|
||||
test->v_index = NULL;
|
||||
test->c_buffer = NULL;
|
||||
|
||||
@ -112,7 +127,7 @@ void test_search(int argc, char *argv[]) {
|
||||
char line[512] = {'\0'}, region[512] = {'\0'};
|
||||
|
||||
// ip parse
|
||||
xdb_ip_version_t *version;
|
||||
xdb_version_t *version;
|
||||
bytes_ip_t ip_bytes[16] = {'\0'};
|
||||
|
||||
searcher_test_t test;
|
||||
@ -158,6 +173,13 @@ void test_search(int argc, char *argv[]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// init the win sock
|
||||
err = xdb_init_winsock();
|
||||
if (err != 0) {
|
||||
printf("failed to init the winsock with errno=%d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
// printf("db_file=%s, cache_policy=%s\n", db_file, cache_policy);
|
||||
err = init_searcher_test(&test, db_file, cache_policy);
|
||||
if (err != 0) {
|
||||
@ -165,8 +187,9 @@ void test_search(int argc, char *argv[]) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("ip2region xdb searcher test program, "
|
||||
"cache_policy: %s\ntype 'quit' to exit\n", cache_policy);
|
||||
printf("ip2region xdb searcher test program\n"
|
||||
"source xdb: %s (%s, %s)\n"
|
||||
"type 'quit' to exit\n", db_file, xdb_get_version(&test.searcher)->name, cache_policy);
|
||||
while ( 1 ) {
|
||||
printf("ip2region>> ");
|
||||
get_line(stdin, line);
|
||||
@ -195,6 +218,7 @@ void test_search(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
destroy_searcher_test(&test);
|
||||
xdb_clean_winsock();
|
||||
printf("searcher test program exited, thanks for trying\n");
|
||||
}
|
||||
|
||||
@ -204,19 +228,18 @@ void test_bench(int argc, char *argv[]) {
|
||||
char db_file[256] = {'\0'}, src_file[256] = {'\0'}, cache_policy[16] = {"vectorIndex"};
|
||||
|
||||
FILE *handle;
|
||||
char line[1024] = {'\0'}, sip_str[16] = {'\0'}, eip_str[16] = {'\0'};
|
||||
char line[1024] = {'\0'}, sip_str[INET6_ADDRSTRLEN+1] = {'\0'}, eip_str[INET6_ADDRSTRLEN+1] = {'\0'};
|
||||
char src_region[512] = {'\0'}, region_buffer[512] = {'\0'};
|
||||
int count = 0, took;
|
||||
long s_time, t_time, c_time = 0;
|
||||
|
||||
// ip parse
|
||||
xdb_ip_version_t *s_version, *e_version;
|
||||
xdb_version_t *s_version, *e_version;
|
||||
bytes_ip_t sip_bytes[16] = {'\0'}, eip_bytes[16] = {'\0'};
|
||||
string_ip_t ip_string[INET6_ADDRSTRLEN] = {'\0'};
|
||||
bytes_ip_t *ip_list[2];
|
||||
|
||||
searcher_test_t test;
|
||||
|
||||
for (i = 2; i < argc; i++) {
|
||||
r = argv[i];
|
||||
if (strlen(r) < 5) {
|
||||
@ -259,6 +282,13 @@ void test_bench(int argc, char *argv[]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// init the win sock
|
||||
err = xdb_init_winsock();
|
||||
if (err != 0) {
|
||||
printf("failed to init the winsock with errno=%d\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
// printf("db_file=%s, src_file=%s, cache_policy=%s\n", db_file, src_file, cache_policy);
|
||||
s_time = xdb_now();
|
||||
err = init_searcher_test(&test, db_file, cache_policy);
|
||||
@ -275,7 +305,7 @@ void test_bench(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
while(fgets(line, sizeof(line), handle) != NULL) {
|
||||
n = sscanf(line, "%15[^|]|%15[^|]|%511[^\n]", sip_str, eip_str, src_region);
|
||||
n = sscanf(line, "%46[^|]|%46[^|]|%511[^\n]", sip_str, eip_str, src_region);
|
||||
if (n != 3) {
|
||||
printf("invalid ip segment line `%s`\n", line);
|
||||
return;
|
||||
@ -328,6 +358,7 @@ void test_bench(int argc, char *argv[]) {
|
||||
|
||||
took = xdb_now() - s_time;
|
||||
destroy_searcher_test(&test);
|
||||
xdb_clean_winsock();
|
||||
fclose(handle);
|
||||
printf("Bench finished, {cache_policy: %s, total: %d, took: %.3fs, cost: %d μs/op}\n",
|
||||
cache_policy, count, took/1e6, count == 0 ? 0 : (int)(c_time/count));
|
||||
|
||||
Binary file not shown.
@ -27,10 +27,13 @@ void test_load_header() {
|
||||
" created_at: %u, \n"
|
||||
" start_index_ptr: %d, \n"
|
||||
" end_index_ptr: %d\n"
|
||||
" ip_version: %d\n"
|
||||
" runtime_ptr_bytes: %d\n"
|
||||
" length: %d\n"
|
||||
"}\n",
|
||||
header->version, header->index_policy, header->created_at,
|
||||
header->start_index_ptr, header->end_index_ptr, header->length
|
||||
header->start_index_ptr, header->end_index_ptr,
|
||||
header->ip_version, header->runtime_ptr_bytes, header->length
|
||||
);
|
||||
}
|
||||
|
||||
@ -68,7 +71,7 @@ void test_parse_ip() {
|
||||
};
|
||||
|
||||
int errcode;
|
||||
xdb_ip_version_t *version;
|
||||
xdb_version_t *version;
|
||||
bytes_ip_t ip_bytes[16] = {'\0'};
|
||||
string_ip_t ip_string[INET6_ADDRSTRLEN] = {'\0'};
|
||||
|
||||
@ -117,7 +120,7 @@ void test_ip_compare() {
|
||||
struct ip_pair *pair_ptr = NULL;
|
||||
bytes_ip_t sip_bytes[16] = {'\0'};
|
||||
bytes_ip_t eip_bytes[16] = {'\0'};
|
||||
xdb_ip_version_t *s_version, *e_version;
|
||||
xdb_version_t *s_version, *e_version;
|
||||
int bytes, errcode;
|
||||
|
||||
// init the sock env (for windows)
|
||||
|
||||
@ -35,6 +35,8 @@
|
||||
#define xdb_free( _ptr ) free( _ptr )
|
||||
|
||||
// public constants define
|
||||
#define xdb_structure_20 2
|
||||
#define xdb_structure_30 3
|
||||
#define xdb_header_info_length 256
|
||||
#define xdb_vector_index_rows 256
|
||||
#define xdb_vector_index_cols 256
|
||||
@ -42,93 +44,13 @@
|
||||
#define xdb_segment_index_size 14
|
||||
|
||||
// --- ip version info
|
||||
#define xdb_ipv4_version_no 4
|
||||
#define xdb_ipv6_version_no 6
|
||||
#define xdb_ipv4_id 4
|
||||
#define xdb_ipv6_id 6
|
||||
#define xdb_ipv4_bytes 4
|
||||
#define xdb_ipv6_bytes 16
|
||||
// cache of vector_index_row × vector_index_rows × vector_index_size
|
||||
#define xdb_vector_index_length 524288
|
||||
|
||||
// types type define
|
||||
typedef char string_ip_t;
|
||||
typedef unsigned char bytes_ip_t;
|
||||
|
||||
// --- ip version
|
||||
#define XDB_IPv4 (xdb_version_ipv4())
|
||||
#define XDB_IPv6 (xdb_version_ipv6())
|
||||
typedef int (* ip_compare_fn_t) (const bytes_ip_t *, int, const char *, int);
|
||||
struct xdb_ip_version_entry {
|
||||
int id; // version id
|
||||
char *name; // version name
|
||||
int bytes; // ip bytes number
|
||||
int segment_index_size; // segment index size in bytes
|
||||
|
||||
// function to compare two ips
|
||||
ip_compare_fn_t ip_compare;
|
||||
};
|
||||
typedef struct xdb_ip_version_entry xdb_ip_version_t;
|
||||
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_version_ipv4();
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_version_ipv6();
|
||||
|
||||
XDB_PUBLIC(int) xdb_ip_version_is_v4(const xdb_ip_version_t *);
|
||||
XDB_PUBLIC(int) xdb_ip_version_is_v6(const xdb_ip_version_t *);
|
||||
|
||||
// --- END ip version
|
||||
|
||||
// --- xdb util functions
|
||||
|
||||
// to compatiable with the windows
|
||||
// returns: 0 for ok and -1 for failed
|
||||
XDB_PUBLIC(int) xdb_init_winsock();
|
||||
XDB_PUBLIC(void) xdb_clean_winsock();
|
||||
|
||||
// get the current time in microseconds
|
||||
XDB_PUBLIC(long) xdb_now();
|
||||
|
||||
// get unsigned long (4bytes) from a specified buffer start from the specified offset with little-endian
|
||||
XDB_PUBLIC(unsigned int) xdb_le_get_uint32(const char *, int);
|
||||
|
||||
// get unsigned short (2bytes) from a specified buffer start from the specified offset with little-endian
|
||||
XDB_PUBLIC(int) xdb_le_get_uint16(const char *, int);
|
||||
|
||||
// check the specified string ip and convert it to an unsigned int
|
||||
XDB_PUBLIC(int) xdb_check_ip(const char *, unsigned int *);
|
||||
|
||||
// unsigned int ip to string ip
|
||||
XDB_PUBLIC(void) xdb_long2ip(unsigned int, char *);
|
||||
|
||||
|
||||
// parse the specified IP address to byte array.
|
||||
// returns: xdb_ip_version_t for valid ipv4 / ipv6, or NULL for failed
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_parse_ip(const string_ip_t *, bytes_ip_t *, size_t);
|
||||
|
||||
// parse the specified IPv4 address to byte array
|
||||
// returns: xdb_ip_version_t for valid ipv4, or NULL for failed
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_parse_v4_ip(const string_ip_t *, bytes_ip_t *, size_t);
|
||||
|
||||
// parse the specified IPv6 address to byte array
|
||||
// returns: xdb_ip_version_t for valid ipv6, or NULL for failed
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_parse_v6_ip(const string_ip_t *, bytes_ip_t *, size_t);
|
||||
|
||||
// convert a specified ip bytes to humen-readable string.
|
||||
// returns: 0 for success or -1 for failed.
|
||||
XDB_PUBLIC(int) xdb_ip_to_string(const bytes_ip_t *, int, char *, size_t);
|
||||
|
||||
// ipv4 bytes to string
|
||||
XDB_PUBLIC(int) xdb_v4_ip_to_string(const bytes_ip_t *, char *, size_t);
|
||||
|
||||
// ipv6 bytes to string
|
||||
XDB_PUBLIC(int) xdb_v6_ip_to_string(const bytes_ip_t *, char *, size_t);
|
||||
|
||||
// compare the specified ip bytes with another ip bytes in the specified buff from offset.
|
||||
// ip args must be the return value from #xdb_parse_ip.
|
||||
// returns: -1 if ip1 < ip2, 1 if ip1 > ip2 or 0
|
||||
XDB_PUBLIC(int) xdb_ip_sub_compare(const bytes_ip_t *, int, const char *, int);
|
||||
|
||||
// --- END xdb utils
|
||||
|
||||
|
||||
// --- xdb buffer functions
|
||||
|
||||
// use the following buffer struct to wrap the binary buffer data
|
||||
@ -186,12 +108,90 @@ XDB_PUBLIC(void) xdb_free_content(void *);
|
||||
|
||||
// --- End xdb buffer
|
||||
|
||||
|
||||
// types type define
|
||||
typedef char string_ip_t;
|
||||
typedef unsigned char bytes_ip_t;
|
||||
|
||||
// --- ip version
|
||||
#define XDB_IPv4 (xdb_version_v4())
|
||||
#define XDB_IPv6 (xdb_version_v6())
|
||||
typedef int (* ip_compare_fn_t) (const bytes_ip_t *, int, const char *, int);
|
||||
struct xdb_ip_version_entry {
|
||||
int id; // version id
|
||||
char *name; // version name
|
||||
int bytes; // ip bytes number
|
||||
int segment_index_size; // segment index size in bytes
|
||||
|
||||
// function to compare two ips
|
||||
ip_compare_fn_t ip_compare;
|
||||
};
|
||||
typedef struct xdb_ip_version_entry xdb_version_t;
|
||||
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_version_v4();
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_version_v6();
|
||||
|
||||
XDB_PUBLIC(int) xdb_version_is_v4(const xdb_version_t *);
|
||||
XDB_PUBLIC(int) xdb_version_is_v6(const xdb_version_t *);
|
||||
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_version_from_name(char *);
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_version_from_header(xdb_header_t *);
|
||||
|
||||
// --- END ip version
|
||||
|
||||
// --- xdb util functions
|
||||
|
||||
// to compatiable with the windows
|
||||
// returns: 0 for ok and -1 for failed
|
||||
XDB_PUBLIC(int) xdb_init_winsock();
|
||||
XDB_PUBLIC(void) xdb_clean_winsock();
|
||||
|
||||
// get the current time in microseconds
|
||||
XDB_PUBLIC(long) xdb_now();
|
||||
|
||||
// get unsigned long (4bytes) from a specified buffer start from the specified offset with little-endian
|
||||
XDB_PUBLIC(unsigned int) xdb_le_get_uint32(const char *, int);
|
||||
|
||||
// get unsigned short (2bytes) from a specified buffer start from the specified offset with little-endian
|
||||
XDB_PUBLIC(int) xdb_le_get_uint16(const char *, int);
|
||||
|
||||
|
||||
// parse the specified IP address to byte array.
|
||||
// returns: xdb_version_t for valid ipv4 / ipv6, or NULL for failed
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_parse_ip(const string_ip_t *, bytes_ip_t *, size_t);
|
||||
|
||||
// parse the specified IPv4 address to byte array
|
||||
// returns: xdb_version_t for valid ipv4, or NULL for failed
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_parse_v4_ip(const string_ip_t *, bytes_ip_t *, size_t);
|
||||
|
||||
// parse the specified IPv6 address to byte array
|
||||
// returns: xdb_version_t for valid ipv6, or NULL for failed
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_parse_v6_ip(const string_ip_t *, bytes_ip_t *, size_t);
|
||||
|
||||
// convert a specified ip bytes to humen-readable string.
|
||||
// returns: 0 for success or -1 for failed.
|
||||
XDB_PUBLIC(int) xdb_ip_to_string(const bytes_ip_t *, int, char *, size_t);
|
||||
|
||||
// ipv4 bytes to string
|
||||
XDB_PUBLIC(int) xdb_v4_ip_to_string(const bytes_ip_t *, char *, size_t);
|
||||
|
||||
// ipv6 bytes to string
|
||||
XDB_PUBLIC(int) xdb_v6_ip_to_string(const bytes_ip_t *, char *, size_t);
|
||||
|
||||
// compare the specified ip bytes with another ip bytes in the specified buff from offset.
|
||||
// ip args must be the return value from #xdb_parse_ip.
|
||||
// returns: -1 if ip1 < ip2, 1 if ip1 > ip2 or 0
|
||||
XDB_PUBLIC(int) xdb_ip_sub_compare(const bytes_ip_t *, int, const char *, int);
|
||||
|
||||
// --- END xdb utils
|
||||
|
||||
|
||||
// --- xdb searcher api
|
||||
|
||||
// xdb searcher structure
|
||||
struct xdb_searcher_entry {
|
||||
// ip version
|
||||
xdb_ip_version_t *version;
|
||||
xdb_version_t *version;
|
||||
|
||||
// xdb file handle
|
||||
FILE *handle;
|
||||
@ -212,11 +212,11 @@ struct xdb_searcher_entry {
|
||||
typedef struct xdb_searcher_entry xdb_searcher_t;
|
||||
|
||||
// xdb searcher new api define
|
||||
XDB_PUBLIC(int) xdb_new_with_file_only(xdb_ip_version_t *, xdb_searcher_t *, const char *);
|
||||
XDB_PUBLIC(int) xdb_new_with_file_only(xdb_version_t *, xdb_searcher_t *, const char *);
|
||||
|
||||
XDB_PUBLIC(int) xdb_new_with_vector_index(xdb_ip_version_t *, xdb_searcher_t *, const char *, const xdb_vector_index_t *);
|
||||
XDB_PUBLIC(int) xdb_new_with_vector_index(xdb_version_t *, xdb_searcher_t *, const char *, const xdb_vector_index_t *);
|
||||
|
||||
XDB_PUBLIC(int) xdb_new_with_buffer(xdb_ip_version_t *, xdb_searcher_t *, const xdb_content_t *);
|
||||
XDB_PUBLIC(int) xdb_new_with_buffer(xdb_version_t *, xdb_searcher_t *, const xdb_content_t *);
|
||||
|
||||
XDB_PUBLIC(void) xdb_close(void *);
|
||||
|
||||
@ -225,7 +225,7 @@ XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *, const string_ip_t *, char
|
||||
|
||||
XDB_PUBLIC(int) xdb_search(xdb_searcher_t *, const bytes_ip_t *, int, char *, size_t);
|
||||
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_get_ip_version(xdb_searcher_t *);
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_get_version(xdb_searcher_t *);
|
||||
|
||||
XDB_PUBLIC(int) xdb_get_io_count(xdb_searcher_t *);
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
// internal function prototype define
|
||||
XDB_PRIVATE(int) read(xdb_searcher_t *, long offset, char *, size_t length);
|
||||
|
||||
XDB_PRIVATE(int) xdb_new_base(xdb_ip_version_t *version, xdb_searcher_t *xdb, const char *db_path, const xdb_vector_index_t *v_index, const xdb_content_t *c_buffer) {
|
||||
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) {
|
||||
memset(xdb, 0x00, sizeof(xdb_searcher_t));
|
||||
|
||||
// set the version
|
||||
@ -37,15 +37,15 @@ XDB_PRIVATE(int) xdb_new_base(xdb_ip_version_t *version, xdb_searcher_t *xdb, co
|
||||
}
|
||||
|
||||
// xdb searcher new api define
|
||||
XDB_PUBLIC(int) xdb_new_with_file_only(xdb_ip_version_t *version, xdb_searcher_t *xdb, const char *db_path) {
|
||||
XDB_PUBLIC(int) xdb_new_with_file_only(xdb_version_t *version, xdb_searcher_t *xdb, const char *db_path) {
|
||||
return xdb_new_base(version, xdb, db_path, NULL, NULL);
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_new_with_vector_index(xdb_ip_version_t *version, xdb_searcher_t *xdb, const char *db_path, const xdb_vector_index_t *v_index) {
|
||||
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) {
|
||||
return xdb_new_base(version, xdb, db_path, v_index, NULL);
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_new_with_buffer(xdb_ip_version_t *version, xdb_searcher_t *xdb, const xdb_content_t *c_buffer) {
|
||||
XDB_PUBLIC(int) xdb_new_with_buffer(xdb_version_t *version, xdb_searcher_t *xdb, const xdb_content_t *c_buffer) {
|
||||
return xdb_new_base(version, xdb, NULL, NULL, c_buffer);
|
||||
}
|
||||
|
||||
@ -61,7 +61,7 @@ XDB_PUBLIC(void) xdb_close(void *ptr) {
|
||||
|
||||
XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *xdb, const string_ip_t *ip_string, char *region_buffer, size_t length) {
|
||||
bytes_ip_t ip_bytes[16] = {'\0'};
|
||||
xdb_ip_version_t *version = xdb_parse_ip(ip_string, ip_bytes, sizeof(ip_bytes));
|
||||
xdb_version_t *version = xdb_parse_ip(ip_string, ip_bytes, sizeof(ip_bytes));
|
||||
if (version == NULL) {
|
||||
return 10;
|
||||
} else {
|
||||
@ -75,7 +75,6 @@ XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int
|
||||
unsigned int s_ptr, e_ptr, data_ptr, data_len;
|
||||
char vector_buffer[xdb_vector_index_size];
|
||||
char *segment_buffer = NULL;
|
||||
string_ip_t sip_string[INET6_ADDRSTRLEN] = {'\0'}, eip_string[INET6_ADDRSTRLEN] = {'\0'};
|
||||
|
||||
// ip version check
|
||||
if (ip_len != xdb->version->bytes) {
|
||||
@ -109,7 +108,7 @@ XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int
|
||||
e_ptr = xdb_le_get_uint32(vector_buffer, 4);
|
||||
}
|
||||
|
||||
printf("s_ptr=%u, e_ptr=%u\n", s_ptr, e_ptr);
|
||||
// printf("s_ptr=%u, e_ptr=%u\n", s_ptr, e_ptr);
|
||||
// binary search to get the final region info
|
||||
seg_index_size = xdb->version->segment_index_size;
|
||||
segment_buffer = xdb_malloc(seg_index_size);
|
||||
@ -124,16 +123,12 @@ XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int
|
||||
p = s_ptr + m * seg_index_size;
|
||||
|
||||
// read the segment index item
|
||||
err = read(xdb, p, segment_buffer, sizeof(segment_buffer));
|
||||
err = read(xdb, p, segment_buffer, seg_index_size);
|
||||
if (err != 0) {
|
||||
err += 20;
|
||||
goto done;
|
||||
}
|
||||
|
||||
xdb_ip_to_string(segment_buffer, bytes, sip_string, sizeof(sip_string));
|
||||
xdb_ip_to_string(segment_buffer + bytes, bytes, eip_string, sizeof(eip_string));
|
||||
printf("l=%d, h=%d, p=%d, sip: %s, eip: %s\n", l, h, p, sip_string, eip_string);
|
||||
|
||||
// decode the data fields as needed
|
||||
if (xdb->version->ip_compare(ip_bytes, bytes, segment_buffer, 0) < 0) {
|
||||
h = m - 1;
|
||||
@ -146,7 +141,7 @@ XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int
|
||||
}
|
||||
}
|
||||
|
||||
printf("data_len=%u, data_ptr=%u\n", data_len, data_ptr);
|
||||
// printf("data_len=%u, data_ptr=%u\n", data_len, data_ptr);
|
||||
if (data_len == 0) {
|
||||
goto done;
|
||||
}
|
||||
@ -195,7 +190,7 @@ XDB_PRIVATE(int) read(xdb_searcher_t *xdb, long offset, char *buffer, size_t len
|
||||
return 0;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_get_ip_version(xdb_searcher_t *xdb) {
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_get_version(xdb_searcher_t *xdb) {
|
||||
return xdb->version;
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
// @Date 2022/06/27
|
||||
|
||||
#include "xdb_api.h"
|
||||
#include <ctype.h>
|
||||
|
||||
// for Linux
|
||||
#ifdef XDB_LINUX
|
||||
@ -58,182 +59,6 @@ XDB_PUBLIC(int) xdb_init_winsock() {return 0;}
|
||||
XDB_PUBLIC(void) xdb_clean_winsock() {}
|
||||
#endif
|
||||
|
||||
// --- ip version
|
||||
|
||||
// ip compare for IPv4
|
||||
// ip1 - with Big endian byte order parsed from an input
|
||||
// ip2 - with Little endian byte order read from the xdb index.
|
||||
// to compatiable with the Little Endian encoded IPv4 on xdb 2.0.
|
||||
XDB_PRIVATE(int) _ipv4_sub_compare(const bytes_ip_t *ip_bytes, int bytes, const char *buffer, int offset) {
|
||||
register int i0, i1;
|
||||
for (int i = 0, j = offset + bytes - 1; i < bytes; i++, j--) {
|
||||
i0 = ip_bytes[i];
|
||||
i1 = buffer[j] & 0xFF;
|
||||
if (i0 > i1) {
|
||||
return 1;
|
||||
} else if (i0 < i1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static xdb_ip_version_t _ip_version_list[] = {
|
||||
// 14 = 4 + 4 + 2 + 4
|
||||
{xdb_ipv4_version_no, "IPv4", xdb_ipv4_bytes, 14, _ipv4_sub_compare},
|
||||
|
||||
// 38 = 16 + 16 + 2 + 4
|
||||
{xdb_ipv6_version_no, "IPv6", xdb_ipv6_bytes, 38, xdb_ip_sub_compare},
|
||||
|
||||
// END
|
||||
{0, NULL, 0, 0, NULL}
|
||||
};
|
||||
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_version_ipv4() {
|
||||
return &_ip_version_list[0];
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_version_ipv6() {
|
||||
return &_ip_version_list[1];
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_ip_version_is_v4(const xdb_ip_version_t *version) {
|
||||
return version->id == xdb_ipv4_version_no;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_ip_version_is_v6(const xdb_ip_version_t *version) {
|
||||
return version->id == xdb_ipv6_version_no;
|
||||
}
|
||||
|
||||
// --- END ip version
|
||||
|
||||
XDB_PUBLIC(long) xdb_now() {
|
||||
struct timeval c_time;
|
||||
gettimeofday(&c_time, NULL);
|
||||
return c_time.tv_sec * (int)1e6 + c_time.tv_usec;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(unsigned int) xdb_le_get_uint32(const char *buffer, int offset) {
|
||||
return (
|
||||
((buffer[offset ]) & 0x000000FF) |
|
||||
((buffer[offset+1] << 8) & 0x0000FF00) |
|
||||
((buffer[offset+2] << 16) & 0x00FF0000) |
|
||||
((buffer[offset+3] << 24) & 0xFF000000)
|
||||
);
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_le_get_uint16(const char *buffer, int offset) {
|
||||
return (
|
||||
((buffer[offset ]) & 0x000000FF) |
|
||||
((buffer[offset+1] << 8) & 0x0000FF00)
|
||||
);
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_parse_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
|
||||
// version check
|
||||
if (strchr(ip_string, '.') != NULL && strchr(ip_string, ':') == NULL) {
|
||||
return xdb_parse_v4_ip(ip_string, buffer, length);
|
||||
} else if (strchr(ip_string, ':') != NULL) {
|
||||
return xdb_parse_v6_ip(ip_string, buffer, length);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_parse_v4_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
|
||||
struct in_addr addr;
|
||||
|
||||
// buffer length checking
|
||||
if (length < xdb_ipv4_bytes) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, ip_string, &addr) != 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// encode the address to buffer with big endian byte bufffer.
|
||||
buffer[0] = (addr.s_addr) & 0xFF;
|
||||
buffer[1] = (addr.s_addr >> 8) & 0xFF;
|
||||
buffer[2] = (addr.s_addr >> 16) & 0xFF;
|
||||
buffer[3] = (addr.s_addr >> 24) & 0xFF;
|
||||
return XDB_IPv4;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_ip_version_t *) xdb_parse_v6_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
|
||||
struct in6_addr addr;
|
||||
|
||||
// buffer length checking
|
||||
if (length < xdb_ipv6_bytes) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET6, ip_string, &addr) != 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(buffer, addr.s6_addr, xdb_ipv6_bytes);
|
||||
return XDB_IPv6;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_ip_to_string(const bytes_ip_t *ip_bytes, int bytes, char *ip_string, size_t length) {
|
||||
if (bytes == xdb_ipv4_bytes) {
|
||||
return xdb_v4_ip_to_string(ip_bytes, ip_string, length);
|
||||
} else if (bytes == xdb_ipv6_bytes) {
|
||||
return xdb_v6_ip_to_string(ip_bytes, ip_string, length);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_v4_ip_to_string(const bytes_ip_t *ip_bytes, char *ip_string, size_t length) {
|
||||
if (!ip_bytes || !ip_string || length == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// buffer length checking
|
||||
if (length < INET_ADDRSTRLEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inet_ntop(AF_INET, ip_bytes, ip_string, length) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_v6_ip_to_string(const bytes_ip_t *ip_bytes, char *ip_string, size_t length) {
|
||||
if (!ip_bytes || !ip_string || length == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (length < INET6_ADDRSTRLEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inet_ntop(AF_INET6, ip_bytes, ip_string, length) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_ip_sub_compare(const bytes_ip_t *ip1, int bytes, const char *buffer, int offset) {
|
||||
register int i, i1, i2;
|
||||
for (i = 0; i < bytes; i++) {
|
||||
i1 = ip1[i];
|
||||
i2 = buffer[offset + i] & 0xFF;
|
||||
if (i1 > i2) {
|
||||
return 1;
|
||||
} else if (i1 < i2) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// --- xdb buffer function implementations
|
||||
|
||||
XDB_PUBLIC(xdb_header_t *) xdb_load_header(FILE *handle) {
|
||||
@ -398,4 +223,215 @@ XDB_PUBLIC(void) xdb_free_content(void *ptr) {
|
||||
}
|
||||
}
|
||||
|
||||
// --- End
|
||||
// --- End content buffer
|
||||
|
||||
|
||||
// --- ip version
|
||||
|
||||
// ip compare for IPv4
|
||||
// ip1 - with Big endian byte order parsed from an input
|
||||
// ip2 - with Little endian byte order read from the xdb index.
|
||||
// to compatiable with the Little Endian encoded IPv4 on xdb 2.0.
|
||||
XDB_PRIVATE(int) _ipv4_sub_compare(const bytes_ip_t *ip_bytes, int bytes, const char *buffer, int offset) {
|
||||
register int i0, i1;
|
||||
for (int i = 0, j = offset + bytes - 1; i < bytes; i++, j--) {
|
||||
i0 = ip_bytes[i];
|
||||
i1 = buffer[j] & 0xFF;
|
||||
if (i0 > i1) {
|
||||
return 1;
|
||||
} else if (i0 < i1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static xdb_version_t _ip_version_list[] = {
|
||||
// 14 = 4 + 4 + 2 + 4
|
||||
{xdb_ipv4_id, "IPv4", xdb_ipv4_bytes, 14, _ipv4_sub_compare},
|
||||
|
||||
// 38 = 16 + 16 + 2 + 4
|
||||
{xdb_ipv6_id, "IPv6", xdb_ipv6_bytes, 38, xdb_ip_sub_compare},
|
||||
|
||||
// END
|
||||
{0, NULL, 0, 0, NULL}
|
||||
};
|
||||
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_version_v4() {
|
||||
return &_ip_version_list[0];
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_version_v6() {
|
||||
return &_ip_version_list[1];
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_version_is_v4(const xdb_version_t *version) {
|
||||
return version->id == xdb_ipv4_id;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_version_is_v6(const xdb_version_t *version) {
|
||||
return version->id == xdb_ipv6_id;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_version_from_name(char *name) {
|
||||
// to upper case the name
|
||||
for (int i = 0; name[i] != '\0'; i++) {
|
||||
name[i] = toupper((unsigned char) name[i]);
|
||||
}
|
||||
|
||||
if (strcmp(name, "V4") == 0 || strcmp(name, "IPV4") == 0) {
|
||||
return xdb_version_v4();
|
||||
} else if (strcmp(name, "V6") == 0 || strcmp(name, "IPV6") == 0) {
|
||||
return xdb_version_v6();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_version_from_header(xdb_header_t *header) {
|
||||
// Old structure with ONLY IPv4 supports
|
||||
if (header->version == xdb_structure_20) {
|
||||
return xdb_version_v4();
|
||||
}
|
||||
|
||||
// structure 3.0 with IPv6 supporting
|
||||
if (header->version != xdb_structure_30) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (header->ip_version == xdb_ipv4_id) {
|
||||
return xdb_version_v4();
|
||||
} else if (header->ip_version == xdb_ipv6_id) {
|
||||
return xdb_version_v6();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// --- END ip version
|
||||
|
||||
XDB_PUBLIC(long) xdb_now() {
|
||||
struct timeval c_time;
|
||||
gettimeofday(&c_time, NULL);
|
||||
return c_time.tv_sec * (int)1e6 + c_time.tv_usec;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(unsigned int) xdb_le_get_uint32(const char *buffer, int offset) {
|
||||
return (
|
||||
((buffer[offset ]) & 0x000000FF) |
|
||||
((buffer[offset+1] << 8) & 0x0000FF00) |
|
||||
((buffer[offset+2] << 16) & 0x00FF0000) |
|
||||
((buffer[offset+3] << 24) & 0xFF000000)
|
||||
);
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_le_get_uint16(const char *buffer, int offset) {
|
||||
return (
|
||||
((buffer[offset ]) & 0x000000FF) |
|
||||
((buffer[offset+1] << 8) & 0x0000FF00)
|
||||
);
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_parse_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
|
||||
// version check
|
||||
if (strchr(ip_string, '.') != NULL && strchr(ip_string, ':') == NULL) {
|
||||
return xdb_parse_v4_ip(ip_string, buffer, length);
|
||||
} else if (strchr(ip_string, ':') != NULL) {
|
||||
return xdb_parse_v6_ip(ip_string, buffer, length);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_parse_v4_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
|
||||
struct in_addr addr;
|
||||
|
||||
// buffer length checking
|
||||
if (length < xdb_ipv4_bytes) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET, ip_string, &addr) != 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// encode the address to buffer with big endian byte bufffer.
|
||||
buffer[0] = (addr.s_addr) & 0xFF;
|
||||
buffer[1] = (addr.s_addr >> 8) & 0xFF;
|
||||
buffer[2] = (addr.s_addr >> 16) & 0xFF;
|
||||
buffer[3] = (addr.s_addr >> 24) & 0xFF;
|
||||
return XDB_IPv4;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(xdb_version_t *) xdb_parse_v6_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
|
||||
struct in6_addr addr;
|
||||
|
||||
// buffer length checking
|
||||
if (length < xdb_ipv6_bytes) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET6, ip_string, &addr) != 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(buffer, addr.s6_addr, xdb_ipv6_bytes);
|
||||
return XDB_IPv6;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_ip_to_string(const bytes_ip_t *ip_bytes, int bytes, char *ip_string, size_t length) {
|
||||
if (bytes == xdb_ipv4_bytes) {
|
||||
return xdb_v4_ip_to_string(ip_bytes, ip_string, length);
|
||||
} else if (bytes == xdb_ipv6_bytes) {
|
||||
return xdb_v6_ip_to_string(ip_bytes, ip_string, length);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_v4_ip_to_string(const bytes_ip_t *ip_bytes, char *ip_string, size_t length) {
|
||||
if (!ip_bytes || !ip_string || length == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// buffer length checking
|
||||
if (length < INET_ADDRSTRLEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inet_ntop(AF_INET, ip_bytes, ip_string, length) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_v6_ip_to_string(const bytes_ip_t *ip_bytes, char *ip_string, size_t length) {
|
||||
if (!ip_bytes || !ip_string || length == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (length < INET6_ADDRSTRLEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (inet_ntop(AF_INET6, ip_bytes, ip_string, length) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XDB_PUBLIC(int) xdb_ip_sub_compare(const bytes_ip_t *ip1, int bytes, const char *buffer, int offset) {
|
||||
register int i, i1, i2;
|
||||
for (i = 0; i < bytes; i++) {
|
||||
i1 = ip1[i];
|
||||
i2 = buffer[offset + i] & 0xFF;
|
||||
if (i1 > i2) {
|
||||
return 1;
|
||||
} else if (i1 < i2) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user