#include #include #include #include #include "utable/utable.h" #include "cjson/cJSON.h" #include "uthash/utarray.h" #pragma GCC diagnostic ignored "-Wunused-parameter" #define IPFIX_DEFUALT_VERSION 10 #define GEEDGE_NETWORKS_PEN_NUMBER 54450 #define IPFIX_DEFUALT_PEN_NUMBER GEEDGE_NETWORKS_PEN_NUMBER #define IPFIX_NONE_PEN_NUMBER -1 #define IPFIX_TEMPLATE_SET_ID 2 #define IPFIX_BUFF_MAX_SIZE 2048 #define IPFIX_ELEMENT_MAX_LEN 32 #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif enum ipfix_type { IPFIX_UNSIGNED8 = 0, IPFIX_UNSIGNED16, IPFIX_UNSIGNED32, IPFIX_UNSIGNED64, IPFIX_VARIABLE_STRING, IPFIX_UNKNOWN }; struct ipfix_element { enum ipfix_type type; uint16_t element_id; uint16_t value_length; // if type is variable_string, value_length is 0 int PEN_number; char name[IPFIX_ELEMENT_MAX_LEN]; }; struct ipfix_template { uint16_t template_id; char *name; UT_array *elements_array; // utarray for current template elements }; struct ipfix_worker_context { int source_id; int sequence; size_t template_blob_length; char *template_blob; }; struct ipfix_exporter_schema { uint16_t n_worker; uint16_t version; int domain_id; int PEN_number; UT_array *templates_array; // utarray for templates struct ipfix_worker_context *worker_context_array; // utarray for worker_context }; struct ipfix_message_head { uint16_t version; uint16_t length; int exporttime; int ipfix_message_sequence; int domain_id; }; #define IPFIX_MESSAGE_HEAD_LEN sizeof(struct ipfix_message_head) #define THREAD_MAX 4 #define TEMPLATE_MAX 13 struct gtest_ipfix_template_info { const char *template_name; int template_id; int n_elements; }; struct gtest_ipfix_template_info gtest_ipfix_template_info[TEMPLATE_MAX] = { {"BASE", 257, 87}, {"SSL", 258, 98}, {"HTTP", 259, 108}, {"MAIL", 260, 100}, {"DNS", 261, 106}, {"DTLS", 262, 97}, {"QUIC", 263, 90}, {"FTP", 264, 91}, {"SIP", 265, 102}, {"RTP", 266, 91}, {"SSH", 267, 98}, {"RDP", 268, 102}, {"Stratum", 269, 91}}; #define IPFIX_ELEMENT_HEAD_LEN sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) // element_id + element_length + PEN_number const char *ipfix_schema_json_path = "./conf/ipfix_schema.json"; int g_domain_id = 1; TEST(utable_ipfix_exporter_test, ipfix_schema_new_error_path) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new((const char *)"", g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema == NULL); } int test_template_blob_len_calculate(struct ipfix_exporter_schema *ipfix_schema) { int template_blob_length = 0; template_blob_length += IPFIX_MESSAGE_HEAD_LEN; // message head template_blob_length += sizeof(uint16_t) + sizeof(uint16_t); // flow set id + flow set length for (unsigned int i = 0; i < TEMPLATE_MAX; i++) { struct ipfix_template *template_item = (struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, i); template_blob_length += sizeof(uint16_t) + sizeof(uint16_t) + utarray_len(template_item->elements_array) * (IPFIX_ELEMENT_HEAD_LEN); // sizeof(template_id) + sizeof(field_count) + n_elements * sizeof(element_id + element_length + PEN_number) } return template_blob_length; } TEST(utable_ipfix_exporter_test, ipfix_schema_new_check_schema) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); EXPECT_EQ(ipfix_schema->domain_id, 1); EXPECT_EQ(ipfix_schema->n_worker, THREAD_MAX); EXPECT_EQ(utarray_len(ipfix_schema->templates_array), TEMPLATE_MAX); EXPECT_EQ(ipfix_schema->PEN_number, GEEDGE_NETWORKS_PEN_NUMBER); EXPECT_EQ(ipfix_schema->version, IPFIX_DEFUALT_VERSION); for (unsigned int i = 0; i < TEMPLATE_MAX; i++) { struct ipfix_template *template_item = (struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, i); ASSERT_TRUE(template_item != NULL); EXPECT_EQ(template_item->template_id, gtest_ipfix_template_info[i].template_id); EXPECT_EQ(gtest_ipfix_template_info[i].n_elements, utarray_len(template_item->elements_array)); EXPECT_STREQ(template_item->name, gtest_ipfix_template_info[i].template_name); } ASSERT_TRUE(ipfix_schema->worker_context_array != NULL); for (int i = 0; i < THREAD_MAX; i++) { EXPECT_EQ(ipfix_schema->worker_context_array[i].source_id, (g_domain_id << 16) + i); EXPECT_EQ(ipfix_schema->worker_context_array[i].sequence, 0); ASSERT_TRUE(ipfix_schema->worker_context_array[i].template_blob != NULL); EXPECT_EQ(ipfix_schema->worker_context_array[i].template_blob_length, test_template_blob_len_calculate(ipfix_schema)); } utable_ipfix_exporter_schema_free(ipfix_schema); } TEST(utable_ipfix_exporter_test, ipfix_template_flow_get0_all_elements_check_blob) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); for (int i = 0; i < THREAD_MAX; i++) { size_t blob_len = 0; const char *blob = utable_ipfix_template_flow_get0(ipfix_schema, i, &blob_len); ASSERT_TRUE(blob != NULL); EXPECT_EQ(blob_len, test_template_blob_len_calculate(ipfix_schema)); // check header struct ipfix_message_head *header = (struct ipfix_message_head *)blob; struct ipfix_message_head header_value = {}; header_value.version = htons(header->version); header_value.length = htons(header->length); header_value.domain_id = htonl(header->domain_id); header_value.ipfix_message_sequence = htonl(header->ipfix_message_sequence); EXPECT_EQ(header_value.version, IPFIX_DEFUALT_VERSION); EXPECT_EQ(header_value.length, test_template_blob_len_calculate(ipfix_schema)); EXPECT_EQ(header_value.domain_id, (g_domain_id << 16) + i); EXPECT_EQ(header_value.ipfix_message_sequence, 0); size_t offset = 0; offset += IPFIX_MESSAGE_HEAD_LEN; uint16_t flow_set_id = ntohs(*(uint16_t *)(blob + offset)); EXPECT_EQ(flow_set_id, IPFIX_TEMPLATE_SET_ID); // template set id offset += 2; uint16_t flow_set_length = ntohs(*(uint16_t *)(blob + offset)); EXPECT_EQ(flow_set_length, blob_len - IPFIX_MESSAGE_HEAD_LEN); // template set length offset += 2; for (unsigned int j = 0; j < TEMPLATE_MAX; j++) { uint16_t cur_template_blob_len = sizeof(uint16_t) + sizeof(uint16_t) + gtest_ipfix_template_info[j].n_elements * IPFIX_ELEMENT_HEAD_LEN; ASSERT_LE(offset + cur_template_blob_len, blob_len); uint16_t template_id = ntohs(*(uint16_t *)(blob + offset)); EXPECT_EQ(template_id, gtest_ipfix_template_info[j].template_id); // template id offset += 2; uint16_t field_count = ntohs(*(uint16_t *)(blob + offset)); EXPECT_EQ(field_count, gtest_ipfix_template_info[j].n_elements); // field count offset += 2; struct ipfix_template *template_item = (struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, j); for (unsigned int p = 0; p < (unsigned int)gtest_ipfix_template_info[j].n_elements; p++) { struct ipfix_element *element = (struct ipfix_element *)utarray_eltptr(template_item->elements_array, p); uint16_t PEN_number_flag = ntohs(*(uint16_t *)(blob + offset)) & 0x8000; EXPECT_EQ(PEN_number_flag, 0x8000); // PEN number flag uint16_t element_id = ntohs(*(uint16_t *)(blob + offset)) & 0x7fff; EXPECT_EQ(element_id, element->element_id); // element id offset += 2; if (element->type == IPFIX_VARIABLE_STRING) { uint16_t element_length = ntohs(*(uint16_t *)(blob + offset)); EXPECT_EQ(element_length, 65535); // element length } else { uint16_t element_length = ntohs(*(uint16_t *)(blob + offset)); EXPECT_EQ(element_length, element->value_length); // element length } offset += 2; uint32_t PEN_number = ntohl(*(uint32_t *)(blob + offset)); EXPECT_EQ(PEN_number, element->PEN_number); // PEN number offset += 4; } } } utable_ipfix_exporter_schema_free(ipfix_schema); } TEST(utable_ipfix_exporter_test, ipfix_template_flow_get0_all_elements_check_sequence) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); for (int i = 0; i < THREAD_MAX; i++) { size_t blob_len = 0; const char *blob = utable_ipfix_template_flow_get0(ipfix_schema, i, &blob_len); ASSERT_TRUE(blob != NULL); // check header struct ipfix_message_head *header = (struct ipfix_message_head *)blob; struct ipfix_message_head header_value = {}; header_value.version = htons(header->version); header_value.length = htons(header->length); header_value.domain_id = htonl(header->domain_id); header_value.ipfix_message_sequence = htonl(header->ipfix_message_sequence); EXPECT_EQ(header_value.version, IPFIX_DEFUALT_VERSION); EXPECT_EQ(header_value.length, test_template_blob_len_calculate(ipfix_schema)); EXPECT_EQ(header_value.domain_id, (g_domain_id << 16) + i); EXPECT_EQ(header_value.ipfix_message_sequence, 0); memset(&header_value, 0, sizeof(struct ipfix_message_head)); header = NULL; blob = NULL; // check sequence, utable_ipfix_template_flow_get0 will not increase sequence blob = utable_ipfix_template_flow_get0(ipfix_schema, i, &blob_len); ASSERT_TRUE(blob != NULL); // check header header = (struct ipfix_message_head *)blob; header_value.ipfix_message_sequence = htonl(header->ipfix_message_sequence); EXPECT_EQ(header_value.ipfix_message_sequence, 0); } utable_ipfix_exporter_schema_free(ipfix_schema); } TEST(utable_ipfix_exporter_test, ipfix_template_get_not_found) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); int template_id = utable_ipfix_template_get(ipfix_schema, "test"); EXPECT_EQ(template_id, -1); utable_ipfix_exporter_schema_free(ipfix_schema); } TEST(utable_ipfix_exporter_test, ipfix_template_get_check_template_id) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); int template_id = 0; for (unsigned int i = 0; i < TEMPLATE_MAX; i++) { template_id = utable_ipfix_template_get(ipfix_schema, gtest_ipfix_template_info[i].template_name); EXPECT_EQ(template_id, i); struct ipfix_template *template_item = (struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, i); ASSERT_TRUE(template_item != NULL); } utable_ipfix_exporter_schema_free(ipfix_schema); } cJSON *test_ipifx_data_blob_to_cjson(struct ipfix_template *template_item, char *blob, size_t sz_blob) { cJSON *root = cJSON_CreateObject(); size_t offset = IPFIX_MESSAGE_HEAD_LEN + sizeof(uint16_t) + sizeof(uint16_t); // skip message head and flow set id and flow set length size_t n_elements = utarray_len(template_item->elements_array); for (size_t i = 0; i < n_elements; i++) { struct ipfix_element *p_element = (struct ipfix_element *)utarray_eltptr(template_item->elements_array, i); switch (p_element->type) { case IPFIX_UNSIGNED8: { cJSON_AddNumberToObject(root, p_element->name, *(uint8_t *)(blob + offset)); offset += sizeof(uint8_t); break; } case IPFIX_UNSIGNED16: { cJSON_AddNumberToObject(root, p_element->name, ntohs(*(uint16_t *)(blob + offset))); offset += sizeof(uint16_t); break; } case IPFIX_UNSIGNED32: { cJSON_AddNumberToObject(root, p_element->name, ntohl(*(uint32_t *)(blob + offset))); offset += sizeof(uint32_t); break; } case IPFIX_UNSIGNED64: { cJSON_AddNumberToObject(root, p_element->name, be64toh(*(uint64_t *)(blob + offset))); offset += sizeof(uint64_t); break; } case IPFIX_VARIABLE_STRING: { uint8_t sz_value = *(uint8_t *)(blob + offset); offset += sizeof(uint8_t); char *string_value = NULL; if (sz_value == 0) { break; } else if (sz_value < 255) { string_value = (char *)malloc(sizeof(char) * (sz_value + 1)); memcpy(string_value, blob + offset, sz_value); string_value[sz_value] = '\0'; offset += sz_value; } else // >= 255 { uint16_t sz_long_string_value = ntohs(*(uint16_t *)(blob + offset)); offset += sizeof(uint16_t); string_value = (char *)malloc(sizeof(char) * (sz_long_string_value + 1)); memcpy(string_value, blob + offset, sz_long_string_value); string_value[sz_long_string_value] = '\0'; offset += sz_long_string_value; } cJSON_AddStringToObject(root, p_element->name, string_value); free(string_value); break; } default: break; } } return root; } // after include before, and the extra part is cJSON_Number, but valueint = 0; void test_ipfix_compare_cjson(cJSON *before, cJSON *after) { // find before's element in after cJSON *item = before->child; while (item != NULL) { if (item->type == cJSON_Number) { cJSON *item_after = cJSON_GetObjectItem(after, item->string); ASSERT_TRUE(item_after != NULL); EXPECT_EQ(item->valueint, item_after->valueint); } if (item->type == cJSON_String) { cJSON *item_after = cJSON_GetObjectItem(after, item->string); ASSERT_TRUE(item_after != NULL); EXPECT_STREQ(item->valuestring, item_after->valuestring); } item = item->next; } // find after's element in before item = after->child; while (item != NULL) { if (item->type == cJSON_Number) // if after's element is cJSON_Number, before's element may be empty or cJSON_Number { cJSON *item_before = cJSON_GetObjectItem(before, item->string); if (item_before == NULL) // if before's element is empty, after's element valueint must be 0 { EXPECT_EQ(item->valueint, 0); } else { EXPECT_EQ(item->valueint, item_before->valueint); // if before's element is cJSON_Number, after's element valueint must be equal to before's element valueint } } if (item->type == cJSON_String) { cJSON *item_before = cJSON_GetObjectItem(before, item->string); ASSERT_TRUE(item_before != NULL); EXPECT_STREQ(item->valuestring, item_before->valuestring); } item = item->next; } } int test_empty_data_blob_len_calculate(struct ipfix_exporter_schema *ipfix_schema, int template_id) { struct ipfix_template *template_item = (struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, (unsigned int)template_id); int data_blob_length = 0; data_blob_length += IPFIX_MESSAGE_HEAD_LEN; // message head data_blob_length += sizeof(uint16_t) + sizeof(uint16_t); // flow set id + flow set length for (unsigned int i = 0; i < utarray_len(template_item->elements_array); i++) { struct ipfix_element *element = (struct ipfix_element *)utarray_eltptr(template_item->elements_array, i); if (element->type == IPFIX_VARIABLE_STRING) { data_blob_length += 1; } else { data_blob_length += element->value_length; // element length } } return data_blob_length; } TEST(utable_ipfix_exporter_test, ipfix_data_flow_empty_utable_check_blob) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); for (unsigned int i = 0; i < TEMPLATE_MAX; i++) { cJSON *before = cJSON_CreateObject(); struct utable *table = utable_new(); int template_id = utable_ipfix_template_get(ipfix_schema, gtest_ipfix_template_info[i].template_name); ASSERT_EQ(template_id, i); for (unsigned int j = 0; j < THREAD_MAX; j++) { size_t blob_len = 0; char *blob = NULL; utable_ipfix_data_flow_exporter(table, ipfix_schema, template_id, j, &blob, &blob_len); ASSERT_TRUE(blob != NULL); struct ipfix_message_head *header = (struct ipfix_message_head *)blob; struct ipfix_message_head header_value = {}; header_value.version = htons(header->version); header_value.length = htons(header->length); header_value.domain_id = htonl(header->domain_id); header_value.ipfix_message_sequence = htonl(header->ipfix_message_sequence); ASSERT_EQ(header_value.version, IPFIX_DEFUALT_VERSION); ASSERT_EQ(header_value.length, blob_len); ASSERT_EQ(header_value.length, test_empty_data_blob_len_calculate(ipfix_schema, i)); ASSERT_EQ(header_value.domain_id, (g_domain_id << 16) + j); ASSERT_EQ(header_value.ipfix_message_sequence, i); cJSON *after = test_ipifx_data_blob_to_cjson((struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, i), blob, blob_len); test_ipfix_compare_cjson(before, after); cJSON_Delete(after); free(blob); blob = NULL; } cJSON_Delete(before); utable_free(table); } utable_ipfix_exporter_schema_free(ipfix_schema); } TEST(utable_ipfix_exporter_test, ipfix_data_flow_utable_value_type_integer) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); cJSON *before = cJSON_CreateObject(); struct utable *table = utable_new(); utable_add_integer(table, "session_id", 123456789); cJSON_AddNumberToObject(before, "session_id", 123456789); unsigned int template_id = utable_ipfix_template_get(ipfix_schema, "HTTP"); char *blob = NULL; size_t sz_blob = 0; utable_ipfix_data_flow_exporter(table, ipfix_schema, template_id, 0, &blob, &sz_blob); ASSERT_EQ(sz_blob, test_empty_data_blob_len_calculate(ipfix_schema, template_id)); // integer value length has been calculated in test_empty_data_blob_len_calculate cJSON *after = test_ipifx_data_blob_to_cjson((struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, template_id), blob, sz_blob); test_ipfix_compare_cjson(before, after); cJSON_Delete(before); cJSON_Delete(after); utable_free(table); free(blob); utable_ipfix_exporter_schema_free(ipfix_schema); } TEST(utable_ipfix_exporter_test, ipfix_data_flow_utable_value_type_cstring) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); cJSON *before = cJSON_CreateObject(); struct utable *table = utable_new(); utable_add_integer(table, "session_id", 123456789); cJSON_AddNumberToObject(before, "session_id", 123456789); utable_add_cstring(table, "http_url", "http://www.baidu.com", strlen("http://www.baidu.com")); cJSON_AddStringToObject(before, "http_url", "http://www.baidu.com"); unsigned int template_id = utable_ipfix_template_get(ipfix_schema, "HTTP"); char *blob = NULL; size_t sz_blob = 0; utable_ipfix_data_flow_exporter(table, ipfix_schema, template_id, 0, &blob, &sz_blob); ASSERT_EQ(sz_blob, test_empty_data_blob_len_calculate(ipfix_schema, template_id) + strlen("http://www.baidu.com")); // variable_string length need to be calculated cJSON *after = test_ipifx_data_blob_to_cjson((struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, template_id), blob, sz_blob); test_ipfix_compare_cjson(before, after); cJSON_Delete(before); cJSON_Delete(after); utable_free(table); free(blob); utable_ipfix_exporter_schema_free(ipfix_schema); } char http_url_test[] = "storeapi.app-vtion.com/storeApi/systemApp/checkAppStatus.json?store=com.tcl.appmarket2&mac=3C:59:1E:DC:F8:F4&accessKeyId=1472540256617"; TEST(utable_ipfix_exporter_test, ipfix_data_flow_variable_string_6000) // 6000 bytes > 2 * IPFIX_BUFF_MAX_SIZE, test variable_string length > 255 and realloc { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); char *http_url = NULL; struct utable *table = utable_new(); cJSON *before = cJSON_CreateObject(); utable_add_cstring(table, "decoded_as", "HTTP", strlen("HTTP")); cJSON_AddStringToObject(before, "decoded_as", "HTTP"); http_url = (char *)malloc(sizeof(char) * 7000); int offset = 0; while (offset < 6000) { memcpy(http_url + offset, http_url_test, sizeof(http_url_test)); offset += sizeof(http_url_test); } utable_add_cstring(table, "http_url", http_url, offset); cJSON_AddStringToObject(before, "http_url", http_url); unsigned int template_id = utable_ipfix_template_get(ipfix_schema, "HTTP"); char *blob = NULL; size_t sz_blob = 0; utable_ipfix_data_flow_exporter(table, ipfix_schema, template_id, 0, &blob, &sz_blob); ASSERT_EQ(sz_blob, test_empty_data_blob_len_calculate(ipfix_schema, template_id) + offset + strlen("HTTP") + 2); // variable_string length need to be calculated, if length > 255, length + 2 cJSON *after = test_ipifx_data_blob_to_cjson((struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, template_id), blob, sz_blob); test_ipfix_compare_cjson(before, after); cJSON_Delete(before); cJSON_Delete(after); utable_free(table); free(blob); free(http_url); utable_ipfix_exporter_schema_free(ipfix_schema); } TEST(utable_ipfix_exporter_test, ipfix_data_flow_utable_value_type_integer_array) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); cJSON *before = cJSON_CreateObject(); struct utable *table = utable_new(); utable_add_integer(table, "session_id", 123456789); cJSON_AddNumberToObject(before, "session_id", 123456789); int64_t monitor_rule_list[8] = {1, 2, 3, 4, 5, 6, 7, 8}; utable_add_integer_array(table, "monitor_rule_list", monitor_rule_list, 8); cJSON_AddStringToObject(before, "monitor_rule_list", "[1,2,3,4,5,6,7,8]"); unsigned int template_id = utable_ipfix_template_get(ipfix_schema, "HTTP"); char *blob = NULL; size_t sz_blob = 0; utable_ipfix_data_flow_exporter(table, ipfix_schema, template_id, 0, &blob, &sz_blob); ASSERT_EQ(sz_blob, test_empty_data_blob_len_calculate(ipfix_schema, template_id) + strlen("[1,2,3,4,5,6,7,8]")); // variable_string length need to be calculated cJSON *after = test_ipifx_data_blob_to_cjson((struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, template_id), blob, sz_blob); test_ipfix_compare_cjson(before, after); cJSON_Delete(before); cJSON_Delete(after); utable_free(table); free(blob); utable_ipfix_exporter_schema_free(ipfix_schema); } extern "C" int load_file_to_memory(const char *file_name, unsigned char **pp_out, size_t *out_sz); cJSON *ipfix_init_utable_from_log_json(struct utable *table, const char *test_json_path, size_t *sz_blob) { size_t json_size = 0; unsigned char *json_str = NULL; load_file_to_memory(test_json_path, &json_str, &json_size); if (json_str == NULL || json_size == 0) { return NULL; } cJSON *root = NULL; root = cJSON_Parse((const char *)json_str); cJSON *item = root->child; while (item != NULL) { switch (item->type) { case cJSON_Number: { utable_add_integer(table, item->string, item->valueint); break; } case cJSON_String: { int sz_value = strlen(item->valuestring); utable_add_cstring(table, item->string, item->valuestring, sz_value); if (sz_value < 255) { *sz_blob += strlen(item->valuestring); } else { *sz_blob += (strlen(item->valuestring) + 2); } break; } case cJSON_Array: { cJSON *array_item = cJSON_GetArrayItem(item, 0); size_t array_sz = cJSON_GetArraySize(item); if (array_sz > 0) { if (array_item->type == cJSON_Number) { int *array = (int *)malloc(sizeof(int) * array_sz); int64_t *long_array = (int64_t *)malloc(sizeof(int64_t) * array_sz); for (size_t i = 0; i < array_sz; i++) { array_item = cJSON_GetArrayItem(item, i); if (array_item->type == cJSON_Number) { array[i] = array_item->valueint; long_array[i] = array_item->valueint; } } utable_add_integer_array(table, item->string, long_array, array_sz); cJSON *json_array = cJSON_CreateIntArray((const int *)array, array_sz); cJSON_Delete(item->child); item->child = NULL; item->type = cJSON_String; item->valuestring = cJSON_PrintUnformatted(json_array); cJSON_Delete(json_array); free(array); free(long_array); } else if (array_item->type == cJSON_String) { char **array = (char **)malloc(sizeof(char *) * array_sz); size_t *sz_value = (size_t *)malloc(sizeof(size_t) * array_sz); for (size_t i = 0; i < array_sz; i++) { array_item = cJSON_GetArrayItem(item, i); if (array_item->type == cJSON_String) { sz_value[i] = strlen(array_item->valuestring); array[i] = strdup(array_item->valuestring); } } utable_add_cstring_array(table, item->string, (const char **)array, sz_value, array_sz); free(sz_value); cJSON *json_array = cJSON_CreateStringArray((const char **)array, array_sz); item->valuestring = cJSON_PrintUnformatted(json_array); item->type = cJSON_String; cJSON_Delete(item->child); item->child = NULL; cJSON_Delete(json_array); for (size_t i = 0; i < array_sz; i++) { free(array[i]); } free(array); } int sz_value = strlen(item->valuestring); if (sz_value < 255) { *sz_blob += sz_value; } else { *sz_blob += (sz_value + 2); } } break; } default: break; } item = item->next; } free(json_str); return root; } const char *ssl_test_json_path = "./conf/ipfix_ssl_test.json"; TEST(utable_ipfix_exporter_test, ipfix_data_flow_ssl_log_test) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); struct utable *table = utable_new(); unsigned int template_id = utable_ipfix_template_get(ipfix_schema, "SSL"); size_t predict_sz_blob = test_empty_data_blob_len_calculate(ipfix_schema, template_id); cJSON *before_json_root = ipfix_init_utable_from_log_json(table, ssl_test_json_path, &predict_sz_blob); char *blob = NULL; size_t sz_blob = 0; utable_ipfix_data_flow_exporter(table, ipfix_schema, template_id, 0, &blob, &sz_blob); ASSERT_EQ(sz_blob, predict_sz_blob); cJSON *after_json_root = test_ipifx_data_blob_to_cjson((struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, template_id), blob, sz_blob); char *before_json_str = cJSON_Print(before_json_root); char *after_json_str = cJSON_Print(after_json_root); printf("before_json: %s\n", before_json_str); printf("after_json: %s\n", after_json_str); free(before_json_str); free(after_json_str); test_ipfix_compare_cjson(before_json_root, after_json_root); cJSON_Delete(before_json_root); cJSON_Delete(after_json_root); free(blob); utable_free(table); utable_ipfix_exporter_schema_free(ipfix_schema); } const char *http_test_json_path = "./conf/ipfix_http_test.json"; TEST(utable_ipfix_exporter_test, ipfix_data_flow_http_log_test) { struct ipfix_exporter_schema *ipfix_schema = utable_ipfix_exporter_schema_new(ipfix_schema_json_path, g_domain_id, THREAD_MAX); ASSERT_TRUE(ipfix_schema != NULL); struct utable *table = utable_new(); unsigned int template_id = utable_ipfix_template_get(ipfix_schema, "HTTP"); size_t predict_sz_blob = test_empty_data_blob_len_calculate(ipfix_schema, template_id); cJSON *before_json_root = ipfix_init_utable_from_log_json(table, http_test_json_path, &predict_sz_blob); char *blob = NULL; size_t sz_blob = 0; utable_ipfix_data_flow_exporter(table, ipfix_schema, template_id, 0, &blob, &sz_blob); ASSERT_EQ(sz_blob, predict_sz_blob); cJSON *after_json_root = test_ipifx_data_blob_to_cjson((struct ipfix_template *)utarray_eltptr(ipfix_schema->templates_array, template_id), blob, sz_blob); test_ipfix_compare_cjson(before_json_root, after_json_root); cJSON_Delete(before_json_root); cJSON_Delete(after_json_root); free(blob); utable_free(table); utable_ipfix_exporter_schema_free(ipfix_schema); } int main(int argc, char *argv[]) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }