Ipv6 search is ready

This commit is contained in:
lion 2025-09-21 00:45:45 +08:00
parent b01253e6b3
commit 2fe0d1f59e
4 changed files with 224 additions and 65 deletions

View File

@ -62,10 +62,29 @@ if string.len(dbFile) < 2 or string.len(srcFile) < 2 then
return
end
-- verify the xdb from header
if xdb.verify(dbFile) == false then
print(string.format("failed to verify the xdb file: %s", dbFile))
return
end
-- detect the version from the xdb header
header, err = xdb.load_header(dbFile)
if err ~= nil then
print(string.format("failed to load header: %s", err))
return
end
version, err = xdb.version_from_header(header);
if err ~= nil then
print(string.format("failed to detect version from header: %s", err))
return
end
-- create the searcher based on the cache-policy
local searcher, v_index, content
if cachePolicy == "file" then
searcher, err = xdb.new_with_file_only(dbFile)
searcher, err = xdb.new_with_file_only(version, dbFile)
if err ~= nil then
print(string.format("failed to create searcher: %s", err))
return
@ -77,7 +96,7 @@ elseif cachePolicy == "vectorIndex" then
return
end
searcher, err = xdb.new_with_vector_index(dbFile, v_index)
searcher, err = xdb.new_with_vector_index(version, dbFile, v_index)
if err ~= nil then
print(string.format("failed to create vector index searcher: %s", err))
return
@ -89,7 +108,7 @@ elseif cachePolicy == "content" then
return
end
searcher, err = xdb.new_with_buffer(content)
searcher, err = xdb.new_with_buffer(version, content)
if err ~= nil then
print(string.format("failed to create content buffer searcher: %s", err))
return
@ -116,7 +135,7 @@ for l in lines do
goto continue
end
for v1, v2, v3 in string.gmatch(l, "([%d%.]+)|([%d%.]+)|([^\n]+)") do
for v1, v2, v3 in string.gmatch(l, "([^|]+)|([^|]+)|([^\n]+)") do
-- print(sip_str, eip_str, region)
sip_str = v1
eip_str = v2
@ -124,36 +143,35 @@ for l in lines do
break
end
sip, err = xdb.check_ip(sip_str)
sip_bytes, err = xdb.parse_ip(sip_str)
if err ~= nil then
print(string.format("invalid start ip `%s`", sip_str))
return
end
eip, err = xdb.check_ip(eip_str)
eip_bytes, err = xdb.parse_ip(eip_str)
if err ~= nil then
print(string.format("invalid end ip `%s`", sip_str))
return
end
if sip > eip then
if xdb.ip_compare(sip_bytes, eip_bytes) > 0 then
print(string.format("start ip(%s) should not be greater than end ip(%s)\n", sip_str, eip_str))
return
end
mip = (sip + eip) >> 1
for _, ip in ipairs({sip, (sip + mip) >> 1, mip, (mip + eip) >> 1, eip}) do
for _, ip_bytes in ipairs({sip_bytes, eip_bytes}) do
t_time = xdb.now()
region, err = searcher:search(ip)
region, err = searcher:search(ip_bytes)
c_time = c_time + xdb.now() - t_time
if err ~= nil then
print(string.format("failed to search ip `%s`", xdb.long2ip(ip)))
print(string.format("failed to search ip `%s`", xdb.ip_to_string(ip_bytes)))
return
end
-- check the region
if region ~= s_region then
printf(string.format("failed search(%s) with (%s != %s)\n", xdb.long2ip(ip), region, s_region))
printf(string.format("failed search(%s) with (%s != %s)\n", xdb.ip_to_string(ip_bytes), region, s_region))
return
end
@ -172,6 +190,8 @@ if content ~= nil then
content:close()
end
xdb.cleanup();
-- print the stats
local avg_costs = 0
if count > 0 then

View File

@ -59,7 +59,24 @@ if string.len(dbFile) < 2 then
return
end
local version = xdb.IPv4
-- verify the xdb from header
if xdb.verify(dbFile) == false then
print(string.format("failed to verify the xdb file: %s", dbFile))
return
end
-- detect the version from the xdb header
header, err = xdb.load_header(dbFile)
if err ~= nil then
print(string.format("failed to load header: %s", err))
return
end
version, err = xdb.version_from_header(header);
if err ~= nil then
print(string.format("failed to detect version from header: %s", err))
return
end
-- create the searcher based on the cache-policy
local searcher, v_index, content
@ -100,8 +117,9 @@ end
-- do the search
print(string.format([[
ip2region xdb searcher test program, cachePolicy: %s
type 'quit' to exit]], cachePolicy))
ip2region xdb searcher test program
source xdb: %s (%s, %s)
type 'quit' to exit]], dbFile, "IPv4", cachePolicy))
local region, err = "", nil
local ip_int, s_time, c_time = 0, 0, 0
while ( true ) do
@ -144,3 +162,5 @@ end
if content ~= nil then
content:close()
end
xdb.cleanup();

