diff --git a/lib/node.c b/lib/node.c new file mode 100644 index 0000000..a3ffa3d --- /dev/null +++ b/lib/node.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +#include "node.h" + +//enum node_status { NODE_INITIALIAZED, NODE_PRESENT, NODE_GONE }; + +// Defines the node structure +struct node_t { + struct sockaddr_in addr; + uint64_t** events; + uint64_t appearance_duration; + uint8_t events_size; + node_status _node_status; +}; + +node_handle_t node_init(struct sockaddr_in addr) { + //assert(addr); + + node_handle_t node = malloc(sizeof(node_t)); + assert(node); + + node->addr = addr; + node->events_size = 0; + node->events = (uint64_t **) malloc(2 * sizeof(uint64_t)); + node->events[0] = (uint64_t *) malloc(sizeof(uint64_t)); + node->events[1] = (uint64_t *) malloc(sizeof(uint64_t)); + node->events[0][0] = 0; + node->events[1][0] = 0; + node->appearance_duration = 0; + node->_node_status = NODE_INITIALIAZED; + + return node; +} + +void node_free(node_handle_t node) { + assert(node); + + free(node->events[0]); + free(node->events[1]); + free(node->events); + free(node); +} + +void node_add_timestamp(node_handle_t node, time_t timestamp, bool visible) { + assert(node && timestamp); + + if ((visible && !node->events[1][node->events_size - 1]) || + (!visible && node->events[1][node->events_size - 1])) { + return; + } + + if (visible) { + int* realloc_r = realloc(node->events[0], node->events_size + 1); + if (!realloc_r) { + node_free(node); + perror("Error trying to reallocate memory for event timestamps!"); + exit(EXIT_FAILURE); + } + realloc_r = realloc(node->events[1], node->events_size + 1); + if (!realloc_r) { + node_free(node); + perror("Error trying to reallocate memory for event timestamps!"); + exit(EXIT_FAILURE); + } + + node->events[0][node->events_size] = timestamp; + node->events[1][node->events_size] = 0; + node->_node_status = NODE_PRESENT; + ++node->events_size; + } else { + node->events[1][node->events_size - 1] = timestamp; + node->_node_status = NODE_GONE; + node->appearance_duration += node->events[1][node->events_size - 1] - + node->events[0][node->events_size - 1]; + } +} + +struct sockaddr_in node_get_addr(node_handle_t node) { + assert(node); + + return node->addr; +} + +enum node_status node_get_status(node_handle_t node) { + assert(node); + + return node->_node_status; +} + +uint8_t node_get_latest_appearance_duration(node_handle_t node) { + assert(node); + + if (node->_node_status == NODE_INITIALIAZED) { + return 0; + } else if (node->events[1][node->events_size - 1] == 0) { + return (uint64_t)time(NULL) - node->events[0][node->events_size - 1]; + } else { + return node->events[1][node->events_size - 1] - node->events[0][node->events_size - 1]; + } +} + +uint8_t node_get_total_appearance_duration(node_handle_t node) { + assert(node); + + return node->appearance_duration; +} + +uint8_t node_get_event_table(node_handle_t node, time_t*** event_table) { + assert(node && event_table); + + if (node->events_size < 1) { + return 0; + } + + (*event_table) = (time_t **) malloc(2 * sizeof(time_t *)); + (*event_table)[0] = (time_t *) malloc(node->events_size * sizeof(time_t)); + (*event_table)[1] = (time_t *) malloc(node->events_size * sizeof(time_t)); + + memcpy((*event_table)[0], node->events[0], node->events_size * sizeof(time_t)); + memcpy((*event_table)[1], node->events[1], node->events_size * sizeof(time_t)); + + return node->events_size; +} \ No newline at end of file diff --git a/lib/node.h b/lib/node.h new file mode 100644 index 0000000..caacf2a --- /dev/null +++ b/lib/node.h @@ -0,0 +1,59 @@ +#ifndef NODE_H_ +#define NODE_H_ + +#include +#include +#include + +// Node structure +typedef struct node_t node_t; +// and handle type +typedef node_t* node_handle_t; + +typedef enum node_status { NODE_INITIALIAZED, NODE_PRESENT, NODE_GONE } node_status; + +#ifdef TEST //This is a test build +// Makes private functions reachable by the tester +#define unit_static +#else +#define unit_static static +#endif + +// Initializes a node structure and returns the node handle. +node_handle_t node_init(struct sockaddr_in addr); + +// Frees a node structure. +void node_free(node_handle_t node); + +// Adds an event timestamp to the node. Either the (re)appearance or the disappearance of the node. +void node_add_timestamp(node_handle_t node, time_t timestamp, bool visible); + +// Returns the address of the node +struct sockaddr_in node_get_addr(node_handle_t node); + +node_status node_get_status(node_handle_t node); + +//uint8_t node_get_appear_count(node_handle_t node); + +//uint8_t node_get_disappear_count(node_handle_t node); + +//void node_get_latest_appear(node_handle_t node, ); + +//void node_get_latest_disappear(node_handle_t node, ); + +// Returns the duration (in seconds) of the latest stretch of time that this node has been visible. +uint8_t node_get_latest_appearance_duration(node_handle_t node); + +// Returns the total duration (in seconds) of time that this node was visible. +uint8_t node_get_total_appearance_duration(node_handle_t node); + +// Returns the event timestamps table for this node. +uint8_t node_get_event_table(node_handle_t node, time_t*** event_table); + +// Serializes the whole node to a single string +//int circ_buf_serialize(node_handle_t node, char** serialized); + +// De-serializes a string to a node +//int circ_buf_deserialize(node_handle_t node, const char* serialized); + +#endif //NODE_H_ diff --git a/test/test_node.c b/test/test_node.c new file mode 100644 index 0000000..ec7e9e6 --- /dev/null +++ b/test/test_node.c @@ -0,0 +1,176 @@ +#include +#include "unity.h" + +#include "node.h" + +struct node_t { + struct sockaddr_in addr; + uint64_t** events; + uint64_t appearance_duration; + uint8_t events_size; + node_status _node_status; +}; + +void test_node_init(void) { + struct sockaddr_in myaddr; + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(2288); + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + node_handle_t node = node_init(myaddr); + TEST_ASSERT_NOT_NULL(node); + + node_free(node); +} + +void test_node_add_timestamp(void) { + struct sockaddr_in myaddr; + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(2288); + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + node_handle_t node = node_init(myaddr); + + time_t base_time = time(NULL); + + node_add_timestamp(node, base_time - 15, true); + TEST_ASSERT_EQUAL_MEMORY(base_time - 15, node->events[0][0], sizeof(time_t)); + TEST_ASSERT_EQUAL_MEMORY(0, node->events[1][0], sizeof(time_t)); + + node_add_timestamp(node, base_time - 10, false); + TEST_ASSERT_EQUAL_MEMORY(base_time - 10, node->events[1][0], sizeof(time_t)); + + node_add_timestamp(node, base_time - 5, true); + TEST_ASSERT_EQUAL_MEMORY(base_time - 5, node->events[0][1], sizeof(time_t)); + TEST_ASSERT_EQUAL_MEMORY(0, node->events[1][1], sizeof(time_t)); + + node_add_timestamp(node, base_time, false); + TEST_ASSERT_EQUAL_MEMORY(base_time, node->events[1][1], sizeof(time_t)); + + node_add_timestamp(node, base_time + 5, false); + TEST_ASSERT_EQUAL_MEMORY(base_time, node->events[1][1], sizeof(time_t)); + + node_add_timestamp(node, base_time + 10, true); + TEST_ASSERT_EQUAL_MEMORY(base_time + 10, node->events[0][2], sizeof(time_t)); + TEST_ASSERT_EQUAL_MEMORY(0, node->events[1][2], sizeof(time_t)); + + node_free(node); +} + +void test_node_get_addr(void){ + struct sockaddr_in myaddr; + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(2288); + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + node_handle_t node = node_init(myaddr); + + struct sockaddr_in actual = node_get_addr(node); + TEST_ASSERT_EQUAL_MEMORY(&myaddr, &actual, sizeof(myaddr)); + + node_free(node); +} + +void test_node_get_status(void){ + struct sockaddr_in myaddr; + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(2288); + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + node_handle_t node = node_init(myaddr); + + TEST_ASSERT_EQUAL_INT(NODE_INITIALIAZED, node_get_status(node)); + + node_add_timestamp(node, time(NULL), true); + TEST_ASSERT_EQUAL_INT(NODE_PRESENT, node_get_status(node)); + + node_add_timestamp(node, time(NULL), false); + TEST_ASSERT_EQUAL_INT(NODE_GONE, node_get_status(node)); + + node_free(node); +} + +void test_node_get_latest_appearance_duration(void){ + struct sockaddr_in myaddr; + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(2288); + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + node_handle_t node = node_init(myaddr); + + time_t base_time = time(NULL); + node_add_timestamp(node, base_time - 10, true); + TEST_ASSERT_UINT8_WITHIN(1, 10, node_get_latest_appearance_duration(node)); + + node_add_timestamp(node, base_time + 10, false); + TEST_ASSERT_EQUAL_UINT8(20, node_get_latest_appearance_duration(node)); + + node_free(node); +} + +void test_node_get_total_appearance_duration(void){ + struct sockaddr_in myaddr; + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(2288); + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + node_handle_t node = node_init(myaddr); + + time_t base_time = time(NULL); + + node_add_timestamp(node, base_time - 30, true); + node_add_timestamp(node, base_time - 25, false); + TEST_ASSERT_EQUAL_UINT8(5, node_get_total_appearance_duration(node)); + + node_add_timestamp(node, base_time - 12, true); + node_add_timestamp(node, base_time - 5, false); + TEST_ASSERT_EQUAL_UINT8(12, node_get_total_appearance_duration(node)); + + node_free(node); +} + +void test_node_get_event_table(void){ + struct sockaddr_in myaddr; + + myaddr.sin_family = AF_INET; + myaddr.sin_port = htons(2288); + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + + node_handle_t node = node_init(myaddr); + + time_t base_time = time(NULL); + + node_add_timestamp(node, base_time - 15, true); + node_add_timestamp(node, base_time - 10, false); + node_add_timestamp(node, base_time - 5, true); + node_add_timestamp(node, base_time, false); + node_add_timestamp(node, base_time + 5, false); + node_add_timestamp(node, base_time + 10, true); + + time_t** event_table; + uint8_t num_entries = node_get_event_table(node, &event_table); + TEST_ASSERT_EQUAL_UINT8(3, num_entries); + TEST_ASSERT_NOT_NULL(event_table); + + time_t** expected_table = (time_t**) malloc(2 * sizeof(time_t *)); + expected_table[0] = (time_t*) malloc(3 * sizeof(time_t)); + expected_table[1] = (time_t*) malloc(3 * sizeof(time_t)); + + expected_table[0][0] = base_time - 15; + expected_table[1][0] = base_time - 10; + expected_table[0][1] = base_time - 5; + expected_table[1][1] = base_time; + expected_table[0][2] = base_time + 10; + expected_table[1][2] = 0; + + TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected_table[0], event_table[0], sizeof(time_t), 3); + TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected_table[1], event_table[1], sizeof(time_t), 3); + + node_free(node); +}