diff --git a/Makefile.dep b/Makefile.dep index 4e1b196c1a..48849ff24d 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -422,8 +422,7 @@ ifneq (,$(filter gnrc_tcp,$(USEMODULE))) USEMODULE += inet_csum USEMODULE += random USEMODULE += tcp - USEMODULE += xtimer - USEMODULE += core_mbox + USEMODULE += evtimer_mbox endif ifneq (,$(filter gnrc_pktdump,$(USEMODULE))) diff --git a/sys/include/net/gnrc/tcp.h b/sys/include/net/gnrc/tcp.h index d44412e41c..85991758d8 100644 --- a/sys/include/net/gnrc/tcp.h +++ b/sys/include/net/gnrc/tcp.h @@ -58,7 +58,7 @@ typedef struct { * @param[in] addr Address for endpoint. * @param[in] addr_size Size of @p addr. * @param[in] port Port number for endpoint. - * @param[in] netif Network inferface to use. + * @param[in] netif Network interface to use. * * @return 0 on success. * @return -EAFNOSUPPORT if @p address_family is not supported. @@ -166,18 +166,18 @@ int gnrc_tcp_open_passive(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *local); * @param[in,out] tcb TCB holding the connection information. * @param[in] data Pointer to the data that should be transmitted. * @param[in] len Number of bytes that should be transmitted. - * @param[in] user_timeout_duration_us If not zero and there was not data transmitted - * the function returns after user_timeout_duration_us. + * @param[in] user_timeout_duration_ms If not zero and there was not data transmitted + * the function returns after user_timeout_duration_ms. * If zero, no timeout will be triggered. * * @return The number of successfully transmitted bytes. * @return -ENOTCONN if connection is not established. * @return -ECONNRESET if connection was reset by the peer. * @return -ECONNABORTED if the connection was aborted. - * @return -ETIMEDOUT if @p user_timeout_duration_us expired. + * @return -ETIMEDOUT if @p user_timeout_duration_ms expired. */ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, - const uint32_t user_timeout_duration_us); + const uint32_t user_timeout_duration_ms); /** * @brief Receive Data from the peer. @@ -193,11 +193,11 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, * should be copied into. * @param[in] max_len Maximum amount to bytes that should be read * into @p data. - * @param[in] user_timeout_duration_us Timeout for receive in microseconds. + * @param[in] user_timeout_duration_ms Timeout for receive in milliseconds. * If zero and no data is available, the function * returns immediately. If not zero the function * blocks until data is available or - * @p user_timeout_duration_us microseconds passed. + * @p user_timeout_duration_ms milliseconds passed. * * @return The number of bytes read into @p data. * @return 0, if the connection is closing and no further data can be read. @@ -205,10 +205,10 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, * @return -EAGAIN if user_timeout_duration_us is zero and no data is available. * @return -ECONNRESET if connection was reset by the peer. * @return -ECONNABORTED if the connection was aborted. - * @return -ETIMEDOUT if @p user_timeout_duration_us expired. + * @return -ETIMEDOUT if @p user_timeout_duration_ms expired. */ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, - const uint32_t user_timeout_duration_us); + const uint32_t user_timeout_duration_ms); /** * @brief Close a TCP connection. diff --git a/sys/include/net/gnrc/tcp/config.h b/sys/include/net/gnrc/tcp/config.h index 9c95fb55aa..e6cf903143 100644 --- a/sys/include/net/gnrc/tcp/config.h +++ b/sys/include/net/gnrc/tcp/config.h @@ -48,22 +48,22 @@ extern "C" { * RTO <- SRTT + max (G, K*RTTVAR) * * where K is a constant, and G is clock granularity in seconds - * ( @ref CONFIG_GNRC_TCP_RTO_GRANULARITY). + * ( @ref CONFIG_GNRC_TCP_RTO_GRANULARITY_MS). * For more information refer to https://tools.ietf.org/html/rfc6298 * @{ */ /** - * @brief Timeout duration for user calls. Default is 2 minutes. + * @brief Timeout duration in milliseconds for user calls. Default is 2 minutes. */ -#ifndef CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION -#define CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION (120U * US_PER_SEC) +#ifndef CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS +#define CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS (120U * MS_PER_SEC) #endif /** - * @brief Maximum segment lifetime (MSL). Default is 30 seconds. + * @brief Maximum segment lifetime (MSL) in milliseconds. Default is 30 seconds. */ -#ifndef CONFIG_GNRC_TCP_MSL -#define CONFIG_GNRC_TCP_MSL (30U * US_PER_SEC) +#ifndef CONFIG_GNRC_TCP_MSL_MS +#define CONFIG_GNRC_TCP_MSL_MS (30U * MS_PER_SEC) #endif /** @@ -109,28 +109,28 @@ extern "C" { #endif /** - * @brief Lower bound for RTO = 1 sec (see RFC 6298) + * @brief Lower bound for RTO in milliseconds. Default is 1 sec (see RFC 6298) * * @note Retransmission Timeout (RTO) determines how long TCP waits for * acknowledgment (ACK) of transmitted segment. If the acknowledgment * isn't received within this time it is considered lost. */ -#ifndef CONFIG_GNRC_TCP_RTO_LOWER_BOUND -#define CONFIG_GNRC_TCP_RTO_LOWER_BOUND (1U * US_PER_SEC) +#ifndef CONFIG_GNRC_TCP_RTO_LOWER_BOUND_MS +#define CONFIG_GNRC_TCP_RTO_LOWER_BOUND_MS (1U * MS_PER_SEC) #endif /** - * @brief Upper bound for RTO = 60 sec (see RFC 6298) + * @brief Upper bound for RTO in milliseconds. Default is 60 sec (see RFC 6298) */ -#ifndef CONFIG_GNRC_TCP_RTO_UPPER_BOUND -#define CONFIG_GNRC_TCP_RTO_UPPER_BOUND (60U * US_PER_SEC) +#ifndef CONFIG_GNRC_TCP_RTO_UPPER_BOUND_MS +#define CONFIG_GNRC_TCP_RTO_UPPER_BOUND_MS (60U * MS_PER_SEC) #endif /** - * @brief Assumes clock granularity for TCP of 10 ms (see RFC 6298) + * @brief Clock granularity for TCP in milliseconds. Dedault is 10 milliseconds (see RFC 6298) */ -#ifndef CONFIG_GNRC_TCP_RTO_GRANULARITY -#define CONFIG_GNRC_TCP_RTO_GRANULARITY (10U * MS_PER_SEC) +#ifndef CONFIG_GNRC_TCP_RTO_GRANULARITY_MS +#define CONFIG_GNRC_TCP_RTO_GRANULARITY_MS (10U) #endif /** @@ -155,17 +155,17 @@ extern "C" { #endif /** - * @brief Lower bound for the duration between probes + * @brief Lower bound for the duration between probes in milliseconds. Default is 1 seconds */ -#ifndef CONFIG_GNRC_TCP_PROBE_LOWER_BOUND -#define CONFIG_GNRC_TCP_PROBE_LOWER_BOUND (1U * US_PER_SEC) +#ifndef CONFIG_GNRC_TCP_PROBE_LOWER_BOUND_MS +#define CONFIG_GNRC_TCP_PROBE_LOWER_BOUND_MS (1U * MS_PER_SEC) #endif /** - * @brief Upper bound for the duration between probes + * @brief Upper bound for the duration between probes in milliseconds. Default is 60 seconds */ -#ifndef CONFIG_GNRC_TCP_PROBE_UPPER_BOUND -#define CONFIG_GNRC_TCP_PROBE_UPPER_BOUND (60U * US_PER_SEC) +#ifndef CONFIG_GNRC_TCP_PROBE_UPPER_BOUND_MS +#define CONFIG_GNRC_TCP_PROBE_UPPER_BOUND_MS (60U * MS_PER_SEC) #endif /** diff --git a/sys/include/net/gnrc/tcp/tcb.h b/sys/include/net/gnrc/tcp/tcb.h index 7a3b2596e6..71e2356630 100644 --- a/sys/include/net/gnrc/tcp/tcb.h +++ b/sys/include/net/gnrc/tcp/tcb.h @@ -23,8 +23,9 @@ #include #include "kernel_types.h" #include "ringbuffer.h" -#include "xtimer.h" #include "mutex.h" +#include "evtimer_msg.h" +#include "evtimer_mbox.h" #include "msg.h" #include "mbox.h" #include "net/gnrc/pkt.h" @@ -67,11 +68,9 @@ typedef struct _transmission_control_block { int32_t srtt; /**< Smoothed round trip time */ int32_t rto; /**< Retransmission timeout duration */ uint8_t retries; /**< Number of retransmissions */ - xtimer_t timer_retransmit; /**< Retransmission timer */ - xtimer_t timer_misc; /**< General purpose timer */ - msg_t msg_retransmit; /**< Retransmission timer message */ - msg_t msg_misc; /**< General purpose timer message */ - gnrc_pktsnip_t *pkt_retransmit; /**< Pointer to packet in "retransmit queue" */ + evtimer_msg_event_t event_retransmit; /**< Retransmission event */ + evtimer_mbox_event_t event_misc; /**< General purpose event */ + gnrc_pktsnip_t *pkt_retransmit; /**< Pointer to packet in "retransmit queue" */ mbox_t *mbox; /**< TCB mbox for synchronization */ uint8_t *rcv_buf_raw; /**< Pointer to the receive buffer */ ringbuffer_t rcv_buf; /**< Receive buffer data structure */ diff --git a/sys/net/gnrc/transport_layer/tcp/Kconfig b/sys/net/gnrc/transport_layer/tcp/Kconfig index 9379662d94..15b899d7af 100644 --- a/sys/net/gnrc/transport_layer/tcp/Kconfig +++ b/sys/net/gnrc/transport_layer/tcp/Kconfig @@ -12,18 +12,18 @@ menuconfig KCONFIG_USEMODULE_GNRC_TCP if KCONFIG_USEMODULE_GNRC_TCP -config GNRC_TCP_CONNECTION_TIMEOUT_DURATION - int "Timeout duration for user calls in microseconds" - default 120000000 +config GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS + int "Timeout duration for user calls in milliseconds" + default 120000 help - Timeout duration for user calls. Default value is 120000000 microseconds + Timeout duration for user calls. Default value is 120000 milliseconds (2 minutes). -config GNRC_TCP_MSL - int "Maximum segment lifetime (MSL) in microseconds" - default 30000000 +config GNRC_TCP_MSL_MS + int "Maximum segment lifetime (MSL) in milliseconds" + default 30000 help - Maximum segment lifetime (MSL) in microseconds. Default value is 30 + Maximum segment lifetime (MSL) in milliseconds. Default value is 30 seconds. config GNRC_TCP_MSS @@ -59,29 +59,29 @@ config GNRC_TCP_RCV_BUFFERS int "Number of preallocated receive buffers" default 1 -config GNRC_TCP_RTO_LOWER_BOUND - int "Lower bound for RTO in microseconds" - default 1000000 +config GNRC_TCP_RTO_LOWER_BOUND_MS + int "Lower bound for RTO in milliseconds" + default 1000 help - Lower bound value for retransmission timeout (RTO) in microseconds. - Default value is 1000000 microseconds (1 second). Retransmission + Lower bound value for retransmission timeout (RTO) in milliseconds. + Default value is 1000 milliseconds (1 second). Retransmission timeout determines how long TCP waits for acknowledgment (ACK) of transmitted segment. Refer to RFC 6298 for more information. -config GNRC_TCP_RTO_UPPER_BOUND - int "Upper bound for RTO in microseconds" - default 60000000 +config GNRC_TCP_RTO_UPPER_BOUND_MS + int "Upper bound for RTO in milliseconds" + default 60000 help - Upper bound value for retransmission timeout (RTO) in microseconds. - Default value is 60000000 microseconds (60 seconds). Refer to RFC 6298 + Upper bound value for retransmission timeout (RTO) in milliseconds. + Default value is 60000 milliseconds (60 seconds). Refer to RFC 6298 for more information. -config GNRC_TCP_RTO_GRANULARITY - int "Clock granularity for RTO in microseconds" - default 10000 +config GNRC_TCP_RTO_GRANULARITY_MS + int "Clock granularity for RTO in milliseconds" + default 10 help Clock granularity for retransmission timeout (RTO) for TCP in - microseconds. Default value is 10000 microseconds (10 milliseconds). + milliseconds. Default value is 10 milliseconds. Refer to RFC 6298 for more information. config GNRC_TCP_RTO_A_DIV @@ -104,13 +104,21 @@ config GNRC_TCP_RTO_K int "K value for RTO calculation" default 4 -config GNRC_TCP_PROBE_LOWER_BOUND - int "Lower bound for the duration between probes in microseconds" - default 1000000 +config GNRC_TCP_PROBE_LOWER_BOUND_MS + int "Lower bound for the duration between probes in milliseconds" + default 1000 + help + Lower bound value for window probes in milliseconds. + Default value is 1000 milliseconds (1 second). + Refer to RFC 6298 for more information. -config GNRC_TCP_PROBE_UPPER_BOUND - int "Lower bound for the duration between probes in microseconds" - default 60000000 +config GNRC_TCP_PROBE_UPPER_BOUND_MS + int "Lower bound for the duration between probes in milliseconds" + default 60000 + help + Upper bound value for window probes in milliseconds. + Default value is 60000 milliseconds (60 seconds). Refer to RFC 6298 + for more information. config GNRC_TCP_MSG_QUEUE_SIZE_SIZE_EXP int "Message queue size for TCP API internal messaging (as exponent of 2^n)" diff --git a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c index f373c65e96..e1b4b0e1ff 100644 --- a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c +++ b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c @@ -21,6 +21,8 @@ #include #include +#include "evtimer.h" +#include "evtimer_mbox.h" #include "mbox.h" #include "net/af.h" #include "net/gnrc.h" @@ -41,19 +43,11 @@ #define TCP_MSG_QUEUE_SIZE (1 << CONFIG_GNRC_TCP_MSG_QUEUE_SIZE_EXP) -/** - * @brief Allocate memory for GNRC TCP thread stack. - */ -#if ENABLE_DEBUG -static char _stack[TCP_EVENTLOOP_STACK_SIZE + THREAD_EXTRA_STACKSIZE_PRINTF]; -#else -static char _stack[TCP_EVENTLOOP_STACK_SIZE]; -#endif /** - * @brief TCPs eventloop pid, declared externally. + * @brief Central MBOX evtimer used by gnrc_tcp */ -kernel_pid_t gnrc_tcp_pid = KERNEL_PID_UNDEF; +static evtimer_t _tcp_mbox_timer; /** * @brief Head of liked TCB list. @@ -65,40 +59,23 @@ gnrc_tcp_tcb_t *_list_tcb_head; */ mutex_t _list_tcb_lock; -/** - * @brief Helper struct, holding all argument data for_cb_mbox_put_msg. - */ -typedef struct _cb_arg { - uint32_t msg_type; /**< Message Type to Put into mbox behind mbox_ptr */ - mbox_t *mbox_ptr; /**< Pointer to mbox */ -} cb_arg_t; - -/** - * @brief Callback for xtimer, puts a message in a mbox. - * - * @param[in] arg Ptr to cb_arg_t. Must not be NULL or anything else. - */ -static void _cb_mbox_put_msg(void *arg) +static void _sched_mbox(evtimer_mbox_event_t *event, uint32_t offset, + uint16_t type, mbox_t *mbox) { - msg_t msg; - msg.type = ((cb_arg_t *) arg)->msg_type; - mbox_try_put(((cb_arg_t *) arg)->mbox_ptr, &msg); + event->event.offset = offset; + event->msg.type = type; + evtimer_add_mbox(&_tcp_mbox_timer, event, mbox); } -/** - * @brief Setup timer with a callback function. - * - * @param[in/out] timer Ptr to timer, which should be set. - * @param[in] duration Duration after @p timer expires. - * @param[in] cb Function to be called after @p duration. - * @param[in] arg Arguments for @p cb. - */ -static void _setup_timeout(xtimer_t *timer, const uint32_t duration, const xtimer_callback_t cb, - cb_arg_t *arg) +static void _sched_connection_timeout(evtimer_mbox_event_t *event, mbox_t *mbox) { - timer->callback = cb; - timer->arg = arg; - xtimer_set(timer, duration); + _sched_mbox(event, CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS, + MSG_TYPE_CONNECTION_TIMEOUT, mbox); +} + +static void _unsched_mbox(evtimer_mbox_event_t *event) +{ + evtimer_del(&_tcp_mbox_timer, (evtimer_event_t *)event); } /** @@ -124,7 +101,6 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *remote, msg_t msg; msg_t msg_queue[TCP_MSG_QUEUE_SIZE]; mbox_t mbox = MBOX_INIT(msg_queue, TCP_MSG_QUEUE_SIZE); - cb_arg_t connection_timeout_arg = {MSG_TYPE_CONNECTION_TIMEOUT, &mbox}; int ret = 0; /* Lock the TCB for this function call */ @@ -185,9 +161,8 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *remote, tcb->local_port = local_port; tcb->peer_port = remote->port; - /* Setup connection timeout: Put timeout message in TCBs mbox on expiration */ - _setup_timeout(&(tcb->timer_misc), CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, - _cb_mbox_put_msg, &connection_timeout_arg); + /* Setup connection timeout */ + _sched_connection_timeout(&tcb->event_misc, &mbox); } /* Call FSM with event: CALL_OPEN */ @@ -211,9 +186,8 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *remote, * send SYN+ACK we received upon entering SYN_RCVD is never acknowledged * by the peer. */ if ((tcb->state == FSM_STATE_SYN_RCVD) && (tcb->status & STATUS_PASSIVE)) { - _setup_timeout(&(tcb->timer_misc), - CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, _cb_mbox_put_msg, - &connection_timeout_arg); + _unsched_mbox(&tcb->event_misc); + _sched_connection_timeout(&tcb->event_misc, &mbox); } break; @@ -241,7 +215,7 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *remote, /* Cleanup */ _fsm_set_mbox(tcb, NULL); - xtimer_remove(&(tcb->timer_misc)); + _unsched_mbox(&tcb->event_misc); if (tcb->state == FSM_STATE_CLOSED && ret == 0) { ret = -ECONNREFUSED; } @@ -378,11 +352,6 @@ int gnrc_tcp_ep_from_str(gnrc_tcp_ep_t *ep, const char *str) int gnrc_tcp_init(void) { - /* Guard: Check if thread is already running */ - if (gnrc_tcp_pid != KERNEL_PID_UNDEF) { - return -1; - } - /* Initialize mutex for TCB list synchronization */ mutex_init(&(_list_tcb_lock)); @@ -390,10 +359,11 @@ int gnrc_tcp_init(void) _list_tcb_head = NULL; _rcvbuf_init(); + /* Initialize timers */ + evtimer_init_mbox(&_tcp_mbox_timer); + /* Start TCP processing thread */ - return thread_create(_stack, sizeof(_stack), TCP_EVENTLOOP_PRIO, - THREAD_CREATE_STACKTEST, _event_loop, NULL, - "gnrc_tcp"); + return _gnrc_tcp_event_loop_init(); } void gnrc_tcp_tcb_init(gnrc_tcp_tcb_t *tcb) @@ -460,7 +430,7 @@ int gnrc_tcp_open_passive(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *local) } ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, - const uint32_t timeout_duration_us) + const uint32_t timeout_duration_ms) { assert(tcb != NULL); assert(data != NULL); @@ -468,12 +438,9 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, msg_t msg; msg_t msg_queue[TCP_MSG_QUEUE_SIZE]; mbox_t mbox = MBOX_INIT(msg_queue, TCP_MSG_QUEUE_SIZE); - cb_arg_t connection_timeout_arg = {MSG_TYPE_CONNECTION_TIMEOUT, &mbox}; - xtimer_t user_timeout; - cb_arg_t user_timeout_arg = {MSG_TYPE_USER_SPEC_TIMEOUT, &mbox}; - xtimer_t probe_timeout; - cb_arg_t probe_timeout_arg = {MSG_TYPE_PROBE_TIMEOUT, &mbox}; - uint32_t probe_timeout_duration_us = 0; + evtimer_mbox_event_t event_user_timeout; + evtimer_mbox_event_t event_probe_timeout; + uint32_t probe_timeout_duration_ms = 0; ssize_t ret = 0; bool probing_mode = false; @@ -489,12 +456,12 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, /* Setup messaging */ _fsm_set_mbox(tcb, &mbox); - /* Setup connection timeout: Put timeout message in tcb's mbox on expiration */ - _setup_timeout(&(tcb->timer_misc), CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, - _cb_mbox_put_msg, &connection_timeout_arg); + /* Setup connection timeout */ + _sched_connection_timeout(&tcb->event_misc, &mbox); - if (timeout_duration_us > 0) { - _setup_timeout(&user_timeout, timeout_duration_us, _cb_mbox_put_msg, &user_timeout_arg); + if (timeout_duration_ms > 0) { + _sched_mbox(&event_user_timeout, timeout_duration_ms, + MSG_TYPE_USER_SPEC_TIMEOUT, &mbox); } /* Loop until something was sent and acked */ @@ -510,11 +477,12 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, /* If this is the first probe: Setup probing duration */ if (!probing_mode) { probing_mode = true; - probe_timeout_duration_us = tcb->rto; + probe_timeout_duration_ms = tcb->rto; } /* Setup probe timeout */ - _setup_timeout(&probe_timeout, probe_timeout_duration_us, _cb_mbox_put_msg, - &probe_timeout_arg); + _unsched_mbox(&event_probe_timeout); + _sched_mbox(&event_probe_timeout, probe_timeout_duration_ms, + MSG_TYPE_PROBE_TIMEOUT, &mbox); } /* Try to send data in case there nothing has been sent and we are not probing */ @@ -541,14 +509,14 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, DEBUG("gnrc_tcp.c : gnrc_tcp_send() : PROBE_TIMEOUT\n"); /* Send probe */ _fsm(tcb, FSM_EVENT_SEND_PROBE, NULL, NULL, 0); - probe_timeout_duration_us += probe_timeout_duration_us; + probe_timeout_duration_ms += probe_timeout_duration_ms; /* Boundary check for time interval between probes */ - if (probe_timeout_duration_us < CONFIG_GNRC_TCP_PROBE_LOWER_BOUND) { - probe_timeout_duration_us = CONFIG_GNRC_TCP_PROBE_LOWER_BOUND; + if (probe_timeout_duration_ms < CONFIG_GNRC_TCP_PROBE_LOWER_BOUND_MS) { + probe_timeout_duration_ms = CONFIG_GNRC_TCP_PROBE_LOWER_BOUND_MS; } - else if (probe_timeout_duration_us > CONFIG_GNRC_TCP_PROBE_UPPER_BOUND) { - probe_timeout_duration_us = CONFIG_GNRC_TCP_PROBE_UPPER_BOUND; + else if (probe_timeout_duration_ms > CONFIG_GNRC_TCP_PROBE_UPPER_BOUND_MS) { + probe_timeout_duration_ms = CONFIG_GNRC_TCP_PROBE_UPPER_BOUND_MS; } break; @@ -556,13 +524,13 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, DEBUG("gnrc_tcp.c : gnrc_tcp_send() : NOTIFY_USER\n"); /* Connection is alive: Reset Connection Timeout */ - _setup_timeout(&(tcb->timer_misc), CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, - _cb_mbox_put_msg, &connection_timeout_arg); + _unsched_mbox(&tcb->event_misc); + _sched_connection_timeout(&tcb->event_misc, &mbox); /* If the window re-opened and we are probing: Stop it */ if (tcb->snd_wnd > 0 && probing_mode) { probing_mode = false; - xtimer_remove(&probe_timeout); + _unsched_mbox(&event_probe_timeout); } break; @@ -573,15 +541,15 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len, /* Cleanup */ _fsm_set_mbox(tcb, NULL); - xtimer_remove(&(tcb->timer_misc)); - xtimer_remove(&probe_timeout); - xtimer_remove(&user_timeout); + _unsched_mbox(&tcb->event_misc); + _unsched_mbox(&event_probe_timeout); + _unsched_mbox(&event_user_timeout); mutex_unlock(&(tcb->function_lock)); return ret; } ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, - const uint32_t timeout_duration_us) + const uint32_t timeout_duration_ms) { assert(tcb != NULL); assert(data != NULL); @@ -589,9 +557,7 @@ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, msg_t msg; msg_t msg_queue[TCP_MSG_QUEUE_SIZE]; mbox_t mbox = MBOX_INIT(msg_queue, TCP_MSG_QUEUE_SIZE); - cb_arg_t connection_timeout_arg = {MSG_TYPE_CONNECTION_TIMEOUT, &mbox}; - xtimer_t user_timeout; - cb_arg_t user_timeout_arg = {MSG_TYPE_USER_SPEC_TIMEOUT, &mbox}; + evtimer_mbox_event_t event_user_timeout; ssize_t ret = 0; /* Lock the TCB for this function call */ @@ -612,8 +578,8 @@ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, return ret; } - /* If this call is non-blocking (timeout_duration_us == 0): Try to read data and return */ - if (timeout_duration_us == 0) { + /* If this call is non-blocking (timeout_duration_ms == 0): Try to read data and return */ + if (timeout_duration_ms == 0) { ret = _fsm(tcb, FSM_EVENT_CALL_RECV, NULL, data, max_len); if (ret == 0) { ret = -EAGAIN; @@ -625,10 +591,13 @@ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, /* Setup messaging */ _fsm_set_mbox(tcb, &mbox); - /* Setup connection timeout: Put timeout message in tcb's mbox on expiration */ - _setup_timeout(&(tcb->timer_misc), CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, - _cb_mbox_put_msg, &connection_timeout_arg); - _setup_timeout(&user_timeout, timeout_duration_us, _cb_mbox_put_msg, &user_timeout_arg); + /* Setup connection timeout */ + _sched_connection_timeout(&tcb->event_misc, &mbox); + + if (timeout_duration_ms > 0) { + _sched_mbox(&event_user_timeout, timeout_duration_ms, + MSG_TYPE_USER_SPEC_TIMEOUT, &mbox); + } /* Processing loop */ while (ret == 0) { @@ -674,8 +643,8 @@ ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, /* Cleanup */ _fsm_set_mbox(tcb, NULL); - xtimer_remove(&(tcb->timer_misc)); - xtimer_remove(&user_timeout); + _unsched_mbox(&tcb->event_misc); + _unsched_mbox(&event_user_timeout); mutex_unlock(&(tcb->function_lock)); return ret; } @@ -687,7 +656,6 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb) msg_t msg; msg_t msg_queue[TCP_MSG_QUEUE_SIZE]; mbox_t mbox = MBOX_INIT(msg_queue, TCP_MSG_QUEUE_SIZE); - cb_arg_t connection_timeout_arg = {MSG_TYPE_CONNECTION_TIMEOUT, &mbox}; /* Lock the TCB for this function call */ mutex_lock(&(tcb->function_lock)); @@ -701,9 +669,8 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb) /* Setup messaging */ _fsm_set_mbox(tcb, &mbox); - /* Setup connection timeout: Put timeout message in tcb's mbox on expiration */ - _setup_timeout(&(tcb->timer_misc), CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, - _cb_mbox_put_msg, &connection_timeout_arg); + /* Setup connection timeout */ + _sched_connection_timeout(&tcb->event_misc, &mbox); /* Start connection teardown sequence */ _fsm(tcb, FSM_EVENT_CALL_CLOSE, NULL, NULL, 0); @@ -728,7 +695,7 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb) /* Cleanup */ _fsm_set_mbox(tcb, NULL); - xtimer_remove(&(tcb->timer_misc)); + _unsched_mbox(&tcb->event_misc); mutex_unlock(&(tcb->function_lock)); } diff --git a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_eventloop.c b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_eventloop.c index 00b467e375..16c2934703 100644 --- a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_eventloop.c +++ b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_eventloop.c @@ -38,6 +38,39 @@ static msg_t _eventloop_msg_queue[TCP_EVENTLOOP_MSG_QUEUE_SIZE]; +/** + * @brief Allocate memory for GNRC TCP thread stack. + */ +#if ENABLE_DEBUG +static char _stack[TCP_EVENTLOOP_STACK_SIZE + THREAD_EXTRA_STACKSIZE_PRINTF]; +#else +static char _stack[TCP_EVENTLOOP_STACK_SIZE]; +#endif + +/** + * @brief Central evtimer for gnrc_tcp event loop + */ +static evtimer_t _tcp_msg_timer; + +/** + * @brief TCPs eventloop pid + */ +static kernel_pid_t _tcp_eventloop_pid = KERNEL_PID_UNDEF; + +void _gnrc_tcp_event_loop_sched(evtimer_msg_event_t *event, uint32_t offset, + uint16_t type, void *context) +{ + event->event.offset = offset; + event->msg.type = type; + event->msg.content.ptr = context; + evtimer_add_msg(&_tcp_msg_timer, event, _tcp_eventloop_pid); +} + +void _gnrc_tcp_event_loop_unsched(evtimer_msg_event_t *event) +{ + evtimer_del(&_tcp_msg_timer, (evtimer_event_t *)event); +} + /** * @brief Send function, pass packet down the network stack. * @@ -220,6 +253,9 @@ static int _receive(gnrc_pktsnip_t *pkt) mutex_unlock(&_list_tcb_lock); /* Call FSM with event RCVD_PKT if a fitting TCB was found */ + /* cppcheck-suppress knownConditionTrueFalse + * (reason: tcb can be NULL at runtime) + */ if (tcb != NULL) { _fsm(tcb, FSM_EVENT_RCVD_PKT, pkt, NULL, 0); } @@ -228,7 +264,7 @@ static int _receive(gnrc_pktsnip_t *pkt) DEBUG("gnrc_tcp_eventloop.c : _receive() : Can't find fitting tcb\n"); if ((ctl & MSK_RST) != MSK_RST) { _pkt_build_reset_from_pkt(&reset, pkt); - if (gnrc_netapi_send(gnrc_tcp_pid, reset) < 1) { + if (gnrc_netapi_send(_tcp_eventloop_pid, reset) < 1) { DEBUG("gnrc_tcp_eventloop.c : _receive() : unable to send reset packet\n"); gnrc_pktbuf_release(reset); } @@ -240,13 +276,13 @@ static int _receive(gnrc_pktsnip_t *pkt) return 0; } -void *_event_loop(__attribute__((unused)) void *arg) +static void *_event_loop(__attribute__((unused)) void *arg) { msg_t msg; msg_t reply; /* Store pid */ - gnrc_tcp_pid = thread_getpid(); + _tcp_eventloop_pid = thread_getpid(); /* Setup reply message */ reply.type = GNRC_NETAPI_MSG_TYPE_ACK; @@ -257,7 +293,7 @@ void *_event_loop(__attribute__((unused)) void *arg) /* Register GNRC TCPs handling thread in netreg */ gnrc_netreg_entry_t entry; - gnrc_netreg_entry_init_pid(&entry, GNRC_NETREG_DEMUX_CTX_ALL, gnrc_tcp_pid); + gnrc_netreg_entry_init_pid(&entry, GNRC_NETREG_DEMUX_CTX_ALL, _tcp_eventloop_pid); gnrc_netreg_register(GNRC_NETTYPE_TCP, &entry); /* dispatch NETAPI messages */ @@ -303,3 +339,18 @@ void *_event_loop(__attribute__((unused)) void *arg) /* Never reached */ return NULL; } + +int _gnrc_tcp_event_loop_init(void) +{ + /* Guard: Check if thread is already running */ + if (_tcp_eventloop_pid != KERNEL_PID_UNDEF) { + return -EEXIST; + } + + /* Initialize timers */ + evtimer_init_msg(&_tcp_msg_timer); + + return thread_create(_stack, sizeof(_stack), TCP_EVENTLOOP_PRIO, + THREAD_CREATE_STACKTEST, _event_loop, NULL, + "gnrc_tcp"); +} diff --git a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c index bc42707d77..7aef6701d8 100644 --- a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c +++ b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_fsm.c @@ -22,7 +22,10 @@ #include "random.h" #include "net/af.h" #include "net/gnrc.h" +#include "evtimer.h" +#include "evtimer_msg.h" #include "internal/common.h" +#include "internal/eventloop.h" #include "internal/pkt.h" #include "internal/option.h" #include "internal/rcvbuf.h" @@ -84,8 +87,8 @@ static uint16_t _get_random_local_port(void) static int _clear_retransmit(gnrc_tcp_tcb_t *tcb) { if (tcb->pkt_retransmit != NULL) { + _gnrc_tcp_event_loop_unsched(&tcb->event_retransmit); gnrc_pktbuf_release(tcb->pkt_retransmit); - xtimer_remove(&(tcb->timer_retransmit)); tcb->pkt_retransmit = NULL; } return 0; @@ -100,11 +103,9 @@ static int _clear_retransmit(gnrc_tcp_tcb_t *tcb) */ static int _restart_timewait_timer(gnrc_tcp_tcb_t *tcb) { - xtimer_remove(&tcb->timer_retransmit); - tcb->msg_retransmit.type = MSG_TYPE_TIMEWAIT; - tcb->msg_retransmit.content.ptr = (void *)tcb; - xtimer_set_msg(&(tcb->timer_retransmit), 2 * CONFIG_GNRC_TCP_MSL, &(tcb->msg_retransmit), - gnrc_tcp_pid); + _gnrc_tcp_event_loop_unsched(&tcb->event_retransmit); + _gnrc_tcp_event_loop_sched(&tcb->event_retransmit, 2 * CONFIG_GNRC_TCP_MSL_MS, + MSG_TYPE_TIMEWAIT, tcb); return 0; } @@ -306,7 +307,7 @@ static int _fsm_call_recv(gnrc_tcp_tcb_t *tcb, void *buf, size_t len) if (ringbuffer_get_free(&tcb->rcv_buf) >= CONFIG_GNRC_TCP_MSS) { tcb->rcv_wnd = ringbuffer_get_free(&(tcb->rcv_buf)); - /* Send ACK to anounce window update */ + /* Send ACK to announce window update */ gnrc_pktsnip_t *out_pkt = NULL; uint16_t seq_con = 0; _pkt_build(tcb, &out_pkt, &seq_con, MSK_ACK, tcb->snd_nxt, tcb->rcv_nxt, NULL, 0); diff --git a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_pkt.c b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_pkt.c index ef23a43d03..4c98094b50 100644 --- a/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_pkt.c +++ b/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_pkt.c @@ -20,9 +20,12 @@ #include #include #include "byteorder.h" +#include "evtimer.h" +#include "evtimer_msg.h" #include "net/inet_csum.h" #include "net/gnrc.h" #include "internal/common.h" +#include "internal/eventloop.h" #include "internal/option.h" #include "internal/pkt.h" @@ -271,14 +274,15 @@ int _pkt_send(gnrc_tcp_tcb_t *tcb, gnrc_pktsnip_t *out_pkt, const uint16_t seq_c if (!retransmit) { tcb->retries = 0; tcb->snd_nxt += seq_con; - tcb->rtt_start = xtimer_now().ticks32; + tcb->rtt_start = evtimer_now_msec(); } else { tcb->retries += 1; } /* Pass packet down the network stack */ - if (gnrc_netapi_send(gnrc_tcp_pid, out_pkt) < 1) { + if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_TCP, GNRC_NETREG_DEMUX_CTX_ALL, + out_pkt)) { DEBUG("gnrc_tcp_pkt.c : _pkt_send() : unable to send packet\n"); gnrc_pktbuf_release(out_pkt); } @@ -385,10 +389,11 @@ int _pkt_setup_retransmit(gnrc_tcp_tcb_t *tcb, gnrc_pktsnip_t *pkt, const bool r if (!retransmit) { /* If this is the first transmission: rto is 1 sec (Lower Bound) */ if (tcb->srtt == RTO_UNINITIALIZED || tcb->rtt_var == RTO_UNINITIALIZED) { - tcb->rto = CONFIG_GNRC_TCP_RTO_LOWER_BOUND; + tcb->rto = CONFIG_GNRC_TCP_RTO_LOWER_BOUND_MS; } else { - tcb->rto = tcb->srtt + _max(CONFIG_GNRC_TCP_RTO_GRANULARITY, CONFIG_GNRC_TCP_RTO_K * tcb->rtt_var); + tcb->rto = tcb->srtt + _max(CONFIG_GNRC_TCP_RTO_GRANULARITY_MS, + CONFIG_GNRC_TCP_RTO_K * tcb->rtt_var); } } else { @@ -404,17 +409,16 @@ int _pkt_setup_retransmit(gnrc_tcp_tcb_t *tcb, gnrc_pktsnip_t *pkt, const bool r } /* Perform boundary checks on current RTO before usage */ - if (tcb->rto < (int32_t) CONFIG_GNRC_TCP_RTO_LOWER_BOUND) { - tcb->rto = CONFIG_GNRC_TCP_RTO_LOWER_BOUND; + if (tcb->rto < (int32_t) CONFIG_GNRC_TCP_RTO_LOWER_BOUND_MS) { + tcb->rto = CONFIG_GNRC_TCP_RTO_LOWER_BOUND_MS; } - else if (tcb->rto > (int32_t) CONFIG_GNRC_TCP_RTO_UPPER_BOUND) { - tcb->rto = CONFIG_GNRC_TCP_RTO_UPPER_BOUND; + else if (tcb->rto > (int32_t) CONFIG_GNRC_TCP_RTO_UPPER_BOUND_MS) { + tcb->rto = CONFIG_GNRC_TCP_RTO_UPPER_BOUND_MS; } /* Setup retransmission timer, msg to TCP thread with ptr to TCB */ - tcb->msg_retransmit.type = MSG_TYPE_RETRANSMISSION; - tcb->msg_retransmit.content.ptr = (void *) tcb; - xtimer_set_msg(&tcb->timer_retransmit, tcb->rto, &tcb->msg_retransmit, gnrc_tcp_pid); + _gnrc_tcp_event_loop_sched(&tcb->event_retransmit, tcb->rto, + MSG_TYPE_RETRANSMISSION, tcb); return 0; } @@ -438,12 +442,12 @@ int _pkt_acknowledge(gnrc_tcp_tcb_t *tcb, const uint32_t ack) /* If segment can be acknowledged -> stop timer, release packet from pktbuf and update rto. */ if (LSS_32_BIT(seg, ack)) { - xtimer_remove(&(tcb->timer_retransmit)); + _gnrc_tcp_event_loop_unsched(&tcb->event_retransmit); gnrc_pktbuf_release(tcb->pkt_retransmit); tcb->pkt_retransmit = NULL; /* Measure round trip time */ - int32_t rtt = xtimer_now().ticks32 - tcb->rtt_start; + int32_t rtt = evtimer_now_msec() - tcb->rtt_start; /* Use time only if there was no timer overflow and no retransmission (Karns Algorithm) */ if (tcb->retries == 0 && rtt > 0) { diff --git a/sys/net/gnrc/transport_layer/tcp/internal/common.h b/sys/net/gnrc/transport_layer/tcp/internal/common.h index c8d0291fa3..da646954d1 100644 --- a/sys/net/gnrc/transport_layer/tcp/internal/common.h +++ b/sys/net/gnrc/transport_layer/tcp/internal/common.h @@ -25,6 +25,7 @@ #include "kernel_types.h" #include "thread.h" #include "mutex.h" +#include "evtimer.h" #include "net/gnrc/netapi.h" #include "net/gnrc/tcp/tcb.h" @@ -113,11 +114,6 @@ extern "C" { */ #define GET_OFFSET( x ) (((x) & MSK_OFFSET) >> 12) -/** - * @brief PID of GNRC TCP event handling thread - */ -extern kernel_pid_t gnrc_tcp_pid; - /** * @brief Head of linked TCB list. */ diff --git a/sys/net/gnrc/transport_layer/tcp/internal/eventloop.h b/sys/net/gnrc/transport_layer/tcp/internal/eventloop.h index e3c6bd9717..19dc5105a0 100644 --- a/sys/net/gnrc/transport_layer/tcp/internal/eventloop.h +++ b/sys/net/gnrc/transport_layer/tcp/internal/eventloop.h @@ -20,18 +20,43 @@ #ifndef EVENTLOOP_H #define EVENTLOOP_H +#include + +#include "evtimer_msg.h" + #ifdef __cplusplus extern "C" { #endif /** - * @brief GNRC TCPs main processing thread. + * @brief Starts GNRC TCP's main processing thread. * - * @param[in] arg Thread arguments (unused). - * - * @returns Never, its an endless loop + * @retval PID of processing thread on success + * @retval -EEXIST if processing thread was already started + * @retval see @ref thread_create() for more error cases. */ -void *_event_loop(__attribute__((unused)) void *arg); +int _gnrc_tcp_event_loop_init(void); + +/** + * @brief Schedule event to event loop + * + * @param[in] event The event to schedule + * @param[in] offset Offset in milliseconds when the event should be handled + * in the event loop + * @param[in] type Type of the message for the event + * @param[in] context Context of the event. + */ +void _gnrc_tcp_event_loop_sched(evtimer_msg_event_t *event, uint32_t offset, + uint16_t type, void *context); + +/** + * @brief Unschedule event to event loop + * + * Does nothing if @p event was not scheduled. + * + * @param[in] event The event to unschedule + */ +void _gnrc_tcp_event_loop_unsched(evtimer_msg_event_t *event); #ifdef __cplusplus } diff --git a/tests/gnrc_tcp/Makefile b/tests/gnrc_tcp/Makefile index bf13bf5151..c946fcdac0 100644 --- a/tests/gnrc_tcp/Makefile +++ b/tests/gnrc_tcp/Makefile @@ -5,8 +5,8 @@ BOARD ?= native TAP ?= tap0 # Shorten default TCP timeouts to speedup testing -MSL_US ?= 1000000 -TIMEOUT_US ?= 3000000 +MSL_MS ?= 1000 +TIMEOUT_MS ?= 3000 # This test depends on tap device setup (only allowed by root) # Suppress test execution to avoid CI errors @@ -45,12 +45,12 @@ ethos: include $(RIOTBASE)/Makefile.include # Set CONFIG_GNRC_TCP_MSL via CFLAGS if not being set via Kconfig -ifndef CONFIG_GNRC_TCP_MSL - CFLAGS += -DCONFIG_GNRC_TCP_MSL=$(MSL_US) +ifndef CONFIG_GNRC_TCP_MSL_MS + CFLAGS += -DCONFIG_GNRC_TCP_MSL_MS=$(MSL_MS) endif # Set CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION via CFLAGS if not being set # via Kconfig -ifndef CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION - CFLAGS += -DCONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION=$(TIMEOUT_US) +ifndef CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS + CFLAGS += -DCONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS=$(TIMEOUT_MS) endif