411 lines
10 KiB
C
411 lines
10 KiB
C
// Copyright 2022 The Ip2Region Authors. All rights reserved.
|
|
// Use of this source code is governed by a Apache2.0-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// ---
|
|
// @Author Lion <chenxin619315@gmail.com>
|
|
// @Date 2022/06/27
|
|
|
|
#include "xdb_api.h"
|
|
|
|
// for Linux
|
|
#ifdef XDB_LINUX
|
|
#include "sys/time.h"
|
|
#endif
|
|
|
|
// @Note: since 2023/10/13 to compatible with the windows system
|
|
#ifdef XDB_WINDOWS
|
|
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;
|
|
SYSTEMTIME wtm;
|
|
GetLocalTime(&wtm);
|
|
tm.tm_year = wtm.wYear - 1900;
|
|
tm.tm_mon = wtm.wMonth - 1;
|
|
tm.tm_mday = wtm.wDay;
|
|
tm.tm_hour = wtm.wHour;
|
|
tm.tm_min = wtm.wMinute;
|
|
tm.tm_sec = wtm.wSecond;
|
|
tm.tm_isdst = -1;
|
|
clock = mktime(&tm);
|
|
tp->tv_sec = clock;
|
|
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() {
|
|
struct timeval c_time;
|
|
gettimeofday(&c_time, NULL);
|
|
return c_time.tv_sec * (int)1e6 + c_time.tv_usec;
|
|
}
|
|
|
|
XDB_PUBLIC(unsigned int) xdb_le_get_uint32(const char *buffer, int offset) {
|
|
return (
|
|
((buffer[offset ]) & 0x000000FF) |
|
|
((buffer[offset+1] << 8) & 0x0000FF00) |
|
|
((buffer[offset+2] << 16) & 0x00FF0000) |
|
|
((buffer[offset+3] << 24) & 0xFF000000)
|
|
);
|
|
}
|
|
|
|
XDB_PUBLIC(int) xdb_le_get_uint16(const char *buffer, int offset) {
|
|
return (
|
|
((buffer[offset ]) & 0x000000FF) |
|
|
((buffer[offset+1] << 8) & 0x0000FF00)
|
|
);
|
|
}
|
|
|
|
// 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) {
|
|
// 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_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_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_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_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_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) {
|
|
register int i, i1, i2;
|
|
for (i = 0; i < length; i++) {
|
|
i1 = ip1[i];
|
|
i2 = buffer[offset + i] & 0xFF;
|
|
if (i1 > i2) {
|
|
return 1;
|
|
} else if (i1 < i2) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// --- xdb buffer function implementations
|
|
|
|
XDB_PUBLIC(xdb_header_t *) xdb_load_header(FILE *handle) {
|
|
xdb_header_t *header;
|
|
unsigned int size = xdb_header_info_length;
|
|
|
|
// entry alloc
|
|
header = (xdb_header_t *) xdb_malloc(sizeof(xdb_header_t));
|
|
if (header == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (fseek(handle, 0, SEEK_SET) == -1) {
|
|
xdb_free(header);
|
|
return NULL;
|
|
}
|
|
|
|
if (fread(header->buffer, 1,size, handle) != size) {
|
|
xdb_free(header);
|
|
return NULL;
|
|
}
|
|
|
|
// fill the fields
|
|
header->length = size;
|
|
header->version = (unsigned short) xdb_le_get_uint16(header->buffer, 0);
|
|
header->index_policy = (unsigned short) xdb_le_get_uint16(header->buffer, 2);
|
|
header->created_at = xdb_le_get_uint32(header->buffer, 4);
|
|
header->start_index_ptr = xdb_le_get_uint32(header->buffer, 8);
|
|
header->end_index_ptr = xdb_le_get_uint32(header->buffer,12);
|
|
|
|
// since IPv6 supporting
|
|
header->ip_version = xdb_le_get_uint16(header->buffer, 16);
|
|
header->runtime_ptr_bytes = xdb_le_get_uint16(header->buffer, 18);
|
|
|
|
return header;
|
|
}
|
|
|
|
XDB_PUBLIC(xdb_header_t *) xdb_load_header_from_file(const char *db_path) {
|
|
xdb_header_t *header;
|
|
FILE *handle = fopen(db_path, "rb");
|
|
if (handle == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
header = xdb_load_header(handle);
|
|
fclose(handle);
|
|
return header;
|
|
}
|
|
|
|
XDB_PUBLIC(void) xdb_free_header(void *ptr) {
|
|
xdb_header_t *header = (xdb_header_t *) ptr;
|
|
if (header->length > 0) {
|
|
header->length = 0;
|
|
xdb_free(header);
|
|
}
|
|
}
|
|
|
|
// --- vector index
|
|
|
|
XDB_PUBLIC(xdb_vector_index_t *) xdb_load_vector_index(FILE *handle) {
|
|
xdb_vector_index_t *v_index;
|
|
unsigned int size = xdb_vector_index_length;
|
|
|
|
// seek to the vector index offset
|
|
if (fseek(handle, xdb_header_info_length, SEEK_SET) == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
// do the buffer read
|
|
v_index = (xdb_vector_index_t *) xdb_malloc(sizeof(xdb_vector_index_t));
|
|
if (v_index == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
v_index->length = size;
|
|
if (fread(v_index->buffer, 1, size, handle) != size) {
|
|
xdb_free(v_index);
|
|
return NULL;
|
|
}
|
|
|
|
return v_index;
|
|
}
|
|
|
|
XDB_PUBLIC(xdb_vector_index_t *) xdb_load_vector_index_from_file(const char *db_path) {
|
|
xdb_vector_index_t *v_index;
|
|
FILE *handle = fopen(db_path, "rb");
|
|
if (handle == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
v_index = xdb_load_vector_index(handle);
|
|
fclose(handle);
|
|
return v_index;
|
|
}
|
|
|
|
XDB_PUBLIC(void) xdb_free_vector_index(void *ptr) {
|
|
xdb_vector_index_t *v_index = (xdb_vector_index_t *) ptr;
|
|
if (v_index->length > 0) {
|
|
v_index->length = 0;
|
|
xdb_free(v_index);
|
|
}
|
|
}
|
|
|
|
// --- content buffer
|
|
|
|
XDB_PUBLIC(xdb_content_t *) xdb_load_content(FILE *handle) {
|
|
unsigned int size;
|
|
xdb_content_t *content;
|
|
|
|
// determine the file size
|
|
if (fseek(handle, 0, SEEK_END) == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
size = (unsigned int) ftell(handle);
|
|
if (fseek(handle, 0, SEEK_SET) == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
// do the file read
|
|
content = (xdb_content_t *) xdb_malloc(sizeof(xdb_content_t));
|
|
if (content == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
// do the buffer alloc
|
|
content->buffer = (char *) xdb_malloc(size);
|
|
if (content->buffer == NULL) {
|
|
xdb_free(content);
|
|
return NULL;
|
|
}
|
|
|
|
// read the content into the buffer
|
|
content->length = size;
|
|
if (fread(content->buffer, 1, size, handle) != size) {
|
|
xdb_free(content);
|
|
return NULL;
|
|
}
|
|
|
|
return content;
|
|
}
|
|
|
|
XDB_PUBLIC(xdb_content_t *) xdb_load_content_from_file(const char *db_path) {
|
|
xdb_content_t *content;
|
|
FILE *handle = fopen(db_path, "rb");
|
|
if (handle == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
content = xdb_load_content(handle);
|
|
fclose(handle);
|
|
return content;
|
|
}
|
|
|
|
XDB_PUBLIC(void) xdb_free_content(void *ptr) {
|
|
xdb_content_t *content = (xdb_content_t *) ptr;
|
|
if (content->length > 0) {
|
|
content->length = 0;
|
|
xdb_free(content->buffer);
|
|
content->buffer = NULL;
|
|
xdb_free(content);
|
|
}
|
|
}
|
|
|
|
// --- 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];
|
|
} |