Porting PicoTCP WIP

This commit is contained in:
2025-10-29 14:29:06 +01:00
parent 6722f42e68
commit 815c2239fe
464 changed files with 235009 additions and 24 deletions

View File

@ -0,0 +1,375 @@
#include <pico_defines.h>
#include <pico_stack.h>
#include <pico_socket.h>
#include <pico_tftp.h>
#include "modules/pico_tftp.c"
#include "check.h"
Suite *pico_suite(void);
int tftp_user_cb(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg);
/* MOCKS */
static int called_pico_socket_close = 0;
static uint16_t expected_opcode = 0;
static int called_user_cb = 0;
static int called_sendto = 0;
static uint32_t called_pico_timer_add = 0;
static int called_pico_timer_cancel = 0;
static struct pico_socket example_socket;
static struct pico_tftp_session example_session;
int pico_socket_close(struct pico_socket *s)
{
fail_if(s != example_session.socket);
called_pico_socket_close++;
return 0;
}
int pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port)
{
const struct pico_tftp_hdr *h = (const struct pico_tftp_hdr *)buf;
fail_if(s != &example_socket);
fail_if(short_be(h->opcode) != expected_opcode);
fail_if(len <= 0);
(void)dst;
(void)remote_port;
called_sendto++;
return 0;
}
int tftp_user_cb(struct pico_tftp_session *session, uint16_t err, uint8_t *block, int32_t len, void *arg)
{
(void)session;
(void)err;
(void)block;
(void)len;
(void)arg;
called_user_cb++;
return 0;
}
uint32_t pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg)
{
(void)expire;
(void)timer;
(void)arg;
return ++called_pico_timer_add;
}
void pico_timer_cancel(uint32_t t)
{
(void)t;
called_pico_timer_cancel++;
}
/* TESTS */
/* START_TEST(tc_check_opcode) */
/* { */
/* / * TODO: test this: static int check_opcode(struct pico_tftp_hdr *th) * / */
/* struct pico_tftp_hdr th; */
/* th.opcode = 0; */
/* fail_unless(check_opcode(&th) == -1); */
/* th.opcode = short_be(PICO_TFTP_RRQ); */
/* fail_unless(check_opcode(&th) == 0); */
/* th.opcode = short_be(0xFF); */
/* fail_unless(check_opcode(&th) == -1); */
/* } */
/* END_TEST */
START_TEST(tc_find_session_by_socket)
{
tftp_sessions = (struct pico_tftp_session *)PICO_ZALLOC(sizeof(struct pico_tftp_session));
tftp_sessions->socket = &example_socket;
tftp_sessions->next = (struct pico_tftp_session *)PICO_ZALLOC(sizeof(struct pico_tftp_session));
tftp_sessions->socket = NULL;
tftp_sessions->next = NULL;
fail_if(find_session_by_socket(&example_socket) != tftp_sessions->next);
}
END_TEST
START_TEST(tc_tftp_finish)
{
tftp_sessions = 0;
/* Test case: client */
example_session.socket = &example_socket;
called_pico_socket_close = 0;
tftp_finish(&example_session);
fail_if(!called_pico_socket_close);
/* Test eval_finish() len is 5*/
example_session.socket = &example_socket;
called_pico_socket_close = 0;
tftp_eval_finish(&example_session, 5);
fail_if(example_session.state != TFTP_STATE_CLOSING);
fail_if(!called_pico_socket_close);
/* Test eval_finish() len is PICO_TFTP_TOTAL_BLOCK_SIZE */
example_session.socket = &example_socket;
called_pico_socket_close = 0;
tftp_eval_finish(&example_session, PICO_TFTP_TOTAL_BLOCK_SIZE);
fail_if(called_pico_socket_close);
}
END_TEST
START_TEST(tc_tftp_send_ack)
{
example_session.socket = &example_socket;
#ifdef PICO_FAULTY
/* send_ack must not segfault when out of memory */
pico_set_mm_failure(1);
tftp_send_ack(&example_session);
fail_if(called_sendto > 0);
#endif
expected_opcode = PICO_TFTP_ACK;
tftp_send_ack(&example_session);
fail_if(called_sendto < 1);
}
END_TEST
START_TEST(tc_tftp_send_req)
{
/* Not needed. The tftp_send_rx_req and tftp_send_tx_req cover this. */
}
END_TEST
START_TEST(tc_tftp_send_rx_req)
{
char filename[14] = "some filename";
example_session.socket = &example_socket;
called_user_cb = 0;
called_pico_socket_close = 0;
called_sendto = 0;
#ifdef PICO_FAULTY
example_session.callback = tftp_user_cb;
/* send_req must call error cb when out of memory */
pico_set_mm_failure(1);
tftp_send_rx_req(&example_session, NULL, 0, filename);
fail_if(called_user_cb < 1);
fail_if(called_sendto > 0);
#endif
expected_opcode = PICO_TFTP_RRQ;
tftp_send_rx_req(&example_session, NULL, 0, NULL);
fail_if(called_sendto > 0); /* Calling with filename = NULL: not good */
tftp_send_rx_req(&example_session, NULL, 0, filename);
fail_if(called_sendto < 0);
}
END_TEST
START_TEST(tc_tftp_send_tx_req)
{
char filename[14] = "some filename";
example_session.socket = &example_socket;
called_user_cb = 0;
called_pico_socket_close = 0;
called_sendto = 0;
#ifdef PICO_FAULTY
example_session.callback = tftp_user_cb;
/* send_req must call error cb when out of memory */
pico_set_mm_failure(1);
tftp_send_tx_req(&example_session, NULL, 0, filename);
fail_if(called_user_cb < 1);
fail_if(called_sendto > 0);
#endif
expected_opcode = PICO_TFTP_WRQ;
tftp_send_tx_req(&example_session, NULL, 0, NULL);
fail_if(called_sendto > 0); /* Calling with filename = NULL: not good */
tftp_send_tx_req(&example_session, NULL, 0, filename);
fail_if(called_sendto < 0);
}
END_TEST
START_TEST(tc_tftp_send_error)
{
char longtext[1024];
example_session.socket = &example_socket;
called_user_cb = 0;
called_pico_socket_close = 0;
/* Sending empty msg */
called_sendto = 0;
expected_opcode = PICO_TFTP_ERROR;
tftp_send_error(&example_session, NULL, 0, 0, NULL);
fail_if(called_sendto < 1);
/* Sending some msg */
called_sendto = 0;
expected_opcode = PICO_TFTP_ERROR;
tftp_send_error(&example_session, NULL, 0, 0, "some text here");
fail_if(called_sendto < 1);
/* sending some very long msg */
memset(longtext, 'a', 1023);
longtext[1023] = (char)0;
called_sendto = 0;
expected_opcode = PICO_TFTP_ERROR;
tftp_send_error(&example_session, NULL, 0, 0, longtext);
fail_if(called_sendto < 1);
}
END_TEST
START_TEST(tc_tftp_send_data)
{
example_session.state = 0;
example_session.socket = &example_socket;
called_sendto = 0;
expected_opcode = PICO_TFTP_DATA;
tftp_send_data(&example_session, (const uint8_t*)"buffer", strlen("buffer"));
fail_if(called_sendto < 1);
fail_if(example_session.state != TFTP_STATE_WAIT_LAST_ACK);
}
END_TEST
START_TEST(tc_pico_tftp_abort)
{
int ret;
server.listen_socket = NULL;
/*first case: no session and no listening socket*/
ret = pico_tftp_abort(NULL, TFTP_ERR_EUSR, "test");
fail_if(ret != -1);
/*second case: no session but listening socket*/
server.listen_socket = example_session.socket = &example_socket;
pico_tftp_abort(NULL, TFTP_ERR_EUSR, "test");
fail_if(ret != -1);
/*tirdh case: session non into list*/
ret = pico_tftp_abort(&example_session, TFTP_ERR_EUSR, "test");
fail_if(ret != -1);
}
END_TEST
/* Receiving functions */
START_TEST(tc_tftp_data)
{
/* TODO: test this: static void tftp_data(uint8_t *block, uint32_t len, union pico_address *a, uint16_t port) */
}
END_TEST
START_TEST(tc_tftp_ack)
{
/* TODO: test this: static void tftp_ack(uint8_t *block, uint32_t len, union pico_address *a, uint16_t port) */
}
END_TEST
START_TEST(tc_tftp_timeout)
{
/* TODO: test this: static void tftp_timeout(pico_time t) */
}
END_TEST
START_TEST(tc_tftp_req)
{
/* TODO: test this: static void tftp_req(uint8_t *block, uint32_t len, union pico_address *a, uint16_t port) */
}
END_TEST
START_TEST(tc_tftp_data_err)
{
/* TODO: test this: static void tftp_data_err(uint8_t *block, uint32_t len, union pico_address *a, uint16_t port) */
}
END_TEST
START_TEST(tc_tftp_fsm_timeout)
{
/* TODO: test this: static void tftp_fsm_timeout(pico_time now, void *arg) */
}
END_TEST
START_TEST(tc_tftp_receive)
{
/* TODO: test this: static void tftp_receive(uint8_t *block, uint32_t r, union pico_address *a, uint16_t port) */
}
END_TEST
START_TEST(tc_tftp_cb)
{
/* TODO: test this: static void tftp_cb(uint16_t ev, struct pico_socket *s) */
}
END_TEST
START_TEST(tc_tftp_socket_open)
{
/* TODO: test this: static int tftp_socket_open(uint16_t family, union pico_address *a, uint16_t port) */
fail_if(tftp_socket_open(0xFFFF, 21) != NULL);
fail_if(tftp_socket_open(0xFFFF, 0xFFFF) != NULL);
}
END_TEST
Suite *pico_suite(void)
{
Suite *s = suite_create("PicoTCP");
/* TCase *TCase_check_opcode = tcase_create("Unit test for check_opcode"); */
TCase *TCase_find_session_by_socket = tcase_create("Unit test for find_session_by_socket");
TCase *TCase_tftp_finish = tcase_create("Unit test for tftp_finish");
TCase *TCase_tftp_send_ack = tcase_create("Unit test for tftp_send_ack");
TCase *TCase_tftp_send_req = tcase_create("Unit test for tftp_send_req");
TCase *TCase_tftp_send_rx_req = tcase_create("Unit test for tftp_send_rx_req");
TCase *TCase_tftp_send_tx_req = tcase_create("Unit test for tftp_send_tx_req");
TCase *TCase_tftp_send_error = tcase_create("Unit test for tftp_send_error");
TCase *TCase_tftp_send_data = tcase_create("Unit test for tftp_send_data");
TCase *Tcase_pico_tftp_abort = tcase_create("Unit test for pico_tftp_abort");
TCase *TCase_tftp_data = tcase_create("Unit test for tftp_data");
TCase *TCase_tftp_ack = tcase_create("Unit test for tftp_ack");
TCase *TCase_tftp_timeout = tcase_create("Unit test for tftp_timeout");
TCase *TCase_tftp_req = tcase_create("Unit test for tftp_req");
TCase *TCase_tftp_data_err = tcase_create("Unit test for tftp_data_err");
TCase *TCase_tftp_fsm_timeout = tcase_create("Unit test for tftp_fsm_timeout");
TCase *TCase_tftp_receive = tcase_create("Unit test for tftp_receive");
TCase *TCase_tftp_cb = tcase_create("Unit test for tftp_cb");
TCase *TCase_tftp_socket_open = tcase_create("Unit test for tftp_socket_open");
/* tcase_add_test(TCase_check_opcode, tc_check_opcode); */
/* suite_add_tcase(s, TCase_check_opcode); */
tcase_add_test(TCase_find_session_by_socket, tc_find_session_by_socket);
suite_add_tcase(s, TCase_find_session_by_socket);
tcase_add_test(TCase_tftp_finish, tc_tftp_finish);
suite_add_tcase(s, TCase_tftp_finish);
tcase_add_test(TCase_tftp_send_ack, tc_tftp_send_ack);
suite_add_tcase(s, TCase_tftp_send_ack);
tcase_add_test(TCase_tftp_send_req, tc_tftp_send_req);
suite_add_tcase(s, TCase_tftp_send_req);
tcase_add_test(TCase_tftp_send_rx_req, tc_tftp_send_rx_req);
suite_add_tcase(s, TCase_tftp_send_rx_req);
tcase_add_test(TCase_tftp_send_tx_req, tc_tftp_send_tx_req);
suite_add_tcase(s, TCase_tftp_send_tx_req);
tcase_add_test(TCase_tftp_send_error, tc_tftp_send_error);
suite_add_tcase(s, TCase_tftp_send_error);
tcase_add_test(TCase_tftp_send_data, tc_tftp_send_data);
suite_add_tcase(s, TCase_tftp_send_data);
tcase_add_test(TCase_tftp_data, tc_tftp_data);
suite_add_tcase(s, Tcase_pico_tftp_abort);
tcase_add_test(Tcase_pico_tftp_abort, tc_pico_tftp_abort);
suite_add_tcase(s, TCase_tftp_data);
tcase_add_test(TCase_tftp_ack, tc_tftp_ack);
suite_add_tcase(s, TCase_tftp_ack);
tcase_add_test(TCase_tftp_timeout, tc_tftp_timeout);
suite_add_tcase(s, TCase_tftp_timeout);
tcase_add_test(TCase_tftp_req, tc_tftp_req);
suite_add_tcase(s, TCase_tftp_req);
tcase_add_test(TCase_tftp_data_err, tc_tftp_data_err);
suite_add_tcase(s, TCase_tftp_data_err);
tcase_add_test(TCase_tftp_fsm_timeout, tc_tftp_fsm_timeout);
suite_add_tcase(s, TCase_tftp_fsm_timeout);
tcase_add_test(TCase_tftp_receive, tc_tftp_receive);
suite_add_tcase(s, TCase_tftp_receive);
tcase_add_test(TCase_tftp_cb, tc_tftp_cb);
suite_add_tcase(s, TCase_tftp_cb);
tcase_add_test(TCase_tftp_socket_open, tc_tftp_socket_open);
suite_add_tcase(s, TCase_tftp_socket_open);
return s;
}
int main(void)
{
int fails;
Suite *s = pico_suite();
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
fails = srunner_ntests_failed(sr);
srunner_free(sr);
return fails;
}