diff --git a/lib/include/chiaki/takionsendbuffer.h b/lib/include/chiaki/takionsendbuffer.h index 35f6335..bdf6ffd 100644 --- a/lib/include/chiaki/takionsendbuffer.h +++ b/lib/include/chiaki/takionsendbuffer.h @@ -23,6 +23,8 @@ #include "thread.h" #include "seqnum.h" +#include + #ifdef __cplusplus extern "C" { #endif @@ -47,12 +49,18 @@ typedef struct chiaki_takion_send_buffer_t } ChiakiTakionSendBuffer; +/** + * Init a Send Buffer and start a thread that automatically re-sends packets on takion. + * + * @param takion if NULL, the Send Buffer thread will effectively do nothing (for unit testing) + * @param size number of packet slots + */ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_buffer_init(ChiakiTakionSendBuffer *send_buffer, ChiakiTakion *takion, size_t size); -CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_buffer_start(ChiakiTakionSendBuffer *send_buffer); CHIAKI_EXPORT void chiaki_takion_send_buffer_fini(ChiakiTakionSendBuffer *send_buffer); /** * @param buf ownership of this is taken by the ChiakiTakionSendBuffer, which will free it automatically later! + * On error, buf is freed immediately. */ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_buffer_push(ChiakiTakionSendBuffer *send_buffer, ChiakiSeqNum32 seq_num, uint8_t *buf, size_t buf_size); CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_buffer_ack(ChiakiTakionSendBuffer *send_buffer, ChiakiSeqNum32 seq_num); diff --git a/lib/src/takionsendbuffer.c b/lib/src/takionsendbuffer.c index 89e9888..4c5b4c1 100644 --- a/lib/src/takionsendbuffer.c +++ b/lib/src/takionsendbuffer.c @@ -15,6 +15,8 @@ * along with Chiaki. If not, see . */ +#ifndef CHIAKI_UNIT_TEST + #include #include #include @@ -22,11 +24,11 @@ #include #include - #define TAKION_DATA_RESEND_TIMEOUT_MS 200 #define TAKION_DATA_RESEND_WAKEUP_TIMEOUT_MS (TAKION_DATA_RESEND_TIMEOUT_MS/2) #define TAKION_DATA_RESEND_TRIES_MAX 10 +#endif struct chiaki_takion_send_buffer_packet_t { @@ -37,12 +39,14 @@ struct chiaki_takion_send_buffer_packet_t size_t buf_size; }; // ChiakiTakionSendBufferPacket +#ifndef CHIAKI_UNIT_TEST + static void *takion_send_buffer_thread_func(void *user); CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_buffer_init(ChiakiTakionSendBuffer *send_buffer, ChiakiTakion *takion, size_t size) { send_buffer->takion = takion; - send_buffer->log = takion->log; + send_buffer->log = takion ? takion->log : NULL; send_buffer->packets = calloc(size, sizeof(ChiakiTakionSendBufferPacket)); if(!send_buffer->packets) @@ -132,6 +136,8 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_takion_send_buffer_push(ChiakiTakionSendBuf } beach: + if(err != CHIAKI_ERR_SUCCESS) + free(buf); chiaki_mutex_unlock(&send_buffer->mutex); return err; } @@ -214,6 +220,9 @@ static void *takion_send_buffer_thread_func(void *user) static void takion_send_buffer_resend(ChiakiTakionSendBuffer *send_buffer) { + if(!send_buffer->takion) + return; + uint64_t now = chiaki_time_now_monotonic_ms(); for(size_t i=0; ipackets_count; i++) @@ -229,3 +238,5 @@ static void takion_send_buffer_resend(ChiakiTakionSendBuffer *send_buffer) } } } + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7794553..f6b8a45 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,7 +10,9 @@ add_executable(chiaki-unit takion.c seqnum.c reorderqueue.c - fec.c) + fec.c + test_log.c + test_log.h) target_link_libraries(chiaki-unit chiaki-lib munit) diff --git a/test/takion.c b/test/takion.c index c2cd332..da69d53 100644 --- a/test/takion.c +++ b/test/takion.c @@ -18,8 +18,14 @@ #include #include +#include #include +#define CHIAKI_UNIT_TEST +#include "../lib/src/takionsendbuffer.c" + +#include "test_log.h" + static MunitResult test_av_packet_parse(const MunitParameter params[], void *user) { @@ -67,6 +73,104 @@ static MunitResult test_av_packet_parse_real_video(const MunitParameter params[] return MUNIT_OK; } +static void random_seqnums(ChiakiSeqNum32 *nums, size_t count) +{ + for(size_t i=0; imutex) != CHIAKI_ERR_SUCCESS) + return false; + + if(send_buffer->packets_count != nums_expected_count) + goto fail; + + for(size_t i=0; ipackets_count; j++) + { + if(send_buffer->packets[j].seq_num == nums_expected[i]) + { + found = true; + break; + } + } + if(!found) + goto fail; + } + + chiaki_mutex_unlock(&send_buffer->mutex); + return true; +fail: + chiaki_mutex_unlock(&send_buffer->mutex); + return false; +} + +static void seqnums_ack(ChiakiSeqNum32 *nums, size_t *nums_count, ChiakiSeqNum32 ack_num) +{ + // simulate ack of ack_num + for(size_t i=0; i<*nums_count; i++) + { + if(nums[i] == ack_num || chiaki_seq_num_32_lt(nums[i], ack_num)) + { + for(size_t j=i+1; j<*nums_count; j++) + nums[j-1] = nums[j]; + (*nums_count)--; + i--; + } + } +} + +static MunitResult test_takion_send_buffer(const MunitParameter params[], void *user) +{ + static const size_t nums_count = 0x30; + ChiakiTakionSendBuffer send_buffer; + ChiakiErrorCode err = chiaki_takion_send_buffer_init(&send_buffer, NULL, nums_count); + munit_assert_int(err, ==, CHIAKI_ERR_SUCCESS); + send_buffer.log = get_test_log(); + + ChiakiSeqNum32 nums_expected[nums_count + 1]; + random_seqnums(nums_expected, nums_count + 1); + + for(size_t i=0; i 0) + { + ChiakiSeqNum32 ack_num = nums_expected[nums_count_cur - 1] + + munit_rand_int_range(-1, 1) * munit_rand_int_range(1, 32); + chiaki_takion_send_buffer_ack(&send_buffer, ack_num); + seqnums_ack(nums_expected, &nums_count_cur, ack_num); + bool correct = check_send_buffer_contents(&send_buffer, nums_expected, nums_count_cur); + munit_assert(correct); + } + + chiaki_takion_send_buffer_fini(&send_buffer); + return MUNIT_OK; +} + MunitTest tests_takion[] = { @@ -86,5 +190,13 @@ MunitTest tests_takion[] = { MUNIT_TEST_OPTION_NONE, NULL }, + { + "/send_buffer", + test_takion_send_buffer, + NULL, + NULL, + MUNIT_TEST_OPTION_NONE, + NULL + }, { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } }; \ No newline at end of file diff --git a/test/test_log.c b/test/test_log.c new file mode 100644 index 0000000..ce4a293 --- /dev/null +++ b/test/test_log.c @@ -0,0 +1,30 @@ +/* + * This file is part of Chiaki. + * + * Chiaki is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chiaki is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chiaki. If not, see . + */ + +#include "test_log.h" + +#include + +static bool initialized = false; +static ChiakiLog log_quiet; + +ChiakiLog *get_test_log() +{ + if(!initialized) + chiaki_log_init(&log_quiet, 0, NULL, NULL); + return &log_quiet; +} \ No newline at end of file diff --git a/test/test_log.h b/test/test_log.h new file mode 100644 index 0000000..074e97e --- /dev/null +++ b/test/test_log.h @@ -0,0 +1,25 @@ +/* + * This file is part of Chiaki. + * + * Chiaki is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chiaki is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chiaki. If not, see . + */ + +#ifndef CHIAKI_TEST_LOG_H +#define CHIAKI_TEST_LOG_H + +#include + +ChiakiLog *get_test_log(); + +#endif // CHIAKI_LOG_QUIET_H