1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

gnrc_tcp: Replace xtimer with evtimer

This commit is contained in:
Simon Brummer 2020-07-12 08:22:16 +02:00
parent b5c51d244e
commit 132882df73
12 changed files with 256 additions and 206 deletions

View File

@ -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)))

View File

@ -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.

View File

@ -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
/**

View File

@ -23,8 +23,9 @@
#include <stdint.h>
#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 */

View File

@ -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)"

View File

@ -21,6 +21,8 @@
#include <string.h>
#include <utlist.h>
#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));
}

View File

@ -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");
}

View File

@ -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);

View File

@ -20,9 +20,12 @@
#include <utlist.h>
#include <errno.h>
#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) {

View File

@ -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.
*/

View File

@ -20,18 +20,43 @@
#ifndef EVENTLOOP_H
#define EVENTLOOP_H
#include <stdint.h>
#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
}

View File

@ -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