diff --git a/binding/c/main.c b/binding/c/main.c index ad11cf7..a209da3 100644 --- a/binding/c/main.c +++ b/binding/c/main.c @@ -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; } diff --git a/binding/c/test_util b/binding/c/test_util index 1b0c79f..8ae3a2e 100755 Binary files a/binding/c/test_util and b/binding/c/test_util differ diff --git a/binding/c/test_util.c b/binding/c/test_util.c index 0d56c7f..ea39248 100644 --- a/binding/c/test_util.c +++ b/binding/c/test_util.c @@ -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) ); } diff --git a/binding/c/xdb_api.h b/binding/c/xdb_api.h index 5763e2e..d0f7338 100644 --- a/binding/c/xdb_api.h +++ b/binding/c/xdb_api.h @@ -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); diff --git a/binding/c/xdb_searcher.c b/binding/c/xdb_searcher.c index d49efef..275c30a 100644 --- a/binding/c/xdb_searcher.c +++ b/binding/c/xdb_searcher.c @@ -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; } diff --git a/binding/c/xdb_util.c b/binding/c/xdb_util.c index 343f25e..6699bc0 100644 --- a/binding/c/xdb_util.c +++ b/binding/c/xdb_util.c @@ -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]; -} \ No newline at end of file