ip parse / to_string / compare util function is ready

This commit is contained in:
lion 2025-09-17 13:07:35 +08:00
parent 0fd0bc59d0
commit 4cff9eb6ee
4 changed files with 252 additions and 78 deletions

Binary file not shown.

View File

@ -9,32 +9,12 @@
#include "stdio.h" #include "stdio.h"
#include "xdb_api.h" #include "xdb_api.h"
void test_check_ip() { typedef void (* test_func_ptr) ();
char *ip_list[] = { struct test_func_entry {
"1.2.3.4", "192.168.2.3", "120.24.78.129", "255.255.255.0", char *name;
"256.7.12.9", "12.56.78.320", "32.12.45.192", "222.221.220.219", test_func_ptr func;
"192.168.1.101 ", "132.96.12.98a", "x23.12.2.12" };
}; typedef struct test_func_entry test_func_t;
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");
}
}
}
void test_load_header() { void test_load_header() {
xdb_header_t *header = xdb_load_header_from_file("../../data/ip2region_v4.xdb"); 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); 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 // valgrind --tool=memcheck --leak-check=full ./a.out
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
printf("test check ip ... \n"); int i;
test_check_ip(); char *name;
printf("|--done\n\n");
printf("test load header ... \n"); // check and call the function
test_load_header(); if (argc < 2) {
printf("|--done\n\n"); printf("please specified the function name to call\n");
return 1;
}
printf("test load vector index ... \n"); name = argv[1];
test_load_vector_index(); test_func_ptr func = NULL;
printf("|--done\n\n"); for (i = 0; ; i++) {
if (_test_function_list[i].name == NULL) {
break;
}
printf("test load content ... \n"); if (strcmp(name, _test_function_list[i].name) == 0) {
test_load_content(); func = _test_function_list[i].func;
printf("|--done\n\n"); break;
}
}
if (func == NULL) {
printf("can't find test function `%s`\n", name);
return 1;
}
// call the function
func();
return 0; return 0;
} }

View File

@ -17,10 +17,17 @@
# define XDB_PUBLIC(type) extern __declspec(dllexport) type # define XDB_PUBLIC(type) extern __declspec(dllexport) type
# define XDB_PRIVATE(type) static type # define XDB_PRIVATE(type) static type
# define XDB_WINDOWS # define XDB_WINDOWS
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#elif ( defined(linux) || defined(_UNIX) || defined(__APPLE__) ) #elif ( defined(linux) || defined(_UNIX) || defined(__APPLE__) )
# define XDB_PUBLIC(type) extern type # define XDB_PUBLIC(type) extern type
# define XDB_PRIVATE(type) static inline type # define XDB_PRIVATE(type) static inline type
# define XDB_LINUX # define XDB_LINUX
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif #endif
#define xdb_calloc( _blocks, _bytes ) calloc( _blocks, _bytes ) #define xdb_calloc( _blocks, _bytes ) calloc( _blocks, _bytes )
@ -37,6 +44,8 @@
// --- ip version info // --- ip version info
#define xdb_ipv4_version_no 4 #define xdb_ipv4_version_no 4
#define xdb_ipv6_version_no 6 #define xdb_ipv6_version_no 6
#define xdb_ipv4_bytes 4
#define xdb_ipv6_bytes 16
#define XDB_IPV4 4 #define XDB_IPV4 4
#define XDB_IPv6 6 #define XDB_IPv6 6
@ -49,6 +58,11 @@ typedef unsigned char bytes_ip_t;
// --- xdb util functions // --- 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 // get the current time in microseconds
XDB_PUBLIC(long) xdb_now(); 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. // convert a specified ip bytes to humen-readable string.
// returns: 0 for success or -1 for failed. // 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 // ipv4 bytes to string
XDB_PUBLIC(int) xdb_v4_ip_to_string(const bytes_ip_t *, char *, size_t); XDB_PUBLIC(int) xdb_v4_ip_to_string(const bytes_ip_t *, char *, size_t);

View File

