diff --git a/binding/c/test_util b/binding/c/test_util index 6f2c779..43fd733 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 9a9fcb6..190382c 100644 --- a/binding/c/test_util.c +++ b/binding/c/test_util.c @@ -9,32 +9,12 @@ #include "stdio.h" #include "xdb_api.h" -void test_check_ip() { - char *ip_list[] = { - "1.2.3.4", "192.168.2.3", "120.24.78.129", "255.255.255.0", - "256.7.12.9", "12.56.78.320", "32.12.45.192", "222.221.220.219", - "192.168.1.101 ", "132.96.12.98a", "x23.12.2.12" - }; - - int errcode, i; - unsigned int ip; - char ip_buff[16] = {'\0'}; - for (i = 0; i < 11; i++) { - errcode = xdb_check_ip(ip_list[i], &ip); - if (errcode != 0) { - printf("invalid ip address `%s`\n", ip_list[i]); - continue; - } - - xdb_long2ip(ip, ip_buff); - printf("long(%-15s)=%-10u, long2ip(%-10u)=%-15s", ip_list[i], ip, ip, ip_buff); - if (strcmp(ip_list[i], ip_buff) != 0) { - printf(" --[Failed]\n"); - } else { - printf(" --[Ok]\n"); - } - } -} +typedef void (* test_func_ptr) (); +struct test_func_entry { + char *name; + test_func_ptr func; +}; +typedef struct test_func_entry test_func_t; void test_load_header() { xdb_header_t *header = xdb_load_header_from_file("../../data/ip2region_v4.xdb"); @@ -79,23 +59,146 @@ void test_load_content() { xdb_free_content(content); } +void test_parse_ip() { + const char *ip_list[] = { + "1.0.0.0", "58.251.30.115", "192.168.1.100", + "::", "2c0f:fff0::", "2fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "240e:982:e617:ffff:ffff:ffff:ffff:ffff", + "219.xx.xx.11", "::xx:ffff", + NULL + }; + + int errcode; + bytes_ip_t ip_bytes[17] = {'\0'}; + string_ip_t ip_string[INET6_ADDRSTRLEN + 1] = {'\0'}; + + // init the sock env (for windows) + if ((errcode = xdb_init_winsock()) != 0) { + printf("failed to init the winsock"); + return; + } + + for (int i = 0;; i++) { + if (ip_list[i] == NULL) { + break; + } + + errcode = xdb_parse_ip(ip_list[i], ip_bytes, sizeof(ip_bytes)); + if (errcode == -1) { + 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); + } + + // clean up the winsock + xdb_clean_winsock(); +} + +struct ip_pair { + const char *sip; + const char *eip; +}; +void test_ip_compare() { + struct ip_pair ip_pair_list[] = { + {"1.0.0.0", "1.0.0.1"}, + {"192.168.1.101", "192.168.1.90"}, + {"219.133.111.87", "114.114.114.114"}, + {"1.0.4.0", "1.0.1.0"}, + {"1.0.4.0", "1.0.3.255"}, + {"2000::", "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff"}, + {"2001:4:112::", "2001:4:112:ffff:ffff:ffff:ffff:ffff"}, + {"ffff::", "2001:4:ffff:ffff:ffff:ffff:ffff:ffff"}, + {NULL, NULL} + }; + + 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; + + // init the sock env (for windows) + if ((errcode = xdb_init_winsock()) != 0) { + printf("failed to init the winsock"); + return; + } + + for (int i = 0; ;i++) { + pair_ptr = &ip_pair_list[i]; + if (pair_ptr->sip == NULL) { + break; + } + + sip_version = xdb_parse_ip(pair_ptr->sip, sip_bytes, sizeof(sip_bytes)); + if (sip_version == -1) { + 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) { + printf("failed to parse eip `%s`", pair_ptr->eip); + continue; + } + + bytes = sip_version == xdb_ipv4_version_no ? xdb_ipv4_bytes : xdb_ipv6_bytes; + printf( + "ip_sub_compare(%s, %s): %d\n", + pair_ptr->sip, pair_ptr->eip, + xdb_ip_sub_compare(sip_bytes, bytes, eip_bytes, 0) + ); + } + + // clean up the winsock + xdb_clean_winsock(); +} + +// please register your function heare +static test_func_t _test_function_list[] = { + // xdb buffer + {"test_load_header", test_load_header}, + {"test_load_vector_index", test_load_vector_index}, + {"test_load_content", test_load_content}, + + // ip utils + {"test_parse_ip", test_parse_ip}, + {"test_ip_compare", test_ip_compare}, + + {NULL, NULL} +}; + // valgrind --tool=memcheck --leak-check=full ./a.out int main(int argc, char *argv[]) { - printf("test check ip ... \n"); - test_check_ip(); - printf("|--done\n\n"); + int i; + char *name; - printf("test load header ... \n"); - test_load_header(); - printf("|--done\n\n"); + // check and call the function + if (argc < 2) { + printf("please specified the function name to call\n"); + return 1; + } - printf("test load vector index ... \n"); - test_load_vector_index(); - printf("|--done\n\n"); + name = argv[1]; + test_func_ptr func = NULL; + for (i = 0; ; i++) { + if (_test_function_list[i].name == NULL) { + break; + } - printf("test load content ... \n"); - test_load_content(); - printf("|--done\n\n"); + if (strcmp(name, _test_function_list[i].name) == 0) { + func = _test_function_list[i].func; + break; + } + } + + if (func == NULL) { + printf("can't find test function `%s`\n", name); + return 1; + } + + // call the function + func(); return 0; } diff --git a/binding/c/xdb_api.h b/binding/c/xdb_api.h index af846cc..244f1c5 100644 --- a/binding/c/xdb_api.h +++ b/binding/c/xdb_api.h @@ -17,10 +17,17 @@ # define XDB_PUBLIC(type) extern __declspec(dllexport) type # define XDB_PRIVATE(type) static type # define XDB_WINDOWS +#include +#include +#include +#pragma comment(lib, "ws2_32.lib") #elif ( defined(linux) || defined(_UNIX) || defined(__APPLE__) ) # define XDB_PUBLIC(type) extern type # define XDB_PRIVATE(type) static inline type # define XDB_LINUX +#include +#include +#include #endif #define xdb_calloc( _blocks, _bytes ) calloc( _blocks, _bytes ) @@ -37,6 +44,8 @@ // --- ip version info #define xdb_ipv4_version_no 4 #define xdb_ipv6_version_no 6 +#define xdb_ipv4_bytes 4 +#define xdb_ipv6_bytes 16 #define XDB_IPV4 4 #define XDB_IPv6 6 @@ -49,6 +58,11 @@ typedef unsigned char bytes_ip_t; // --- 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(); @@ -79,7 +93,7 @@ XDB_PUBLIC(int) 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 *, size_t, char *, size_t); +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); diff --git a/binding/c/xdb_util.c b/binding/c/xdb_util.c index 812f7b4..0f48b42 100644 --- a/binding/c/xdb_util.c +++ b/binding/c/xdb_util.c @@ -15,7 +15,27 @@ // @Note: since 2023/10/13 to compatible with the windows system #ifdef XDB_WINDOWS -#include +static int winsock_initialized = 0; +XDB_PUBLIC(int) xdb_init_winsock() { + if (winsock_initialized == 1) { + return 0; + } + + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { + return -1; + } + winsock_initialized = 1; + return 0; +} + +XDB_PUBLIC(void) xdb_clean_winsock() { + if (winsock_initialized == 1) { + WSACleanup(); + winsock_initialized = 0; + } +} + XDB_PRIVATE(int) gettimeofday(struct timeval* tp, void* tzp) { time_t clock; struct tm tm; @@ -33,6 +53,9 @@ XDB_PRIVATE(int) gettimeofday(struct timeval* tp, void* tzp) { tp->tv_usec = wtm.wMilliseconds * 1000; return (0); } +#else +XDB_PUBLIC(int) xdb_init_winsock() {return 0;} +XDB_PUBLIC(void) xdb_clean_winsock() {} #endif XDB_PUBLIC(long) xdb_now() { @@ -96,66 +119,100 @@ 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, bytes_ip_t *buffer, size_t length) { - // where there is a . there is a IPV4 even though there are IPv6 wrapped IPv4 like - // ::ffff:192.168.1.100, lets just keep it in this way. - if (strchr(ip, '.') != NULL) { - return xdb_parse_v4_ip(ip, buffer, length); - } else if (strchr(ip, ':') != NULL) { - return xdb_parse_v6_ip(ip, buffer, length); +XDB_PUBLIC(int) 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 -1; } -XDB_PUBLIC(int) xdb_parse_v4_ip(const string_ip_t *ip, bytes_ip_t *buffer, size_t length) { - return 0; +XDB_PUBLIC(int) 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; + } + + if (inet_pton(AF_INET, ip_string, &addr) != 1) { + return -1; + } + + // 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_version_no; } -XDB_PUBLIC(int) xdb_parse_v6_ip(const string_ip_t *ip, bytes_ip_t *buffer, size_t length) { - return 0; +XDB_PUBLIC(int) 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; + } + + if (inet_pton(AF_INET6, ip_string, &addr) != 1) { + return -1; + } + + memcpy(buffer, addr.s6_addr, xdb_ipv6_bytes); + return xdb_ipv6_version_no; } -XDB_PUBLIC(int) xdb_ip_to_string(const bytes_ip_t *ip, size_t bytes, char *buffer, size_t length) { - if (bytes == 4) { - return xdb_v4_ip_to_string(ip, buffer, length); - } else if (bytes == 16) { - return xdb_v6_ip_to_string(ip, buffer, length); +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) { + return xdb_v4_ip_to_string(ip_bytes, ip_string, length); + } else if (version == xdb_ipv6_version_no) { + 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, char *buffer, size_t length) { - snprintf( - buffer, length, - "%d.%d.%d.%d", - ip[0], ip[1], ip[2], ip[3] - ); +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, char *buffer, size_t length) { - // temp solution for testing ONLY, we will handle the :: later - snprintf( - buffer, length, - "%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x", - ip[0], ip[1], - ip[2], ip[3], - ip[4], ip[5], - ip[6], ip[7], - ip[8], ip[9], - ip[10], ip[11], - ip[12], ip[13], - ip[14], ip[15] - ); +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, size_t length, const char *buffer, int offset) { - int i, i1, i2; + register int i, i1, i2; for (i = 0; i < length; i++) { - i1 = ip1[i] & 0xFF; + i1 = ip1[i]; i2 = buffer[offset + i] & 0xFF; if (i1 > i2) { return 1;