From dff3084b93faee923469980215f55eadda518743 Mon Sep 17 00:00:00 2001 From: lion Date: Thu, 18 Sep 2025 23:09:19 +0800 Subject: [PATCH] C binding is ready for IPv6 --- binding/c/main.c | 67 +++++++++++++++++++++++++++++---------- binding/c/test_util | Bin 22448 -> 22576 bytes binding/c/xdb_api.h | 18 +++++++++-- binding/c/xdb_searcher.c | 21 ++++++++---- binding/c/xdb_util.c | 55 ++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 25 deletions(-) diff --git a/binding/c/main.c b/binding/c/main.c index eef96a8..1280666 100644 --- a/binding/c/main.c +++ b/binding/c/main.c @@ -17,23 +17,35 @@ struct searcher_test_entry { typedef struct searcher_test_entry searcher_test_t; int init_searcher_test(searcher_test_t *test, char *db_path, char *cache_policy) { - int err; + int err, errcode = 0; + FILE *handle = fopen(db_path, "rb"); + if (handle == NULL) { + return -1; + } // auto detect the version from the xdb header - xdb_header_t *header = xdb_load_header_from_file(db_path); + xdb_header_t *header = xdb_load_header(handle); if (header == NULL) { printf("failed to load header from `%s`\n", db_path); - return 1; + errcode = 1; + goto defer; + } + + // verify the current xdb + err = xdb_verify_from_header(handle, header); + if (err != 0) { + printf("failed to verify xdb file `%s` with errno=%d\n", db_path, err); + errcode = 2; + goto defer; } xdb_version_t *version = xdb_version_from_header(header); if (version == NULL) { printf("failed to load version from header\n"); - xdb_free_header(header); - return 1; + errcode = 3; + goto defer; } - xdb_free_header(header); test->v_index = NULL; test->c_buffer = NULL; @@ -41,38 +53,53 @@ int init_searcher_test(searcher_test_t *test, char *db_path, char *cache_policy) err = xdb_new_with_file_only(version, &test->searcher, db_path); if (err != 0) { printf("failed to create searcher with errcode=%d\n", err); - return 1; + errcode = 4; + goto defer; } } else if (strcmp(cache_policy, "vectorIndex") == 0) { test->v_index = xdb_load_vector_index_from_file(db_path); if (test->v_index == NULL) { printf("failed to load vector index from `%s`\n", db_path); - return 2; + errcode = 4; + goto defer; } err = xdb_new_with_vector_index(version, &test->searcher, db_path, test->v_index); if (err != 0) { printf("failed to create vector index cached searcher with errcode=%d\n", err); - return 3; + errcode = 5; + goto defer; } } else if (strcmp(cache_policy, "content") == 0) { test->c_buffer = xdb_load_content_from_file(db_path); if (test->c_buffer == NULL) { printf("failed to load xdb content from `%s`\n", db_path); - return 4; + errcode = 4; + goto defer; } err = xdb_new_with_buffer(version, &test->searcher, test->c_buffer); if (err != 0) { printf("failed to create content cached searcher with errcode=%d\n", err); - return 5; + errcode = 5; + goto defer; } } else { printf("invalid cache policy `%s`, options: file/vectorIndex/content\n", cache_policy); - return 6; + errcode = 6; + goto defer; } - return 0; +defer: + if (header != NULL) { + xdb_free_header(header); + } + + if (handle != NULL) { + fclose(handle); + } + + return errcode; } void destroy_searcher_test(searcher_test_t *test) { @@ -125,6 +152,7 @@ void test_search(int argc, char *argv[]) { long s_time, c_time; unsigned int ip; char line[512] = {'\0'}, region[512] = {'\0'}; + char *region_buffer = NULL; // ip parse xdb_version_t *version; @@ -208,13 +236,17 @@ void test_search(int argc, char *argv[]) { } s_time = xdb_now(); - err = xdb_search(&test.searcher, ip_bytes, version->bytes, region, sizeof(region)); + err = xdb_search(&test.searcher, ip_bytes, version->bytes, ®ion_buffer, sizeof(region)); if (err != 0) { printf("{err: %d, io_count: %d}\n", err, xdb_get_io_count(&test.searcher)); } else { c_time = xdb_now() - s_time; - printf("{region: %s, io_count: %d, took: %ld μs}\n", region, xdb_get_io_count(&test.searcher), c_time); + printf("{region: %s, io_count: %d, took: %ld μs}\n", region_buffer, xdb_get_io_count(&test.searcher), c_time); } + + // free the region_buffer + xdb_free(region_buffer); + region_buffer = NULL; } destroy_searcher_test(&test); @@ -229,7 +261,8 @@ void test_bench(int argc, char *argv[]) { FILE *handle; char line[1024] = {'\0'}, sip_str[INET6_ADDRSTRLEN+1] = {'\0'}, eip_str[INET6_ADDRSTRLEN+1] = {'\0'}; - char src_region[512] = {'\0'}, region_buffer[512] = {'\0'}; + char src_region[512] = {'\0'}, region[512] = {'\0'}; + char *region_buffer = region; int count = 0, took; long s_time, t_time, c_time = 0; @@ -337,7 +370,7 @@ void test_bench(int argc, char *argv[]) { ip_list[1] = eip_bytes; for (i = 0; i < 2; i++) { t_time = xdb_now(); - err = xdb_search(&test.searcher, ip_list[i], s_version->bytes, region_buffer, sizeof(region_buffer)); + err = xdb_search(&test.searcher, ip_list[i], s_version->bytes, ®ion_buffer, sizeof(region)); c_time += xdb_now() - t_time; if (err != 0) { xdb_ip_to_string(ip_list[i], s_version->bytes, ip_string, sizeof(ip_string)); diff --git a/binding/c/test_util b/binding/c/test_util index 91a4af0eec9d50569295d400ea80bf3d65fd76d2..3024380d49e6a066fe52ca64f1b58aa7682eff22 100755 GIT binary patch delta 3652 zcmZWr3s6+o89sY?t$@1=EbN2VDjNYG2+BJ+vbx{}iK2iw6{B{9fF(*CXlSd2cEx&Y zHX}WzLlW!gw6%;)6~#uIs9gaA&1g%kcAWSCU&$IUVns!bo_^=gZ5yOAwNaTPI%*tO+CXs0pK?s-(c+V9zo*xU*1|uNqgX@~lhg`@(?U zpvmvm+6qG~yJjT0sI*~c=;=>8-|^YtE4ZR*pgKv&jiK3qT`_bGfW*=d0R5KE&((W1 zO=Tsb^jLHZtF?zCsvM7m`X3w-5FJyW2D|p~+R#tM3Do45nHtBq-T zR3=JKN|1oj{qA>+iBh*GNXv!#P*J)pO1Irh7-L&Y^w?61U`9EZCjc^#?ABnn^&u=U zQREjlcw{RTooRnE5K>m+J_S3m#Z|vZlzOp~?WpPvq~VT`H$KUga8deUg}Q!M}NTaUZ)+cbnq$=RrHhR1Gt$wCn6vct=O1(etLFs76INAQ#*j z-Ihv-P4XYw?bh6PcJnI&y+=Pa&kWml&lA~%$i7y{w`NjR zWP%WPk4}lq5#Af6HIW5E;V3;6DGFqiK8;);bljy2q9z9{48?6Nd_bF`%);X^`e9T| zQ`ji3)X`(X6)n4&|9~-1MgGpa7DWt#M~cgR>n?9CSXg1fTajN(iRhg5uMkAs4-)Ob z?>~O4&g=S?UUog`b^V7YxYBvfS&7iyP1pacME*0EtCC*mZFz%re1nC!!tZZT(t#xIQGwnba{bNkJaOV!a6q6WV206tgI!>zPs=7bEgF3L(3U` z3HChMZp$=@p^Uk}3Q10_@@h^V#QoOXk5^_cbW^$6BAp|sL6KcW`5$xE1u2c_t&;3b@v zrlFr%rUnQ|!F}#FeP~&cRL{#KeN!Y|kqcszkWN~MM()R@w|NPFgc9Cr_!Uakeur+J zki0kzs<(Q9Fu9qGr>0!tBIzo;lf1fn_*;onPmku&k0c-?p7ucosMY904}oWX$3ZKVU8}^Bcxi0@cH)995;qn|7gglX&^< z0qAZ*toWqj(?@MkJHBL0rn!WHUnr@^r=9*H-H>QOy%%sAgIn#wr{X2<5V$saB0Vg8 zI~1fOj|6;Q#Ah45nLb4ry+q&5nB>QsQB7?bVJbZ>%g9hwP-n)J@H$*(xW|j+09~-! zKu>4PR$ZjyGp96-K$j1&NTYKI#oZb;>I*wOvxzS*_-*c+r_pT|Y#O7(XP(9)R0L{_ zHjU1vQRfAbWXScfaxnAPXY2+w4{1)WFeRni9at(uXe*o79&LlI0 z)dCHQS$ebMqDY)2tXj3mWni{ase9&5oH7t>4OBM2&7EwwNDOfbV%hb+`xK zExgUQ!zQ2GysptzfamEo%Tb&;vpQ&7GAXRK#_zne~;gpw6L-=NuP0%rtavlAw#CbLJkO(H!ORYxMw0#RY~6 zA*3QsAr#2wJnD*f-Wm4S&EE7jDDrMa9x>9r_WT*%Y`W0feDJp5-Y(@by!YyhTi`q~ z(}{U|gl%T}dEV489T~xEB_DGC0(a0=c?Q!##d?s}8^hZ?J#<38!E{bh`z^9aevLi( zxWRo@W3(oJy6Op^7ie)6ayCjFZv)3DeE&=QG=;BIvU=MSnAqtR>|3m;x%i*q<9!d1 zG8!_^P_WkPtK6sDHn8}m!h7$rO!3;T@I=|mTdDo@t$BtNm!cM%J?7qiKjV!S>EYj0 zqFv=V;5Fcjc?Odn4aQHsQhE4zpFvit5)CP-idw9ky-tZxpzxNL@?TC({cu;{*4HuA7lHMNzUH(v`7I&Uw$;v<+t=$VqFKyUX}#L>Xg x&8kw`S~@+%g4cIGyg1zXMd@roRYyb0Gsaou#|j}|(?wVX;ID~~c-p!s_J8gUV~+p; delta 3133 zcmZuz4Nz3q6@Krr;tC7Pugk)&yIoOMiwGhtB8;qpKH|o%Mk1*{p;O8@1}$x2Y9?Ap zk;Ikk49v+mB%Nr@OzKX?nXVyDu)~-Qn2~Xk)Hq2?6XRbr-AEDvMTu#B{m#DkMr(U# zcE5YR@7#0mJ?Ff)8xD)%KZ`wXDg2Y(g%=a7X+msR(JrAu$^87 zbU6CY8sALLl!G(gC=-NXv!hD5Wu9{n_K7n3M^=UO+waL@UA#FdOAzG1&FDwpD@tGp zawgon&bQ`w{_td5e8*m~v~{%{EE%(?Zb#wv7d~EB1irK2E1PSE&_49g5$l4S*FA#J)Ok;8U04(W#oV!PX>w-Ila5Z)n(V$b z`?R8*Do1!6sWxyrnlw!l*>f}8pgX6uql7 zH+SecTZMFeicZ>UrB|oOV3#HT6s@zblY}WcWM4S*aJnEw4^Puy?b*`WOd7M#Y5)0@ zq97MeIdEz7*9UQEH6!mze4}8=W~?ZRL@U{gJzC+R7v>2$Sn1%13P?FHEO$j(^SV>? zrSE0NmP-0kE9!vY`?wScUHL5ZX#3LJTI3&i@1_FXfh*4&yo<(*9>&uD-Qc9U!Rva2 zlaFlhE8gIfTUz`-u=?Ney_;lfFtZOkV53Id#QS8EY~F>I%6uV{oQ}D2Gizt6b7ej= zYa___FF-b#o8M#m9PCEyV@|EkH8OFAzeW*nt?I@7`FI+2J67d=hfH)u%v~SF?%$ki zMD^cE6$D?fG1u=4Hs?0@f+b=mO*u*>?=4#7T#)w$DI|x z8p-x$INgBF4rL&0yM~#Lg1(}IIvQz9TFQWF~I6h4C#e%tmU?CDARo2zg`m-#{V zehQbb3l;8kyc~Rit62RzU5{3;pCe_g`0(5O5m!0dV_QIJg1tRO3GtC1VCo z49o|HfHKe>Rg~Sp{lGq86gU7JxS=RUvX^=y+**Wh-*IPLo)98=o+^nGbOzm>&a&jbg)%?+f^ZNc8+zGF_ws&%#V6ih-v) zHkRUB#+LcC)8mm^*SV<7g^$DVZYWxDQJA>C%$)s9~%As@NsB687%^~ounl7Bea zC~zAJGBg`B6KfdEZ2_0{2*(A@0GAZ=QvJBNDGzacu0C)kaD(hulT4eIE!cVv+{@rr zXlwaQ*T6-<)iNh17e1GeZ1m!{oc9+{C=pOjwQcbxd{%y=!uF#J1Ipw36euH*g%?r0Br))u9 z_;};&jCOmNXP10@xb^C<(op%r8tyvo+B()^`|iX&)+PE8#s+E&bne>!r~9Dqf$pZF z9~f9M|jRf zILY%O1M<#$wrG*{=OA6Z^Usz%dsOaJ=16_V(t-c6oaqp?3lc(KyQu=Z;Q%A?c`j{g9Yt(UX_ diff --git a/binding/c/xdb_api.h b/binding/c/xdb_api.h index 2e01e11..d044bff 100644 --- a/binding/c/xdb_api.h +++ b/binding/c/xdb_api.h @@ -106,6 +106,20 @@ XDB_PUBLIC(xdb_content_t *) xdb_load_content_from_file(const char *); XDB_PUBLIC(void) xdb_free_content(void *); +// --- xdb verify + +// Verify if the current Searcher could be used to search the specified xdb file. +// Why do we need this check ? +// The future features of the xdb impl may cause the current searcher not able to work properly. +// +// @Note: You Just need to check this ONCE when the service starts +// Or use another process (eg, A command) to check once Just to confirm the suitability. +XDB_PUBLIC(int) xdb_verify(FILE *); + +XDB_PUBLIC(int) xdb_verify_from_header(FILE *handle, xdb_header_t *); + +XDB_PUBLIC(int) xdb_verify_from_file(const char *); + // --- End xdb buffer @@ -221,9 +235,9 @@ XDB_PUBLIC(int) xdb_new_with_buffer(xdb_version_t *, xdb_searcher_t *, const xdb XDB_PUBLIC(void) xdb_close(void *); // xdb searcher search api define -XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *, const string_ip_t *, char *, size_t); +XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *, const string_ip_t *, char **, size_t); -XDB_PUBLIC(int) xdb_search(xdb_searcher_t *, const bytes_ip_t *, int, char *, size_t); +XDB_PUBLIC(int) xdb_search(xdb_searcher_t *, const bytes_ip_t *, int, char **, size_t); XDB_PUBLIC(xdb_version_t *) xdb_get_version(xdb_searcher_t *); diff --git a/binding/c/xdb_searcher.c b/binding/c/xdb_searcher.c index 0beeb5f..38a950e 100644 --- a/binding/c/xdb_searcher.c +++ b/binding/c/xdb_searcher.c @@ -59,7 +59,7 @@ XDB_PUBLIC(void) xdb_close(void *ptr) { // --- xdb searcher search api define -XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *xdb, const string_ip_t *ip_string, char *region_buffer, size_t length) { +XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *xdb, const string_ip_t *ip_string, char **region_buffer, size_t length) { bytes_ip_t ip_bytes[16] = {'\0'}; xdb_version_t *version = xdb_parse_ip(ip_string, ip_bytes, sizeof(ip_bytes)); if (version == NULL) { @@ -69,7 +69,7 @@ XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *xdb, const string_ip_t *ip_ } } -XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int ip_len, char *region_buffer, size_t length) { +XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int ip_len, char **region_buffer, size_t length) { int il0, il1, idx, err, bytes, d_bytes; register int seg_index_size, l, h, m, p; unsigned int s_ptr, e_ptr, data_ptr, data_len; @@ -147,12 +147,23 @@ XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, const bytes_ip_t *ip_bytes, int } // buffer length checking - if (data_len >= (int) length) { + if (length > 0 && data_len >= (int) length) { err = 1; goto done; } - err = read(xdb, data_ptr, region_buffer, data_len); + // @Note: since 2025/09/18 with IPv6 supporting. + // if the region_buffer is NULL or the length is 0 we will create a buffer + // to hold the region info and the caller should call xdb_free to free the region info after finished use it. + char *r_buffer = *region_buffer; + if (r_buffer == NULL || length == 0) { + r_buffer = (char *) xdb_malloc(data_len + 1); + *region_buffer = r_buffer; + } + + // auto append a NULL-end + r_buffer[data_len] = '\0'; + err = read(xdb, data_ptr, r_buffer, data_len); if (err != 0) { err += 30; goto done; @@ -165,8 +176,6 @@ done: segment_buffer = NULL; } - // auto append a NULL-end - region_buffer[data_len] = '\0'; return err; } diff --git a/binding/c/xdb_util.c b/binding/c/xdb_util.c index 29e40b9..0f04a4e 100644 --- a/binding/c/xdb_util.c +++ b/binding/c/xdb_util.c @@ -223,6 +223,61 @@ XDB_PUBLIC(void) xdb_free_content(void *ptr) { } } +XDB_PUBLIC(int) xdb_verify_from_header(FILE *handle, xdb_header_t *header) { + int runtime_ptr_bytes = 0; // runtime ptr bytes + if (header->version == xdb_structure_20) { + runtime_ptr_bytes = 4; + } else if (header->version == xdb_structure_30) { + runtime_ptr_bytes = header->runtime_ptr_bytes; + } else { + return 2; + } + + // 1, confirm the xdb file size. + // to ensure that the maximum file pointer does not overflow. + int err = fseek(handle, 0L, SEEK_END); + if (err != 0) { + return 3; + } + + long int fileBytes = ftell(handle); + long int maxFilePtr = (1L << (runtime_ptr_bytes * 8)) - 1; + // printf("fileBytes: %ld, maxFilePtr: %ld\n", fileBytes, maxFilePtr); + if (fileBytes > maxFilePtr) { + return 4; + } + + return 0; +} + +XDB_PUBLIC(int) xdb_verify(FILE *handle) { + xdb_header_t *header = xdb_load_header(handle); + if (header == NULL) { + return 1; + } + + int errcode = xdb_verify_from_header(handle, header); + if (errcode != 0) { + goto done; + } + + // what next ? +done: + xdb_free_header(header); + return errcode; +} + +XDB_PUBLIC(int) xdb_verify_from_file(const char *db_path) { + FILE *handle = fopen(db_path, "rb"); + if (handle == NULL) { + return -1; + } + + int r = xdb_verify(handle); + fclose(handle); + return r; +} + // --- End content buffer