mirror of
https://github.com/lionsoul2014/ip2region.git
synced 2025-12-08 19:25:22 +00:00
ip parse / to_string / compare util function is ready
This commit is contained in:
parent
0fd0bc59d0
commit
4cff9eb6ee
Binary file not shown.
@ -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;
|
||||
}
|
||||
|
||||
@ -17,10 +17,17 @@
|
||||
# define XDB_PUBLIC(type) extern __declspec(dllexport) type
|
||||
# define XDB_PRIVATE(type) static type
|
||||
# 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__) )
|
||||
# define XDB_PUBLIC(type) extern type
|
||||
# define XDB_PRIVATE(type) static inline type
|
||||
# define XDB_LINUX
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#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);
|
||||
|
||||
@ -15,7 +15,27 @@
|
||||
|
||||
// @Note: since 2023/10/13 to compatible with the windows system
|
||||
#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) {
|
||||
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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user