diff --git a/README.md b/README.md index fb04184..ea65c48 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,13 @@ # MicroTCP -Micro TCP is a network stack designed to be easily embeddable, portable and thoroughly tested. It implements ARP, IP, ICMP and TCP. The ideal use-cases are user-space networking and using it in bare-metal microcontrollers. +MicroTCP is a TCP/IP network stack which I started building as a learning exercise while I was attending the Computer Networking course at the Università degli Studi di Napoli Federico II. It's just a hobby project and is intended to just be a minimal, yet complete, implementation. + +At this moment MicroTCP implements ARP (RFC 826, complete), IPv4 (no fragmentation), ICMP (minimum necessary to reply to pings) and TCP (complete but not stress-tested). Note that "complete" should be not intended as "fully compliant" but just as a measure of progress on all of the major features. For instance, it's complete enough to handle HTTP traffic on a local network (Look into examples/microhttp to know more). + +## Where does it run? +MicroTCP can run on Windows and Linux alongside the OS's network stack. To route the network traffic to MicroTCP, the process running it behaves as a virtual host with its own IP address. This is done using a TAP device, which comes built-in on Linux but needs installing on Windows. It should be very easy to adapt to run on microcontrollers but haven't tried yet, the dream is to serve my [blog](https://cozis.github.io/) from an STM32 board. ## Usage -To use it, you need to instanciate a `microtcp_t` structure using either the `microtcp_create` or `microtcp_create_using_callbacks` constructor. - -The basic constructor `microtcp_create` behaves differently based on your platform because it needs to plug the stack to the system. At the moment it's assumed a Linux host and the instanciated stack is associated to a tap device `tap0` with IP `10.0.0.5/24`. The stack produces packets with IP `10.0.0.4/24` (being honest, this configuration is only useful for testing). - -It's also possible to configure the stack explicitly using the `microtcp_create_using_callbacks`, which lets the caller provide the callbacks to input the ethernet frames to the stack and send frames back on the wire. Each system will need it's specific implementation of these callbacks. - -Each instance of MicroTCP (without considering the callbacks) is completely isolated from the others, therefore, if your specific callback implementation allows it, you can have as many instances as you like! Usually the callbacks introduce a dependency between the stacks because the system is one big global state. - -Once instanciated, you can free the stack using `microtcp_destroy`. - -Once a `microtcp_t` instance is created, you can create and use sockets with methods analogous to the BSD socket API. For instance, here's a simple TCP echo server which replies to messages with the message itself prefixed with "echo: ": +MicroTCP's uses the usual socket interface any network programmer is familiar with, the main difference being you need to esplicitly instanciate the network stack and pass its handle around. Without further ado, here's a simple echo server that shows the basic usage: ```c #include @@ -45,10 +40,10 @@ int main(void) // If you want to use this code, you probably want to // add some checks! ``` +This should be pretty straight forward to understand. One thing may be worth noting is that `microtcp_open` behaves as the BSD's `socket+bind+listen` all at once to setup a listening TCP server. -## Contributing -The build result is a header and a .c obtained as an amalgamation of all the source files. Any header included in the source files must be guarded by a `#ifndef MICROTCP_AMALGAMATION`. +There are more than one way to set up the stack, the main way being `microtcp_create` which creates a virtual network inferface on the host OS with IP 10.0.0.5/24 and a virtual host for the MicroTCP process with the 10.0.0.4/24 IP. You can open Wireshark on the virtual NIC to inspect the traffic between the host and the process. -## Functionalities -MicroTCP will not support -* TCP options \ No newline at end of file +It's also possible to configure the stack using the `microtcp_create_using_callbacks`, which lets you explicitly provide the input L2 frames to it and receive the frames in a buffer. This is how one would run the stack on a microcontroller. + +Each instance of MicroTCP (without considering the callbacks) is completely isolated from the others, therefore, if your specific callback implementation allows it, you can have as many instances as you like! Usually the callbacks introduce a dependency between the stacks because the system is one big global state. diff --git a/examples/echo_tcp_mux.c b/examples/echo_tcp_mux.c deleted file mode 100644 index 7bd3811..0000000 --- a/examples/echo_tcp_mux.c +++ /dev/null @@ -1,25 +0,0 @@ - - -int main(void) -{ - microtcp_t *mtcp = microtcp_create(..); - - uint16_t port = 8080; - microtcp_socket_t *socket = microtcp_open(mtcp, port, 0); - - microtcp_mux_t *mux = microtcp_mux_create(mtcp); - for (int i = 0; i < 3; i++) { - microtcp_socket_t *accepted = microtcp_accept(socket, 0, 0); - microtcp_mux_register(mux, accepted, MICROTCP_MUX_RECV | MICROTCP_MUX_SEND); - } - - for (microtcp_muxevent_t event; microtcp_mux_wait(mux, &event)) { - if (event.events & MICROTCP_MUX_RECV) { - // Il socket "event.socket" ha dei dati da leggere - } else { - // Il socket "event.socket" ha spazio per inviare - } - } - - microtcp_destroy(mtcp); -} \ No newline at end of file diff --git a/makefile b/makefile index eb5687d..012b215 100644 --- a/makefile +++ b/makefile @@ -143,15 +143,5 @@ build/microtcp.c: 3p/include/tinycthread.h 3p/src/tinycthread.c $(wildcard src/* build/echo_http: examples/microhttp/main.c $(LIBDIR)/libtuntap.a 3p/include/tuntap.h 3p/include/tuntap-export.h build/microtcp.h build/microtcp.c gcc examples/microhttp/main.c examples/microhttp/xhttp.c build/microtcp.c -o $@ $(CFLAGS) $(LFLAGS) -DDEBUG=1 -DARP_DEBUG -DMICROTCP_DEBUG -DIP_DEBUG -DICMP_DEBUG -DTCP_DEBUG -DMICROTCP_USING_MUX -build/test: tests/test.c tests/test_tcp_timer.c src/tcp_timer.c src/tcp_timer.h - gcc -fprofile-arcs -ftest-coverage tests/test.c tests/test_tcp_timer.c src/tcp_timer.c -o $@ -Wall -Wextra -DTCP_MAX_TIMERS=4 - -build/test_arp: tests/test_arp.c - gcc tests/test_arp.c -o build/test_arp -Wall -Wextra - -report: build/test - ./build/test - gcov -b build/test-tcp_timer.c - clean: rm -fr build 3p/libtuntap/build 3p/lib/* 3p/include/* \ No newline at end of file diff --git a/misc/serv.py b/misc/serv.py deleted file mode 100644 index 2e38463..0000000 --- a/misc/serv.py +++ /dev/null @@ -1,15 +0,0 @@ - -from http.server import BaseHTTPRequestHandler, HTTPServer - -class RequestHandler(BaseHTTPRequestHandler): - - def do_GET(self): - self.send_response(200) - self.send_header('Content-type','text/html') - self.end_headers() - message = "Hello world!" - self.wfile.write(bytes(message, "utf8")) - return - -addr = ('127.0.0.1', 8080) -HTTPServer(addr, RequestHandler).serve_forever() \ No newline at end of file diff --git a/tests/arp_0.test b/tests/arp_0.test deleted file mode 100644 index 1d3f173..0000000 --- a/tests/arp_0.test +++ /dev/null @@ -1,11 +0,0 @@ -@type [ARP] - -@desc - Peer requests host's MAC given its IP and host replies. - -@IP [10.0.0.4] -@MAC [56:34:f5:4d:4f:44] - -@timeline - <= [ ETHERNET | IP | 6 | 4 | REQUEST | 00:34:56:34:f5:4f | 10.0.0.5 | 00:00:00:00:00:00 | 10.0.0.4 ] - => [ ETHERNET | IP | 6 | 4 | REPLY | 56:34:f5:4d:4f:44 | 10.0.0.4 | 00:34:56:34:f5:4f | 10.0.0.5 ] diff --git a/tests/test.c b/tests/test.c deleted file mode 100644 index 1fe3f98..0000000 --- a/tests/test.c +++ /dev/null @@ -1,8 +0,0 @@ - -void test_tcp_timer(void); - -int main(void) -{ - test_tcp_timer(); - return 0; -} \ No newline at end of file diff --git a/tests/test_arp.c b/tests/test_arp.c deleted file mode 100644 index 14b63ba..0000000 --- a/tests/test_arp.c +++ /dev/null @@ -1,463 +0,0 @@ -#include -#include -#include "../src/utils.c" -#include "../src/endian.c" -#include "../src/arp.c" - -/* - BLACK BOX TEST CASES - - A) Peer requests host's MAC given its IP and host - replies. - - B) Peer requests host's non MAC level 2 address - given its IP and host doesn't reply because it - only supports MAC. - - C) Peer requests host's MAC address given its non - IP level 3 address and host doesn't reply - because it only supports IP. - - D) Peer requests host's MAC given its IP, but the - MAC address length field isn't 6, therefore - host doesn't reply. - - E) Peer requests host's MAC given its IP, but the - IP address length field isn't 4, therefore host - doesn't reply. - - F) Peer sends a request/reply that doesn't refer - to host and is from a sender with IP never seen - by the host (no entry in the translation table). - It's expected that no entry is added to the - translation table. - - G) Peer sends a request/reply that doesn't refer - to host but is from a sender with IP already - in the ARP translation table, therefore is - expected that host updates the entry. - - H) Program queries the ARP module for a MAC that - isn't cached, therefore an ARP request is - expected to be generated and, when replied to, - the ARP module is expected to resolve the - program's query. - - I) Program queries the ARP module for a MAC that's - cached, therefore the ARP module is expected to - resolve it without sending packets. -*/ - -typedef enum { - TEST_PASSED, - TEST_FAILED, - TEST_ABORTED, -} test_result_t; - -#define OUTPUT_QUEUE_SIZE 8 - -typedef struct { - arp_state_t *state; - arp_packet_t queue[OUTPUT_QUEUE_SIZE]; - int count; - int oflow; -} output_queue_t; - -static void send_arp_packet_callback(void *data, mac_address_t mac) -{ - output_queue_t *oq = (output_queue_t*) data; - if (oq->count == OUTPUT_QUEUE_SIZE) - oq->oflow++; - else { - oq->count++; - if (oq->count == OUTPUT_QUEUE_SIZE) - arp_change_output_buffer(oq->state, NULL, 0); - else - arp_change_output_buffer(oq->state, oq->queue+oq->count, sizeof(arp_packet_t)); - } -} - -test_result_t test_arp_bb_A(char *msg, size_t msgmax) -{ - // Addresses of the packets that will be sent towards - // the ARP module - const char net_ip_str[] = "10.0.0.5"; - const char net_mac_str[] = "00:34:56:34:f5:4f"; - - // Addresses of the ARP module - const char ip_str[] = "10.0.0.4"; - const char mac_str[] = "56:34:f5:4d:4f:44"; - - // Parse the addresses to binary form - ip_address_t ip, net_ip; - mac_address_t mac, net_mac; - if (!parse_mac(mac_str, sizeof(mac_str)-1, &mac) || - !parse_ip(ip_str, &ip) || - !parse_mac(net_mac_str, sizeof(net_mac_str)-1, &net_mac) || - !parse_ip(net_ip_str, &net_ip)) { - snprintf(msg, msgmax, "Couldn't parse IP and MAC strings"); - return TEST_ABORTED; - } - - // Set up the module with the output queue - arp_state_t state; - output_queue_t oq = {.state=&state, .count=0, .oflow=0}; // Buffer where replies and requests will be stored - // by the ARP module - arp_init(&state, ip, mac, &oq, send_arp_packet_callback); - arp_change_output_buffer(&state, oq.queue, sizeof(arp_packet_t)); - - // Build the request - arp_packet_t request = { - .hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET), - .protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP), - .hardware_len = 6, - .protocol_len = 4, - .operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST), - .sender_hardware_address = net_mac, - .sender_protocol_address = net_ip, - .target_hardware_address = MAC_ZERO, - .target_protocol_address = ip, - }; - - // Send the request - arp_process_result_t res; - res = arp_process_packet(&state, &request, sizeof(arp_packet_t)); - switch (res) { - case ARP_PROCESS_RESULT_HWARENOTSUPP: - case ARP_PROCESS_RESULT_PROTONOTSUPP: - case ARP_PROCESS_RESULT_INVALID: - snprintf(msg, msgmax, "ARP module couldn't process request"); - return TEST_FAILED; - - case ARP_PROCESS_RESULT_OK: - break; - } - - // Make sure that the module replies one time and one time only - if (oq.count == 0) { - // The ARP module sent no reply given - // our request. - snprintf(msg, msgmax, "ARP module didn't reply"); - return TEST_FAILED; - } - if (oq.count > 1) { - // Sent too many replies - snprintf(msg, msgmax, "ARP module replied too many times"); - return TEST_FAILED; - } - - // Check that the reply has the right content - arp_packet_t *reply = oq.queue; - if (net_to_cpu_u16(reply->hardware_type) != ARP_HARDWARE_ETHERNET || - net_to_cpu_u16(reply->protocol_type) != ARP_PROTOCOL_IP || - net_to_cpu_u16(reply->operation_type) != ARP_OPERATION_REPLY || - memcmp(&reply->sender_hardware_address, &mac, sizeof(mac_address_t)) || - memcmp(&reply->sender_protocol_address, &ip, sizeof(ip_address_t)) || - memcmp(&reply->target_hardware_address, &net_mac, sizeof(mac_address_t)) || - memcmp(&reply->target_protocol_address, &net_ip, sizeof(ip_address_t))) { - // Unexpected reply - snprintf(msg, msgmax, "ARP module sent an unexpected reply"); - return TEST_FAILED; - } - - return TEST_PASSED; -} - -test_result_t test_arp_bb_B(char *msg, size_t msgmax) -{ - // Addresses of the packets that will be sent towards - // the ARP module - const char net_ip_str[] = "10.0.0.5"; - const char net_mac_str[] = "00:34:56:34:f5:4f"; - - // Addresses of the ARP module - const char ip_str[] = "10.0.0.4"; - const char mac_str[] = "56:34:f5:4d:4f:44"; - - // Parse the addresses to binary form - ip_address_t ip, net_ip; - mac_address_t mac, net_mac; - if (!parse_mac(mac_str, sizeof(mac_str)-1, &mac) || - !parse_ip(ip_str, &ip) || - !parse_mac(net_mac_str, sizeof(net_mac_str)-1, &net_mac) || - !parse_ip(net_ip_str, &net_ip)) { - snprintf(msg, msgmax, "Couldn't parse IP and MAC strings"); - return TEST_ABORTED; - } - - // Set up the module with the output queue - arp_state_t state; - output_queue_t oq = {.state=&state, .count=0, .oflow=0}; // Buffer where replies and requests will be stored - // by the ARP module - arp_init(&state, ip, mac, &oq, send_arp_packet_callback); - arp_change_output_buffer(&state, oq.queue, sizeof(arp_packet_t)); - - // Build the request - arp_packet_t request = { - .hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET)+1, // Some value other than ETHERNET - .protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP), - .hardware_len = 6, - .protocol_len = 4, - .operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST), - .sender_hardware_address = net_mac, - .sender_protocol_address = net_ip, - .target_hardware_address = MAC_ZERO, - .target_protocol_address = ip, - }; - - // Send the request - arp_process_result_t res; - res = arp_process_packet(&state, &request, sizeof(arp_packet_t)); - switch (res) { - case ARP_PROCESS_RESULT_HWARENOTSUPP: - break; - - case ARP_PROCESS_RESULT_PROTONOTSUPP: - case ARP_PROCESS_RESULT_INVALID: - snprintf(msg, msgmax, "ARP module couldn't process request"); - return TEST_FAILED; - - case ARP_PROCESS_RESULT_OK: - snprintf(msg, msgmax, "ARP module processed a request for an hardware type it didn't support"); - return TEST_FAILED; - } - - if (oq.count > 0) { - // Sent replies - snprintf(msg, msgmax, "ARP module replied even though it failed to process the request"); - return TEST_FAILED; - } - - return TEST_PASSED; -} - -test_result_t test_arp_bb_C(char *msg, size_t msgmax) -{ - // Addresses of the packets that will be sent towards - // the ARP module - const char net_ip_str[] = "10.0.0.5"; - const char net_mac_str[] = "00:34:56:34:f5:4f"; - - // Addresses of the ARP module - const char ip_str[] = "10.0.0.4"; - const char mac_str[] = "56:34:f5:4d:4f:44"; - - // Parse the addresses to binary form - ip_address_t ip, net_ip; - mac_address_t mac, net_mac; - if (!parse_mac(mac_str, sizeof(mac_str)-1, &mac) || - !parse_ip(ip_str, &ip) || - !parse_mac(net_mac_str, sizeof(net_mac_str)-1, &net_mac) || - !parse_ip(net_ip_str, &net_ip)) { - snprintf(msg, msgmax, "Couldn't parse IP and MAC strings"); - return TEST_ABORTED; - } - - // Set up the module with the output queue - arp_state_t state; - output_queue_t oq = {.state=&state, .count=0, .oflow=0}; // Buffer where replies and requests will be stored - // by the ARP module - arp_init(&state, ip, mac, &oq, send_arp_packet_callback); - arp_change_output_buffer(&state, oq.queue, sizeof(arp_packet_t)); - - // Build the request - arp_packet_t request = { - .hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET), - .protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP)+1, // Some value other than IP - .hardware_len = 6, - .protocol_len = 4, - .operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST), - .sender_hardware_address = net_mac, - .sender_protocol_address = net_ip, - .target_hardware_address = MAC_ZERO, - .target_protocol_address = ip, - }; - - // Send the request - arp_process_result_t res; - res = arp_process_packet(&state, &request, sizeof(arp_packet_t)); - switch (res) { - - case ARP_PROCESS_RESULT_PROTONOTSUPP: - break; - - case ARP_PROCESS_RESULT_HWARENOTSUPP: - case ARP_PROCESS_RESULT_INVALID: - snprintf(msg, msgmax, "ARP module couldn't process request"); - return TEST_FAILED; - - case ARP_PROCESS_RESULT_OK: - snprintf(msg, msgmax, "ARP module processed a request for a protocol type it didn't support"); - return TEST_FAILED; - } - - if (oq.count > 0) { - // Sent replies - snprintf(msg, msgmax, "ARP module replied even though it failed to process the request"); - return TEST_FAILED; - } - - return TEST_PASSED; -} - - -test_result_t test_arp_bb_D(char *msg, size_t msgmax) -{ - // Addresses of the packets that will be sent towards - // the ARP module - const char net_ip_str[] = "10.0.0.5"; - const char net_mac_str[] = "00:34:56:34:f5:4f"; - - // Addresses of the ARP module - const char ip_str[] = "10.0.0.4"; - const char mac_str[] = "56:34:f5:4d:4f:44"; - - // Parse the addresses to binary form - ip_address_t ip, net_ip; - mac_address_t mac, net_mac; - if (!parse_mac(mac_str, sizeof(mac_str)-1, &mac) || - !parse_ip(ip_str, &ip) || - !parse_mac(net_mac_str, sizeof(net_mac_str)-1, &net_mac) || - !parse_ip(net_ip_str, &net_ip)) { - snprintf(msg, msgmax, "Couldn't parse IP and MAC strings"); - return TEST_ABORTED; - } - - // Set up the module with the output queue - arp_state_t state; - output_queue_t oq = {.state=&state, .count=0, .oflow=0}; // Buffer where replies and requests will be stored - // by the ARP module - arp_init(&state, ip, mac, &oq, send_arp_packet_callback); - arp_change_output_buffer(&state, oq.queue, sizeof(arp_packet_t)); - - // Build the request - arp_packet_t request = { - .hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET), - .protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP), - .hardware_len = 6+1, // Something other than the correct length - .protocol_len = 4, - .operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST), - .sender_hardware_address = net_mac, - .sender_protocol_address = net_ip, - .target_hardware_address = MAC_ZERO, - .target_protocol_address = ip, - }; - - // Send the request - arp_process_result_t res; - res = arp_process_packet(&state, &request, sizeof(arp_packet_t)); - switch (res) { - - case ARP_PROCESS_RESULT_INVALID: - break; - - case ARP_PROCESS_RESULT_HWARENOTSUPP: - case ARP_PROCESS_RESULT_PROTONOTSUPP: - snprintf(msg, msgmax, "ARP module couldn't process request"); - return TEST_FAILED; - - case ARP_PROCESS_RESULT_OK: - snprintf(msg, msgmax, "ARP module processed a request for an invalid hardware address length"); - return TEST_FAILED; - } - - if (oq.count > 0) { - // Sent replies - snprintf(msg, msgmax, "ARP module replied even though it failed to process the request"); - return TEST_FAILED; - } - - return TEST_PASSED; -} - - -test_result_t test_arp_bb_E(char *msg, size_t msgmax) -{ - // Addresses of the packets that will be sent towards - // the ARP module - const char net_ip_str[] = "10.0.0.5"; - const char net_mac_str[] = "00:34:56:34:f5:4f"; - - // Addresses of the ARP module - const char ip_str[] = "10.0.0.4"; - const char mac_str[] = "56:34:f5:4d:4f:44"; - - // Parse the addresses to binary form - ip_address_t ip, net_ip; - mac_address_t mac, net_mac; - if (!parse_mac(mac_str, sizeof(mac_str)-1, &mac) || - !parse_ip(ip_str, &ip) || - !parse_mac(net_mac_str, sizeof(net_mac_str)-1, &net_mac) || - !parse_ip(net_ip_str, &net_ip)) { - snprintf(msg, msgmax, "Couldn't parse IP and MAC strings"); - return TEST_ABORTED; - } - - // Set up the module with the output queue - arp_state_t state; - output_queue_t oq = {.state=&state, .count=0, .oflow=0}; // Buffer where replies and requests will be stored - // by the ARP module - arp_init(&state, ip, mac, &oq, send_arp_packet_callback); - arp_change_output_buffer(&state, oq.queue, sizeof(arp_packet_t)); - - // Build the request - arp_packet_t request = { - .hardware_type = cpu_to_net_u16(ARP_HARDWARE_ETHERNET), - .protocol_type = cpu_to_net_u16(ARP_PROTOCOL_IP), - .hardware_len = 6, - .protocol_len = 4+1, // Something other than the correct length - .operation_type = cpu_to_net_u16(ARP_OPERATION_REQUEST), - .sender_hardware_address = net_mac, - .sender_protocol_address = net_ip, - .target_hardware_address = MAC_ZERO, - .target_protocol_address = ip, - }; - - // Send the request - arp_process_result_t res; - res = arp_process_packet(&state, &request, sizeof(arp_packet_t)); - switch (res) { - - case ARP_PROCESS_RESULT_INVALID: - break; - - case ARP_PROCESS_RESULT_HWARENOTSUPP: - case ARP_PROCESS_RESULT_PROTONOTSUPP: - snprintf(msg, msgmax, "ARP module couldn't process request"); - return TEST_FAILED; - - case ARP_PROCESS_RESULT_OK: - snprintf(msg, msgmax, "ARP module processed a request for an invalid protocol address length"); - return TEST_FAILED; - } - - if (oq.count > 0) { - // Sent replies - snprintf(msg, msgmax, "ARP module replied even though it failed to process the request"); - return TEST_FAILED; - } - - return TEST_PASSED; -} - -int main(void) -{ - void *tests[] = { - test_arp_bb_A, - test_arp_bb_B, - test_arp_bb_C, - test_arp_bb_D, - test_arp_bb_E, - }; - - char msg[256]; - for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { - test_result_t (*test_fn)(char*, size_t) = tests[i]; - switch (test_fn(msg, sizeof(msg))) { - case TEST_PASSED: fprintf(stdout, "PASSED\n"); break; - case TEST_FAILED: fprintf(stdout, "FAILED: %s\n", msg); break; - case TEST_ABORTED: fprintf(stdout, "ABORTED: %s\n", msg); break; - } - } - return 0; -} \ No newline at end of file diff --git a/tests/test_tcp_timer.c b/tests/test_tcp_timer.c deleted file mode 100644 index 9fc72b5..0000000 --- a/tests/test_tcp_timer.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include "../src/tcp_timer.h" - -static void set_int_variable_to_1(void *data) -{ - int *n = data; - *n = 1; -} - -static void test_timer(void) -{ - static_assert(TCP_MAX_TIMERS > 0); - - tcp_timerset_t set; - tcp_timerset_init(&set); - - int resolved = 0; - tcp_timer_t *t1 = tcp_timer_create(&set, 5, "t1", set_int_variable_to_1, &resolved); - - assert(t1); - assert(resolved == 0); - - tcp_timerset_step(&set, 1); - assert(resolved == 0); - - tcp_timerset_step(&set, 4); - assert(resolved == 1); - - tcp_timerset_free(&set); -} - -static void test_disabled_timer(void) -{ - static_assert(TCP_MAX_TIMERS > 0); - - tcp_timerset_t set; - tcp_timerset_init(&set); - - int resolved = 0; - tcp_timer_t *t1 = tcp_timer_create(&set, 5, "t1", set_int_variable_to_1, &resolved); - - assert(t1); - assert(resolved == 0); - - tcp_timer_disable(t1); - - tcp_timerset_step(&set, 1); - assert(resolved == 0); - - tcp_timerset_step(&set, 4); - assert(resolved == 0); - - tcp_timerset_free(&set); -} - -static void test_disabled_timer_2(void) -{ - static_assert(TCP_MAX_TIMERS > 0); - - tcp_timerset_t set; - tcp_timerset_init(&set); - - int resolved = 0; - tcp_timer_t *t1 = tcp_timer_create(&set, 5, "t1", set_int_variable_to_1, &resolved); - - assert(t1); - assert(resolved == 0); - - tcp_timerset_step(&set, 1); - assert(resolved == 0); - - tcp_timer_disable(t1); - - tcp_timerset_step(&set, 4); - assert(resolved == 0); - - tcp_timerset_free(&set); -} - -static void test_disabled_timer_3(void) -{ - static_assert(TCP_MAX_TIMERS > 0); - - tcp_timerset_t set; - tcp_timerset_init(&set); - - int resolved_1 = 0; - int resolved_2 = 0; - tcp_timer_t *t1 = tcp_timer_create(&set, 5, "t1", set_int_variable_to_1, &resolved_1); - tcp_timer_t *t2 = tcp_timer_create(&set, 5, "t2", set_int_variable_to_1, &resolved_2); - - assert(t1); - assert(t2); - assert(resolved_1 == 0); - assert(resolved_2 == 0); - - tcp_timerset_step(&set, 1); - assert(resolved_1 == 0); - assert(resolved_2 == 0); - - tcp_timer_disable(t1); - - tcp_timerset_step(&set, 4); - assert(resolved_1 == 0); - assert(resolved_2 == 1); - - tcp_timerset_free(&set); -} - -static void test_disabled_timer_4(void) -{ - static_assert(TCP_MAX_TIMERS > 0); - - tcp_timerset_t set; - tcp_timerset_init(&set); - - int resolved_1 = 0; - int resolved_2 = 0; - tcp_timer_t *t1 = tcp_timer_create(&set, 5, "t1", set_int_variable_to_1, &resolved_1); - tcp_timer_t *t2 = tcp_timer_create(&set, 5, "t2", set_int_variable_to_1, &resolved_2); - - assert(t1); - assert(t2); - assert(resolved_1 == 0); - assert(resolved_2 == 0); - - tcp_timerset_step(&set, 1); - assert(resolved_1 == 0); - assert(resolved_2 == 0); - - tcp_timer_disable(t2); - - tcp_timerset_step(&set, 4); - assert(resolved_1 == 1); - assert(resolved_2 == 0); - - tcp_timerset_free(&set); -} - -static void test_out_of_timers(void) -{ - static_assert(TCP_MAX_TIMERS > 0); - - tcp_timerset_t set; - tcp_timerset_init(&set); - - int temp; - for (int i = 0; i < TCP_MAX_TIMERS; i++) { - tcp_timer_t *t = tcp_timer_create(&set, 5, "t1", set_int_variable_to_1, &temp); - assert(t != NULL); - } - tcp_timer_t *t = tcp_timer_create(&set, 5, "t2", set_int_variable_to_1, &temp); - assert(t == NULL); - - tcp_timerset_free(&set); -} - -void test_tcp_timer(void) -{ - test_timer(); - test_disabled_timer(); - test_disabled_timer_2(); - test_disabled_timer_3(); - test_disabled_timer_4(); - test_out_of_timers(); -} \ No newline at end of file