apply the bytes ip to the whole search process

This commit is contained in:
lion 2025-09-17 23:10:42 +08:00
parent 69b9f062e4
commit 73c8b20d3a
6 changed files with 162 additions and 140 deletions

View File

@ -110,6 +110,11 @@ void test_search(int argc, char *argv[]) {
long s_time, c_time;
unsigned int ip;
char line[512] = {'\0'}, region[512] = {'\0'};
// ip parse
xdb_ip_version_t *version;
bytes_ip_t ip_bytes[16] = {'\0'};
searcher_test_t test;
for (i = 2; i < argc; i++) {
@ -173,13 +178,14 @@ void test_search(int argc, char *argv[]) {
break;
}
if (xdb_check_ip(line, &ip) != 0) {
version = xdb_parse_ip(line, ip_bytes, sizeof(ip_bytes));
if (version == NULL) {
printf("invalid ip address `%s`\n", line);
continue;
}
s_time = xdb_now();
err = xdb_search(&test.searcher, ip, region, sizeof(region));
err = xdb_search(&test.searcher, ip_bytes, version->bytes, region, sizeof(region));
if (err != 0) {
printf("{err: %d, io_count: %d}\n", err, xdb_get_io_count(&test.searcher));
} else {
@ -200,9 +206,15 @@ void test_bench(int argc, char *argv[]) {
FILE *handle;
char line[1024] = {'\0'}, sip_str[16] = {'\0'}, eip_str[16] = {'\0'};
char src_region[512] = {'\0'}, region_buffer[512] = {'\0'};
unsigned int sip, eip, ip_list[2];
int count = 0, took;
long s_time, t_time, c_time = 0;
// ip parse
xdb_ip_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++) {
@ -269,38 +281,44 @@ void test_bench(int argc, char *argv[]) {
return;
}
if (xdb_check_ip(sip_str, &sip) != 0) {
s_version = xdb_parse_ip(sip_str, sip_bytes, sizeof(sip_bytes));
if (s_version == NULL) {
printf("invalid start ip `%s`\n", sip_str);
return;
}
if (xdb_check_ip(eip_str, &eip) != 0) {
e_version = xdb_parse_ip(eip_str, eip_bytes, sizeof(eip_bytes));
if (e_version == NULL) {
printf("invalid end ip `%s`\n", sip_str);
return;
}
if (sip > eip) {
if (s_version->id != e_version->id) {
printf("start ip and end ip version not match for line `%s`\n", line);
return;
}
if (xdb_ip_sub_compare(sip_bytes, s_version->bytes, eip_bytes, 0) > 0) {
printf("start ip(%s) should not be greater than end ip(%s)\n", sip_str, eip_str);
return;
}
ip_list[0] = sip;
ip_list[1] = eip;
ip_list[0] = sip_bytes;
ip_list[1] = eip_bytes;
for (i = 0; i < 2; i++) {
t_time = xdb_now();
err = xdb_search(&test.searcher, ip_list[i], region_buffer, sizeof(region_buffer));
err = xdb_search(&test.searcher, ip_list[i], s_version->bytes, region_buffer, sizeof(region_buffer));
c_time += xdb_now() - t_time;
if (err != 0) {
xdb_long2ip(ip_list[i], sip_str);
printf("failed to search ip `%s` with errno=%d\n", sip_str, err);
xdb_ip_to_string(ip_list[i], s_version->bytes, ip_string, sizeof(ip_string));
printf("failed to search ip `%s` with errno=%d\n", ip_string, err);
return;
}
c_time += xdb_now() - t_time;
// check the region info
if (strcmp(region_buffer, src_region) != 0) {
xdb_long2ip(ip_list[i], sip_str);
printf("failed to search(%s) with (%s != %s)\n", sip_str, region_buffer, src_region);
xdb_ip_to_string(ip_list[i], s_version->bytes, ip_string, sizeof(ip_string));
printf("failed to search(%s) with (%s != %s)\n", ip_string, region_buffer, src_region);
return;
}

Binary file not shown.

View File

@ -68,6 +68,7 @@ void test_parse_ip() {
};
int errcode;
xdb_ip_version_t *version;
bytes_ip_t ip_bytes[16] = {'\0'};
string_ip_t ip_string[INET6_ADDRSTRLEN] = {'\0'};
@ -82,14 +83,14 @@ void test_parse_ip() {
break;
}
errcode = xdb_parse_ip(ip_list[i], ip_bytes, sizeof(ip_bytes));
if (errcode == -1) {
version = xdb_parse_ip(ip_list[i], ip_bytes, sizeof(ip_bytes));
if (version == NULL) {
printf("failed to parse ip `%s`\n", ip_list[i]);
continue;
}
xdb_ip_to_string(ip_bytes, errcode, ip_string, sizeof(ip_string));
printf("ip: %s (version=v%d), toString: %s\n", ip_list[i], errcode, ip_string);
xdb_ip_to_string(ip_bytes, version->bytes, ip_string, sizeof(ip_string));
printf("ip: %s (version=v%d), toString: %s\n", ip_list[i], version->id, ip_string);
}
// clean up the winsock
@ -116,7 +117,8 @@ void test_ip_compare() {
struct ip_pair *pair_ptr = NULL;
bytes_ip_t sip_bytes[16] = {'\0'};
bytes_ip_t eip_bytes[16] = {'\0'};
int sip_version, eip_version, bytes, errcode;
xdb_ip_version_t *s_version, *e_version;
int bytes, errcode;
// init the sock env (for windows)
if ((errcode = xdb_init_winsock()) != 0) {
@ -130,23 +132,27 @@ void test_ip_compare() {
break;
}
sip_version = xdb_parse_ip(pair_ptr->sip, sip_bytes, sizeof(sip_bytes));
if (sip_version == -1) {
s_version = xdb_parse_ip(pair_ptr->sip, sip_bytes, sizeof(sip_bytes));
if (s_version == NULL) {
printf("failed to parse sip `%s`", pair_ptr->sip);
continue;
}
eip_version = xdb_parse_ip(pair_ptr->eip, eip_bytes, sizeof(eip_bytes));
if (eip_version == -1) {
e_version = xdb_parse_ip(pair_ptr->eip, eip_bytes, sizeof(eip_bytes));
if (e_version == NULL) {
printf("failed to parse eip `%s`", pair_ptr->eip);
continue;
}
bytes = sip_version == xdb_ipv4_version_no ? xdb_ipv4_bytes : xdb_ipv6_bytes;
if (s_version->id != e_version->id) {
printf("sip and eip version not match `%s` != `%s`\n", s_version->name, e_version->name);
continue;
}
printf(
"ip_sub_compare(%s, %s): %d\n",
pair_ptr->sip, pair_ptr->eip,
xdb_ip_sub_compare(sip_bytes, bytes, eip_bytes, 0)
xdb_ip_sub_compare(sip_bytes, s_version->bytes, eip_bytes, 0)
);
}

View File

@ -53,6 +53,29 @@
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
@ -77,16 +100,16 @@ XDB_PUBLIC(void) xdb_long2ip(unsigned int, char *);
// parse the specified IP address to byte array.
// returns: 4 for valid ipv4, 16 for valid ipv6, or -1 for failed
XDB_PUBLIC(int) xdb_parse_ip(const string_ip_t *, bytes_ip_t *, size_t);
// 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: 4 for valid ipv4, or -1 for failed
XDB_PUBLIC(int) xdb_parse_v4_ip(const string_ip_t *, bytes_ip_t *, size_t);
// 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: 16 for valid ipv6, or -1 for failed
XDB_PUBLIC(int) xdb_parse_v6_ip(const string_ip_t *, bytes_ip_t *, size_t);
// 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.
@ -101,30 +124,10 @@ 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 *, size_t, const char *, int);
XDB_PUBLIC(int) xdb_ip_sub_compare(const bytes_ip_t *, int, const char *, int);
// --- END xdb utils
// --- ip version
#define XDB_IPv4 (xdb_version_ipv4())
#define XDB_IPv6 (xdb_version_ipv6())
typedef int (* ip_compare_fn_t) (const bytes_ip_t *, size_t, 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();
// --- END ip version
// --- xdb buffer functions
@ -218,7 +221,7 @@ XDB_PUBLIC(int) xdb_new_with_buffer(xdb_ip_version_t *, xdb_searcher_t *, const
XDB_PUBLIC(void) xdb_close(void *);
// xdb searcher search api define
XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *, const char *, char *, size_t);
XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *, const string_ip_t *, char *, size_t);
XDB_PUBLIC(int) xdb_search(xdb_searcher_t *, const bytes_ip_t *, int, char *, size_t);

View File

@ -59,33 +59,34 @@ XDB_PUBLIC(void) xdb_close(void *ptr) {
// --- xdb searcher search api define
XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *xdb, const char *ip_string, char *region_buffer, size_t length) {
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'};
int versionNo = xdb_parse_ip(ip_string, ip_bytes, sizeof(ip_bytes));
if (versionNo == -1) {
xdb_ip_version_t *version = xdb_parse_ip(ip_string, ip_bytes, sizeof(ip_bytes));
if (version == NULL) {
return 10;
} else {
return xdb_search(xdb, ip_bytes, versionNo, region_buffer, length);
return xdb_search(xdb, ip_bytes, version->bytes, region_buffer, length);
}
}
XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int byte_count, char *region_buffer, size_t length) {
XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int ip_len, char *region_buffer, size_t length) {
int il0, il1, idx, err, bytes, d_bytes;
register int seg_index_size, l, h, m, p;
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 (byte_count != xdb->version->bytes) {
if (ip_len != xdb->version->bytes) {
return -1;
}
// some resets
err = 0;
data_len = 0;
bytes = byte_count;
d_bytes = byte_count << 1;
bytes = xdb->version->bytes;
d_bytes = xdb->version->bytes << 1;
xdb->io_count = 0;
// locate the segment index block based on the vector index
@ -108,7 +109,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);
@ -129,10 +130,14 @@ XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int
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_ip_sub_compare(ip_bytes, byte_count, segment_buffer, 0) < 0) {
if (xdb->version->ip_compare(ip_bytes, bytes, segment_buffer, 0) < 0) {
h = m - 1;
} else if (xdb_ip_sub_compare(ip_bytes, byte_count, segment_buffer, bytes) > 0) {
} else if (xdb->version->ip_compare(ip_bytes, bytes, segment_buffer, bytes) > 0) {
l = m + 1;
} else {
data_len = xdb_le_get_uint16(segment_buffer, d_bytes);
@ -141,7 +146,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;
}

View File

@ -58,6 +58,55 @@ 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);
@ -80,46 +129,7 @@ XDB_PUBLIC(int) xdb_le_get_uint16(const char *buffer, int offset) {
);
}
// string ip to unsigned int
static int shiftIndex[4] = {24, 16, 8, 0};
XDB_PUBLIC(int) xdb_check_ip(const char *src_ip, unsigned int *dst_ip) {
char c;
int i, n, ip = 0;
const char *ptr = src_ip;
for (i = 0; i < 4; i++) {
n = 0;
while (1) {
c = *ptr;
ptr++;
if (c >= '0' && c <= '9') {
n *= 10;
n += c - '0';
} else if ((i < 3 && c == '.') || i == 3) {
// stopping at the '.' but ignore the tailing chars
// after the 3rd one (auto clean the tailing none-integer ?).
break;
} else {
return 1;
}
}
if (n > 0xFF) {
return 2;
}
ip |= (n << shiftIndex[i]);
}
*dst_ip = ip;
return 0;
}
// unsigned int ip to string ip
XDB_PUBLIC(void) xdb_long2ip(unsigned int ip, char *buffer) {
sprintf(buffer, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
}
XDB_PUBLIC(int) xdb_parse_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
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);
@ -127,19 +137,19 @@ XDB_PUBLIC(int) xdb_parse_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, s
return xdb_parse_v6_ip(ip_string, buffer, length);
}
return -1;
return NULL;
}
XDB_PUBLIC(int) xdb_parse_v4_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
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 -1;
return NULL;
}
if (inet_pton(AF_INET, ip_string, &addr) != 1) {
return -1;
return NULL;
}
// encode the address to buffer with big endian byte bufffer.
@ -147,29 +157,29 @@ XDB_PUBLIC(int) xdb_parse_v4_ip(const string_ip_t *ip_string, bytes_ip_t *buffer
buffer[1] = (addr.s_addr >> 8) & 0xFF;
buffer[2] = (addr.s_addr >> 16) & 0xFF;
buffer[3] = (addr.s_addr >> 24) & 0xFF;
return xdb_ipv4_version_no;
return XDB_IPv4;
}
XDB_PUBLIC(int) xdb_parse_v6_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
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 -1;
return NULL;
}
if (inet_pton(AF_INET6, ip_string, &addr) != 1) {
return -1;
return NULL;
}
memcpy(buffer, addr.s6_addr, xdb_ipv6_bytes);
return xdb_ipv6_version_no;
return XDB_IPv6;
}
XDB_PUBLIC(int) xdb_ip_to_string(const bytes_ip_t *ip_bytes, int version, char *ip_string, size_t length) {
if (version == xdb_ipv4_version_no) {
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 (version == xdb_ipv6_version_no) {
} else if (bytes == xdb_ipv6_bytes) {
return xdb_v6_ip_to_string(ip_bytes, ip_string, length);
}
@ -209,9 +219,9 @@ XDB_PUBLIC(int) xdb_v6_ip_to_string(const bytes_ip_t *ip_bytes, char *ip_string,
return 0;
}
XDB_PUBLIC(int) xdb_ip_sub_compare(const bytes_ip_t *ip1, size_t length, const char *buffer, int offset) {
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 < length; i++) {
for (i = 0; i < bytes; i++) {
i1 = ip1[i];
i2 = buffer[offset + i] & 0xFF;
if (i1 > i2) {
@ -389,23 +399,3 @@ XDB_PUBLIC(void) xdb_free_content(void *ptr) {
}
// --- End
// --- ip version
static xdb_ip_version_t _ip_version_list[] = {
// 14 = 4 + 4 + 2 + 4
{xdb_ipv4_version_no, "IPv4", xdb_ipv4_bytes, 14, NULL},
// 38 = 16 + 16 + 2 + 4
{xdb_ipv6_version_no, "IPv6", xdb_ipv6_bytes, 38, NULL},
// 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];
}