From 2fe0d1f59eaa1bf372dfe29c0b6cee50472f6319 Mon Sep 17 00:00:00 2001 From: lion Date: Sun, 21 Sep 2025 00:45:45 +0800 Subject: [PATCH] Ipv6 search is ready --- binding/lua_c/bench_test.lua | 44 +++++-- binding/lua_c/search_test.lua | 28 ++++- binding/lua_c/util_test.lua | 4 +- binding/lua_c/xdb_searcher.c | 213 ++++++++++++++++++++++++++-------- 4 files changed, 224 insertions(+), 65 deletions(-) diff --git a/binding/lua_c/bench_test.lua b/binding/lua_c/bench_test.lua index af1df2c..6534c65 100644 --- a/binding/lua_c/bench_test.lua +++ b/binding/lua_c/bench_test.lua @@ -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 diff --git a/binding/lua_c/search_test.lua b/binding/lua_c/search_test.lua index 6f48f1a..762b0b3 100644 --- a/binding/lua_c/search_test.lua +++ b/binding/lua_c/search_test.lua @@ -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 @@ -143,4 +161,6 @@ if v_index ~= nil then end if content ~= nil then content:close() -end \ No newline at end of file +end + +xdb.cleanup(); \ No newline at end of file diff --git a/binding/lua_c/util_test.lua b/binding/lua_c/util_test.lua index 20fe708..eb2b41a 100644 --- a/binding/lua_c/util_test.lua +++ b/binding/lua_c/util_test.lua @@ -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)) \ No newline at end of file diff --git a/binding/lua_c/xdb_searcher.c b/binding/lua_c/xdb_searcher.c index 217ddbe..c3a899d 100644 --- a/binding/lua_c/xdb_searcher.c +++ b/binding/lua_c/xdb_searcher.c @@ -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");