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 91a4af0..3024380 100755 Binary files a/binding/c/test_util and b/binding/c/test_util differ 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