View File

@ -24,7 +24,8 @@ function test_parse_ip()
if err ~= nil then
print(string.format("invalid ip address `%s`: %s", ip_src, err))
else
print(string.format("parse_ip(%s): %s", ip_src, xdb.ip_to_string(ip_bytes)))
local ip_string = xdb.ip_to_string(ip_bytes);
print(string.format("parse_ip(%s)->%s ? %s", ip_src, ip_string, ip_src==ip_string))
end
end
end
@ -116,4 +117,5 @@ local s_time = xdb.now();
print(string.format("+---calling test function %s ...", func_name))
_G[func_name]();
local cost_time = xdb.now() - s_time
xdb.cleanup();
print(string.format("|---done, took: %.3fμs", cost_time))

View File

@ -257,16 +257,48 @@ static int lua_xdb_load_content_from_file(lua_State *L) {
return 2;
}
static int lua_xdb_version_from_header(lua_State *L) {
xdb_version_t *version;
xdb_buffer_t *buffer;
luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and xdb header expected");
// header buffer checking
buffer = luaL_checkudata(L, 1, XDB_BUFFER_METATABLE_NAME);
if (buffer->type != xdb_header_buffer) {
return luaL_error(L, "invalid xdb header buffer");
}
version = xdb_version_from_header((xdb_header_t *) buffer->ptr);
if (version == NULL) {
lua_pushnil(L);
lua_pushstring(L, "failed to detect version from header");
} else {
lua_pushlightuserdata(L, version);
lua_pushnil(L);
}
return 2;
}
static int lua_xdb_verify_from_file(lua_State *L) {
const char *db_path;
luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and the xdb file path expected");
db_path = luaL_checkstring(L, 1);
lua_pushboolean(L, xdb_verify_from_file(db_path) == 0 ? 1 : 0);
return 1;
}
static int lua_xdb_parse_ip(lua_State *L) {
int err;
const char *ip_str;
bytes_ip_t ip_bytes[18] = {'\0'};
bytes_ip_t ip_bytes[19] = {'\0'};
xdb_version_t *version;
luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and string ip expected, eg: 1.2.3.4 / 3000::");
ip_str = luaL_checkstring(L, 1);
version = xdb_parse_ip(ip_str, ip_bytes, sizeof(ip_bytes));
version = xdb_parse_ip(ip_str, ip_bytes + 2, sizeof(ip_bytes) - 2);
if (version == NULL) {
lua_pushnil(L);
lua_pushfstring(L, "failed to parse the `%s`", ip_str);
@ -275,32 +307,46 @@ static int lua_xdb_parse_ip(lua_State *L) {
// append the magic char for later analysis
// printf("ip:%s, version->id: %d\n", ip_str, version->id);
ip_bytes[version->bytes] = '&';
ip_bytes[version->bytes+1] = '\0';
lua_pushstring(L, ip_bytes);
ip_bytes[0] = '&';
ip_bytes[1] = (bytes_ip_t) version->id;
lua_pushlstring(L, ip_bytes, version->bytes + 2);
lua_pushnil(L);
return 2;
}
static int lua_xdb_ip_to_string(lua_State *L) {
int err, len;
int err, vid, bytes;
const bytes_ip_t *ip_bytes;
char ip_string[INET6_ADDRSTRLEN] = {'\0'};
char ip_string[INET6_ADDRSTRLEN + 1] = {'\0'};
luaL_argcheck(L, lua_gettop(L) == 1, 1, "call via '.' and bytes ip expected");
ip_bytes = luaL_checkstring(L, 1);
len = strlen(ip_bytes);
if (len == 5 && ip_bytes[4] == '&') {
// binary IPv4 bytes
} else if (len == 17 || ip_bytes[16] == '&') { // IPv6
// binary IPv6 bytes
if (strlen(ip_bytes) < 2) {
lua_pushnil(L);
lua_pushstring(L, "invalid binary ip bytes specified");
return 2;
}
if (ip_bytes[0] != '&') {
lua_pushnil(L);
lua_pushstring(L, "invalid binary ip bytes specified");
return 2;
}
vid = ip_bytes[1] & 0xFF;
if (vid == xdb_ipv4_id) {
// IPv4
bytes = xdb_ipv4_bytes;
} else if (vid == xdb_ipv6_id) {
// IPv6
bytes = xdb_ipv6_bytes;
} else {
lua_pushnil(L);
lua_pushstring(L, "invalid binary ip bytes specified");
return 2;
}
err = xdb_ip_to_string(ip_bytes, len-1, ip_string, sizeof(ip_string));
err = xdb_ip_to_string(ip_bytes + 2, bytes, ip_string, sizeof(ip_string));
if (err != 0) {
lua_pushnil(L);
lua_pushstring(L, "failed to conver the ip bytes to string");
@ -312,6 +358,59 @@ static int lua_xdb_ip_to_string(lua_State *L) {
return 2;
}
static int _validate_bytes_ip(const bytes_ip_t *ip_bytes) {
if (strlen(ip_bytes) < 2) {
return 1;
}
if (ip_bytes[0] != '&') {
return 2;
}
int vid = ip_bytes[1] & 0xFF;
if (vid != xdb_ipv4_id && vid != xdb_ipv6_id) {
return 3;
}
return 0;
}
static int lua_xdb_ip_compare(lua_State *L) {
int err, vid, bytes;
const bytes_ip_t *ip1_bytes, *ip2_bytes;
luaL_argcheck(L, lua_gettop(L) == 2, 1, "call via '.' bytes ip1 and ip2 expected");
ip1_bytes = luaL_checkstring(L, 1);
ip2_bytes = luaL_checkstring(L, 2);
// validate the ip1
err = _validate_bytes_ip(ip1_bytes);
if (err != 0) {
lua_pushnil(L);
lua_pushfstring(L, "failed to validate ip1 with errcode=%d", err);
return 2;
}
// validate the ip2
err = _validate_bytes_ip(ip2_bytes);
if (err != 0) {
lua_pushnil(L);
lua_pushfstring(L, "failed to validate ip2 with errcode=%d", err);
return 2;
}
if (ip1_bytes[1] != ip2_bytes[1]) {
lua_pushnil(L);
lua_pushstring(L, "ip version of ip1 and ip2 are not the same");
return 2;
}
err = xdb_ip_sub_compare(ip1_bytes + 2, (ip1_bytes[1] & 0xFF), ip2_bytes, 2);
lua_pushinteger(L, err);
lua_pushnil(L);
return 2;
}
static int lua_xdb_now(lua_State *L) {
lua_pushinteger(L, xdb_now());
return 1;
@ -332,13 +431,10 @@ static int lua_xdb_new_with_file_only(lua_State *L) {
luaL_argcheck(L, lua_gettop(L) == 2, 1, "call via '.' and ip version / xdb file path expected");
// check the ip version
vid = luaL_checkinteger(L, 1);
if (vid == xdb_ipv4_id) {
version = XDB_IPv4;
} else if (vid == xdb_ipv6_id) {
version = XDB_IPv6;
if (!lua_islightuserdata(L, 1)) {
return luaL_error(L, "invalid verison resouce specified");
} else {
return luaL_error(L, "invalid verison id (`%d`) specified", vid);
version = (xdb_version_t *) lua_touserdata(L, 1);
}
// check the db path
@ -372,18 +468,15 @@ static int lua_xdb_new_with_vector_index(lua_State *L) {
xdb_searcher_t *searcher;
xdb_buffer_t *xBuffer;
const char *db_path;
int err, vid;
int err;
luaL_argcheck(L, lua_gettop(L) == 3, 1, "call via '.', ip version / xdb file path / vector index buffer expected");
// ip version checking
vid = luaL_checkinteger(L, 1);
if (vid == xdb_ipv4_id) {
version = XDB_IPv4;
} else if (vid == xdb_ipv6_id) {
version = XDB_IPv6;
// check the ip version
if (!lua_islightuserdata(L, 1)) {
return luaL_error(L, "invalid verison resouce specified");
} else {
return luaL_error(L, "invalid verison id (`%d`) specified", vid);
version = (xdb_version_t *) lua_touserdata(L, 1);
}
// db_path checking
@ -422,18 +515,15 @@ static int lua_xdb_new_with_buffer(lua_State *L) {
xdb_version_t *version;
xdb_searcher_t *searcher;
xdb_buffer_t *xBuffer;
int err, vid;
int err;
luaL_argcheck(L, lua_gettop(L) == 2, 1, "call via '.' and ip version / xdb content buffer expected");
// ip version checking
vid = luaL_checkinteger(L, 1);
if (vid == xdb_ipv4_id) {
version = XDB_IPv4;
} else if (vid == xdb_ipv6_id) {
version = XDB_IPv6;
// check the ip version
if (!lua_islightuserdata(L, 1)) {
return luaL_error(L, "invalid verison resouce specified");
} else {
return luaL_error(L, "invalid verison id (`%d`) specified", vid);
version = (xdb_version_t *) lua_touserdata(L, 1);
}
// content buffer checking
@ -479,7 +569,7 @@ static int lua_xdb_close(lua_State *L) {
}
static int lua_xdb_search(lua_State *L) {
int err, len, ip_len;
int err, vid, ip_len;
const char *ip_string;
bytes_ip_t ip_buffer[INET6_ADDRSTRLEN] = {'\0'};
const bytes_ip_t *ip_bytes;
@ -495,16 +585,26 @@ static int lua_xdb_search(lua_State *L) {
ip_string = luaL_checkstring(L, 2);
// ip string type checking
len = strlen(ip_string);
if (len == 5 && ip_string[4] == '&') {
// binary IPv4
ip_len = 4;
ip_bytes = ip_string;
} else if (len == 17 && ip_string[16] == '&') {
// binary IPv6
ip_len = 16;
ip_bytes = ip_string;
printf("ipv6 binary string\n");
if (strlen(ip_string) < 2) {
lua_pushnil(L);
lua_pushfstring(L, "invalid ip address `%s`", ip_string);
return 2;
}
if (ip_string[0] == '&') {
vid = ip_string[1] & 0xFF;
if (vid == xdb_ipv4_id) {
ip_len = xdb_ipv4_bytes;
} else if (vid == xdb_ipv6_id) {
ip_len = xdb_ipv6_bytes;
} else {
lua_pushnil(L);
lua_pushstring(L, "invalid binary ip bytes specified");
return 2;
}
ip_bytes = ip_string + 2;
// printf("ip_len: %d, vid: %d\n", ip_len, vid);
} else {
version = xdb_parse_ip(ip_string, ip_buffer, sizeof(ip_buffer));
if (version == NULL) {
@ -552,6 +652,12 @@ static int lua_xdb_tostring(lua_State *L) {
return 1;
}
// cleanup the current module
static int lua_xdb_cleanup(lua_State *L) {
xdb_clean_winsock();
return 0;
}
// module method define, should be access via ':'
static const struct luaL_Reg xdb_searcher_methods[] = {
{"search", lua_xdb_search},
@ -570,15 +676,26 @@ static const struct luaL_Reg xdb_searcher_functions[] = {
{"load_header", lua_xdb_load_header_from_file},
{"load_vector_index", lua_xdb_load_vector_index_from_file},
{"load_content", lua_xdb_load_content_from_file},
{"verify", lua_xdb_verify_from_file},
{"version_from_header", lua_xdb_version_from_header},
{"parse_ip", lua_xdb_parse_ip},
{"ip_to_string", lua_xdb_ip_to_string},
{"ip_compare", lua_xdb_ip_compare},
{"now", lua_xdb_now},
{"close", lua_xdb_close},
{"cleanup", lua_xdb_cleanup},
{NULL, NULL}
};
// module register function
int luaopen_xdb_searcher(lua_State *L)
{
int err = xdb_init_winsock();
if (err != 0) {
luaL_error(L, "failed to init the winsock with errno=%d\n", err);
return 1;
}
// create a metatable for xdb buffer object
luaL_newmetatable(L, XDB_BUFFER_METATABLE_NAME);
lua_pushvalue(L, -1);
@ -593,9 +710,9 @@ int luaopen_xdb_searcher(lua_State *L)
luaL_setfuncs(L, xdb_searcher_functions, 0);
// register the constants attributes
lua_pushinteger(L, xdb_ipv4_id);
lua_pushlightuserdata(L, XDB_IPv4);
lua_setfield(L, -2, "IPv4");
lua_pushinteger(L, xdb_ipv6_id);
lua_pushlightuserdata(L, XDB_IPv6);
lua_setfield(L, -2, "IPv6");
lua_pushinteger(L, xdb_header_buffer);
lua_setfield(L, -2, "header_buffer");