@ -15,7 +15,27 @@
// @Note: since 2023/10/13 to compatible with the windows system // @Note: since 2023/10/13 to compatible with the windows system
#ifdef XDB_WINDOWS #ifdef XDB_WINDOWS
#include <windows.h> 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) { XDB_PRIVATE(int) gettimeofday(struct timeval* tp, void* tzp) {
time_t clock; time_t clock;
struct tm tm; struct tm tm;
@ -33,6 +53,9 @@ XDB_PRIVATE(int) gettimeofday(struct timeval* tp, void* tzp) {
tp->tv_usec = wtm.wMilliseconds * 1000; tp->tv_usec = wtm.wMilliseconds * 1000;
return (0); return (0);
} }
#else
XDB_PUBLIC(int) xdb_init_winsock() {return 0;}
XDB_PUBLIC(void) xdb_clean_winsock() {}
#endif #endif
XDB_PUBLIC(long) xdb_now() { 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); 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) { XDB_PUBLIC(int) xdb_parse_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
// where there is a . there is a IPV4 even though there are IPv6 wrapped IPv4 like // version check
// ::ffff:192.168.1.100, lets just keep it in this way. if (strchr(ip_string, '.') != NULL && strchr(ip_string, ':') == NULL) {
if (strchr(ip, '.') != NULL) { return xdb_parse_v4_ip(ip_string, buffer, length);
return xdb_parse_v4_ip(ip, buffer, length); } else if (strchr(ip_string, ':') != NULL) {
} else if (strchr(ip, ':') != NULL) { return xdb_parse_v6_ip(ip_string, buffer, length);
return xdb_parse_v6_ip(ip, buffer, length);
} }
return -1; return -1;
} }
XDB_PUBLIC(int) xdb_parse_v4_ip(const string_ip_t *ip, bytes_ip_t *buffer, size_t length) { XDB_PUBLIC(int) xdb_parse_v4_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
return 0; 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) { XDB_PUBLIC(int) xdb_parse_v6_ip(const string_ip_t *ip_string, bytes_ip_t *buffer, size_t length) {
return 0; 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) { XDB_PUBLIC(int) xdb_ip_to_string(const bytes_ip_t *ip_bytes, int version, char *ip_string, size_t length) {
if (bytes == 4) { if (version == xdb_ipv4_version_no) {
return xdb_v4_ip_to_string(ip, buffer, length); return xdb_v4_ip_to_string(ip_bytes, ip_string, length);
} else if (bytes == 16) { } else if (version == xdb_ipv6_version_no) {
return xdb_v6_ip_to_string(ip, buffer, length); return xdb_v6_ip_to_string(ip_bytes, ip_string, length);
} }
return -1; return -1;
} }
XDB_PUBLIC(int) xdb_v4_ip_to_string(const bytes_ip_t *ip, char *buffer, size_t length) { XDB_PUBLIC(int) xdb_v4_ip_to_string(const bytes_ip_t *ip_bytes, char *ip_string, size_t length) {
snprintf( if (!ip_bytes || !ip_string || length == 0) {
buffer, length, return -1;
"%d.%d.%d.%d", }
ip[0], ip[1], ip[2], ip[3]
); // buffer length checking
if (length < INET_ADDRSTRLEN) {
return -1;
}
if (inet_ntop(AF_INET, ip_bytes, ip_string, length) == NULL) {
return -1;
}
return 0; return 0;
} }
XDB_PUBLIC(int) xdb_v6_ip_to_string(const bytes_ip_t *ip, char *buffer, size_t length) { XDB_PUBLIC(int) xdb_v6_ip_to_string(const bytes_ip_t *ip_bytes, char *ip_string, size_t length) {
// temp solution for testing ONLY, we will handle the :: later if (!ip_bytes || !ip_string || length == 0) {
snprintf( return -1;
buffer, length, }
"%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x",
ip[0], ip[1], if (length < INET6_ADDRSTRLEN) {
ip[2], ip[3], return -1;
ip[4], ip[5], }
ip[6], ip[7],
ip[8], ip[9], if (inet_ntop(AF_INET6, ip_bytes, ip_string, length) == NULL) {
ip[10], ip[11], return -1;
ip[12], ip[13], }
ip[14], ip[15]
);
return 0; 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, size_t length, const char *buffer, int offset) {
int i, i1, i2; register int i, i1, i2;
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
i1 = ip1[i] & 0xFF; i1 = ip1[i];
i2 = buffer[offset + i] & 0xFF; i2 = buffer[offset + i] & 0xFF;
if (i1 > i2) { if (i1 > i2) {
return 1; return 1;