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 += inet_csum
USEMODULE += random USEMODULE += random
USEMODULE += tcp USEMODULE += tcp
USEMODULE += xtimer USEMODULE += evtimer_mbox
USEMODULE += core_mbox
endif endif
ifneq (,$(filter gnrc_pktdump,$(USEMODULE))) ifneq (,$(filter gnrc_pktdump,$(USEMODULE)))

View File

@ -58,7 +58,7 @@ typedef struct {
* @param[in] addr Address for endpoint. * @param[in] addr Address for endpoint.
* @param[in] addr_size Size of @p addr. * @param[in] addr_size Size of @p addr.
* @param[in] port Port number for endpoint. * @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 0 on success.
* @return -EAFNOSUPPORT if @p address_family is not supported. * @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,out] tcb TCB holding the connection information.
* @param[in] data Pointer to the data that should be transmitted. * @param[in] data Pointer to the data that should be transmitted.
* @param[in] len Number of bytes 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 * @param[in] user_timeout_duration_ms If not zero and there was not data transmitted
* the function returns after user_timeout_duration_us. * the function returns after user_timeout_duration_ms.
* If zero, no timeout will be triggered. * If zero, no timeout will be triggered.
* *
* @return The number of successfully transmitted bytes. * @return The number of successfully transmitted bytes.
* @return -ENOTCONN if connection is not established. * @return -ENOTCONN if connection is not established.
* @return -ECONNRESET if connection was reset by the peer. * @return -ECONNRESET if connection was reset by the peer.
* @return -ECONNABORTED if the connection was aborted. * @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, 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. * @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. * should be copied into.
* @param[in] max_len Maximum amount to bytes that should be read * @param[in] max_len Maximum amount to bytes that should be read
* into @p data. * 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 * If zero and no data is available, the function
* returns immediately. If not zero the function * returns immediately. If not zero the function
* blocks until data is available or * 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 The number of bytes read into @p data.
* @return 0, if the connection is closing and no further data can be read. * @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 -EAGAIN if user_timeout_duration_us is zero and no data is available.
* @return -ECONNRESET if connection was reset by the peer. * @return -ECONNRESET if connection was reset by the peer.
* @return -ECONNABORTED if the connection was aborted. * @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, 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. * @brief Close a TCP connection.

View File

@ -48,22 +48,22 @@ extern "C" {
* RTO <- SRTT + max (G, K*RTTVAR) * RTO <- SRTT + max (G, K*RTTVAR)
* *
* where K is a constant, and G is clock granularity in seconds * 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 * 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 #ifndef CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS
#define CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION (120U * US_PER_SEC) #define CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS (120U * MS_PER_SEC)
#endif #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 #ifndef CONFIG_GNRC_TCP_MSL_MS
#define CONFIG_GNRC_TCP_MSL (30U * US_PER_SEC) #define CONFIG_GNRC_TCP_MSL_MS (30U * MS_PER_SEC)
#endif #endif
/** /**
@ -109,28 +109,28 @@ extern "C" {
#endif #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 * @note Retransmission Timeout (RTO) determines how long TCP waits for
* acknowledgment (ACK) of transmitted segment. If the acknowledgment * acknowledgment (ACK) of transmitted segment. If the acknowledgment
* isn't received within this time it is considered lost. * isn't received within this time it is considered lost.
*/ */
#ifndef CONFIG_GNRC_TCP_RTO_LOWER_BOUND #ifndef CONFIG_GNRC_TCP_RTO_LOWER_BOUND_MS
#define CONFIG_GNRC_TCP_RTO_LOWER_BOUND (1U * US_PER_SEC) #define CONFIG_GNRC_TCP_RTO_LOWER_BOUND_MS (1U * MS_PER_SEC)
#endif #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 #ifndef CONFIG_GNRC_TCP_RTO_UPPER_BOUND_MS
#define CONFIG_GNRC_TCP_RTO_UPPER_BOUND (60U * US_PER_SEC) #define CONFIG_GNRC_TCP_RTO_UPPER_BOUND_MS (60U * MS_PER_SEC)
#endif #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 #ifndef CONFIG_GNRC_TCP_RTO_GRANULARITY_MS
#define CONFIG_GNRC_TCP_RTO_GRANULARITY (10U * MS_PER_SEC) #define CONFIG_GNRC_TCP_RTO_GRANULARITY_MS (10U)
#endif #endif
/** /**
@ -155,17 +155,17 @@ extern "C" {
#endif #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 #ifndef CONFIG_GNRC_TCP_PROBE_LOWER_BOUND_MS
#define CONFIG_GNRC_TCP_PROBE_LOWER_BOUND (1U * US_PER_SEC) #define CONFIG_GNRC_TCP_PROBE_LOWER_BOUND_MS (1U * MS_PER_SEC)
#endif #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 #ifndef CONFIG_GNRC_TCP_PROBE_UPPER_BOUND_MS
#define CONFIG_GNRC_TCP_PROBE_UPPER_BOUND (60U * US_PER_SEC) #define CONFIG_GNRC_TCP_PROBE_UPPER_BOUND_MS (60U * MS_PER_SEC)
#endif #endif
/** /**

View File

@ -23,8 +23,9 @@
#include <stdint.h> #include <stdint.h>
#include "kernel_types.h" #include "kernel_types.h"
#include "ringbuffer.h" #include "ringbuffer.h"
#include "xtimer.h"
#include "mutex.h" #include "mutex.h"
#include "evtimer_msg.h"
#include "evtimer_mbox.h"
#include "msg.h" #include "msg.h"
#include "mbox.h" #include "mbox.h"
#include "net/gnrc/pkt.h" #include "net/gnrc/pkt.h"
@ -67,11 +68,9 @@ typedef struct _transmission_control_block {
int32_t srtt; /**< Smoothed round trip time */ int32_t srtt; /**< Smoothed round trip time */
int32_t rto; /**< Retransmission timeout duration */ int32_t rto; /**< Retransmission timeout duration */
uint8_t retries; /**< Number of retransmissions */ uint8_t retries; /**< Number of retransmissions */
xtimer_t timer_retransmit; /**< Retransmission timer */ evtimer_msg_event_t event_retransmit; /**< Retransmission event */
xtimer_t timer_misc; /**< General purpose timer */ evtimer_mbox_event_t event_misc; /**< General purpose event */
msg_t msg_retransmit; /**< Retransmission timer message */ gnrc_pktsnip_t *pkt_retransmit; /**< Pointer to packet in "retransmit queue" */
msg_t msg_misc; /**< General purpose timer message */
gnrc_pktsnip_t *pkt_retransmit; /**< Pointer to packet in "retransmit queue" */
mbox_t *mbox; /**< TCB mbox for synchronization */ mbox_t *mbox; /**< TCB mbox for synchronization */
uint8_t *rcv_buf_raw; /**< Pointer to the receive buffer */ uint8_t *rcv_buf_raw; /**< Pointer to the receive buffer */
ringbuffer_t rcv_buf; /**< Receive buffer data structure */ ringbuffer_t rcv_buf; /**< Receive buffer data structure */

View File

@ -12,18 +12,18 @@ menuconfig KCONFIG_USEMODULE_GNRC_TCP
if KCONFIG_USEMODULE_GNRC_TCP if KCONFIG_USEMODULE_GNRC_TCP
config GNRC_TCP_CONNECTION_TIMEOUT_DURATION config GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS
int "Timeout duration for user calls in microseconds" int "Timeout duration for user calls in milliseconds"
default 120000000 default 120000
help help
Timeout duration for user calls. Default value is 120000000 microseconds Timeout duration for user calls. Default value is 120000 milliseconds
(2 minutes). (2 minutes).
config GNRC_TCP_MSL config GNRC_TCP_MSL_MS
int "Maximum segment lifetime (MSL) in microseconds" int "Maximum segment lifetime (MSL) in milliseconds"
default 30000000 default 30000
help help
Maximum segment lifetime (MSL) in microseconds. Default value is 30 Maximum segment lifetime (MSL) in milliseconds. Default value is 30
seconds. seconds.
config GNRC_TCP_MSS config GNRC_TCP_MSS
@ -59,29 +59,29 @@ config GNRC_TCP_RCV_BUFFERS
int "Number of preallocated receive buffers" int "Number of preallocated receive buffers"
default 1 default 1
config GNRC_TCP_RTO_LOWER_BOUND config GNRC_TCP_RTO_LOWER_BOUND_MS
int "Lower bound for RTO in microseconds" int "Lower bound for RTO in milliseconds"
default 1000000 default 1000
help help
Lower bound value for retransmission timeout (RTO) in microseconds. Lower bound value for retransmission timeout (RTO) in milliseconds.
Default value is 1000000 microseconds (1 second). Retransmission Default value is 1000 milliseconds (1 second). Retransmission
timeout determines how long TCP waits for acknowledgment (ACK) of timeout determines how long TCP waits for acknowledgment (ACK) of
transmitted segment. Refer to RFC 6298 for more information. transmitted segment. Refer to RFC 6298 for more information.
config GNRC_TCP_RTO_UPPER_BOUND config GNRC_TCP_RTO_UPPER_BOUND_MS
int "Upper bound for RTO in microseconds" int "Upper bound for RTO in milliseconds"
default 60000000 default 60000
help help
Upper bound value for retransmission timeout (RTO) in microseconds. Upper bound value for retransmission timeout (RTO) in milliseconds.
Default value is 60000000 microseconds (60 seconds). Refer to RFC 6298 Default value is 60000 milliseconds (60 seconds). Refer to RFC 6298
for more information. for more information.
config GNRC_TCP_RTO_GRANULARITY config GNRC_TCP_RTO_GRANULARITY_MS
int "Clock granularity for RTO in microseconds" int "Clock granularity for RTO in milliseconds"
default 10000 default 10
help help
Clock granularity for retransmission timeout (RTO) for TCP in 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. Refer to RFC 6298 for more information.
config GNRC_TCP_RTO_A_DIV config GNRC_TCP_RTO_A_DIV
@ -104,13 +104,21 @@ config GNRC_TCP_RTO_K
int "K value for RTO calculation" int "K value for RTO calculation"
default 4 default 4
config GNRC_TCP_PROBE_LOWER_BOUND config GNRC_TCP_PROBE_LOWER_BOUND_MS
int "Lower bound for the duration between probes in microseconds" int "Lower bound for the duration between probes in milliseconds"
default 1000000 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 config GNRC_TCP_PROBE_UPPER_BOUND_MS
int "Lower bound for the duration between probes in microseconds" int "Lower bound for the duration between probes in milliseconds"
default 60000000 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 config GNRC_TCP_MSG_QUEUE_SIZE_SIZE_EXP
int "Message queue size for TCP API internal messaging (as exponent of 2^n)" int "Message queue size for TCP API internal messaging (as exponent of 2^n)"

View File

@ -21,6 +21,8 @@
#include <string.h> #include <string.h>
#include <utlist.h> #include <utlist.h>
#include "evtimer.h"
#include "evtimer_mbox.h"
#include "mbox.h" #include "mbox.h"
#include "net/af.h" #include "net/af.h"
#include "net/gnrc.h" #include "net/gnrc.h"
@ -41,19 +43,11 @@
#define TCP_MSG_QUEUE_SIZE (1 << CONFIG_GNRC_TCP_MSG_QUEUE_SIZE_EXP) #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. * @brief Head of liked TCB list.
@ -65,40 +59,23 @@ gnrc_tcp_tcb_t *_list_tcb_head;
*/ */
mutex_t _list_tcb_lock; mutex_t _list_tcb_lock;
/** static void _sched_mbox(evtimer_mbox_event_t *event, uint32_t offset,
* @brief Helper struct, holding all argument data for_cb_mbox_put_msg. uint16_t type, mbox_t *mbox)
*/
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)
{ {
msg_t msg; event->event.offset = offset;
msg.type = ((cb_arg_t *) arg)->msg_type; event->msg.type = type;
mbox_try_put(((cb_arg_t *) arg)->mbox_ptr, &msg); evtimer_add_mbox(&_tcp_mbox_timer, event, mbox);
} }
/** static void _sched_connection_timeout(evtimer_mbox_event_t *event, mbox_t *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)
{ {
timer->callback = cb; _sched_mbox(event, CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS,
timer->arg = arg; MSG_TYPE_CONNECTION_TIMEOUT, mbox);
xtimer_set(timer, duration); }
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;
msg_t msg_queue[TCP_MSG_QUEUE_SIZE]; msg_t msg_queue[TCP_MSG_QUEUE_SIZE];
mbox_t mbox = MBOX_INIT(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; int ret = 0;
/* Lock the TCB for this function call */ /* 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->local_port = local_port;
tcb->peer_port = remote->port; tcb->peer_port = remote->port;
/* Setup connection timeout: Put timeout message in TCBs mbox on expiration */ /* Setup connection timeout */
_setup_timeout(&(tcb->timer_misc), CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, _sched_connection_timeout(&tcb->event_misc, &mbox);
_cb_mbox_put_msg, &connection_timeout_arg);
} }
/* Call FSM with event: CALL_OPEN */ /* 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 * send SYN+ACK we received upon entering SYN_RCVD is never acknowledged
* by the peer. */ * by the peer. */
if ((tcb->state == FSM_STATE_SYN_RCVD) && (tcb->status & STATUS_PASSIVE)) { if ((tcb->state == FSM_STATE_SYN_RCVD) && (tcb->status & STATUS_PASSIVE)) {
_setup_timeout(&(tcb->timer_misc), _unsched_mbox(&tcb->event_misc);
CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, _cb_mbox_put_msg, _sched_connection_timeout(&tcb->event_misc, &mbox);
&connection_timeout_arg);
} }
break; break;
@ -241,7 +215,7 @@ static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *remote,
/* Cleanup */ /* Cleanup */
_fsm_set_mbox(tcb, NULL); _fsm_set_mbox(tcb, NULL);
xtimer_remove(&(tcb->timer_misc)); _unsched_mbox(&tcb->event_misc);
if (tcb->state == FSM_STATE_CLOSED && ret == 0) { if (tcb->state == FSM_STATE_CLOSED && ret == 0) {
ret = -ECONNREFUSED; 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) 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 */ /* Initialize mutex for TCB list synchronization */
mutex_init(&(_list_tcb_lock)); mutex_init(&(_list_tcb_lock));
@ -390,10 +359,11 @@ int gnrc_tcp_init(void)
_list_tcb_head = NULL; _list_tcb_head = NULL;
_rcvbuf_init(); _rcvbuf_init();
/* Initialize timers */
evtimer_init_mbox(&_tcp_mbox_timer);
/* Start TCP processing thread */ /* Start TCP processing thread */
return thread_create(_stack, sizeof(_stack), TCP_EVENTLOOP_PRIO, return _gnrc_tcp_event_loop_init();
THREAD_CREATE_STACKTEST, _event_loop, NULL,
"gnrc_tcp");
} }
void gnrc_tcp_tcb_init(gnrc_tcp_tcb_t *tcb) 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, 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(tcb != NULL);
assert(data != 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;
msg_t msg_queue[TCP_MSG_QUEUE_SIZE]; msg_t msg_queue[TCP_MSG_QUEUE_SIZE];
mbox_t mbox = MBOX_INIT(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}; evtimer_mbox_event_t event_user_timeout;
xtimer_t user_timeout; evtimer_mbox_event_t event_probe_timeout;
cb_arg_t user_timeout_arg = {MSG_TYPE_USER_SPEC_TIMEOUT, &mbox}; uint32_t probe_timeout_duration_ms = 0;
xtimer_t probe_timeout;
cb_arg_t probe_timeout_arg = {MSG_TYPE_PROBE_TIMEOUT, &mbox};
uint32_t probe_timeout_duration_us = 0;
ssize_t ret = 0; ssize_t ret = 0;
bool probing_mode = false; 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 */ /* Setup messaging */
_fsm_set_mbox(tcb, &mbox); _fsm_set_mbox(tcb, &mbox);
/* Setup connection timeout: Put timeout message in tcb's mbox on expiration */ /* Setup connection timeout */
_setup_timeout(&(tcb->timer_misc), CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, _sched_connection_timeout(&tcb->event_misc, &mbox);
_cb_mbox_put_msg, &connection_timeout_arg);
if (timeout_duration_us > 0) { if (timeout_duration_ms > 0) {
_setup_timeout(&user_timeout, timeout_duration_us, _cb_mbox_put_msg, &user_timeout_arg); _sched_mbox(&event_user_timeout, timeout_duration_ms,
MSG_TYPE_USER_SPEC_TIMEOUT, &mbox);
} }
/* Loop until something was sent and acked */ /* 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 this is the first probe: Setup probing duration */
if (!probing_mode) { if (!probing_mode) {
probing_mode = true; probing_mode = true;
probe_timeout_duration_us = tcb->rto; probe_timeout_duration_ms = tcb->rto;
} }
/* Setup probe timeout */ /* Setup probe timeout */
_setup_timeout(&probe_timeout, probe_timeout_duration_us, _cb_mbox_put_msg, _unsched_mbox(&event_probe_timeout);
&probe_timeout_arg); _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 */ /* 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"); DEBUG("gnrc_tcp.c : gnrc_tcp_send() : PROBE_TIMEOUT\n");
/* Send probe */ /* Send probe */
_fsm(tcb, FSM_EVENT_SEND_PROBE, NULL, NULL, 0); _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 */ /* Boundary check for time interval between probes */
if (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_us = CONFIG_GNRC_TCP_PROBE_LOWER_BOUND; probe_timeout_duration_ms = CONFIG_GNRC_TCP_PROBE_LOWER_BOUND_MS;
} }
else if (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_us = CONFIG_GNRC_TCP_PROBE_UPPER_BOUND; probe_timeout_duration_ms = CONFIG_GNRC_TCP_PROBE_UPPER_BOUND_MS;
} }
break; 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"); DEBUG("gnrc_tcp.c : gnrc_tcp_send() : NOTIFY_USER\n");
/* Connection is alive: Reset Connection Timeout */ /* Connection is alive: Reset Connection Timeout */
_setup_timeout(&(tcb->timer_misc), CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, _unsched_mbox(&tcb->event_misc);
_cb_mbox_put_msg, &connection_timeout_arg); _sched_connection_timeout(&tcb->event_misc, &mbox);
/* If the window re-opened and we are probing: Stop it */ /* If the window re-opened and we are probing: Stop it */
if (tcb->snd_wnd > 0 && probing_mode) { if (tcb->snd_wnd > 0 && probing_mode) {
probing_mode = false; probing_mode = false;
xtimer_remove(&probe_timeout); _unsched_mbox(&event_probe_timeout);
} }
break; break;
@ -573,15 +541,15 @@ ssize_t gnrc_tcp_send(gnrc_tcp_tcb_t *tcb, const void *data, const size_t len,
/* Cleanup */ /* Cleanup */
_fsm_set_mbox(tcb, NULL); _fsm_set_mbox(tcb, NULL);
xtimer_remove(&(tcb->timer_misc)); _unsched_mbox(&tcb->event_misc);
xtimer_remove(&probe_timeout); _unsched_mbox(&event_probe_timeout);
xtimer_remove(&user_timeout); _unsched_mbox(&event_user_timeout);
mutex_unlock(&(tcb->function_lock)); mutex_unlock(&(tcb->function_lock));
return ret; return ret;
} }
ssize_t gnrc_tcp_recv(gnrc_tcp_tcb_t *tcb, void *data, const size_t max_len, 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(tcb != NULL);
assert(data != 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;
msg_t msg_queue[TCP_MSG_QUEUE_SIZE]; msg_t msg_queue[TCP_MSG_QUEUE_SIZE];
mbox_t mbox = MBOX_INIT(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}; evtimer_mbox_event_t event_user_timeout;
xtimer_t user_timeout;
cb_arg_t user_timeout_arg = {MSG_TYPE_USER_SPEC_TIMEOUT, &mbox};
ssize_t ret = 0; ssize_t ret = 0;
/* Lock the TCB for this function call */ /* 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; return ret;
} }
/* If this call is non-blocking (timeout_duration_us == 0): Try to read data and return */ /* If this call is non-blocking (timeout_duration_ms == 0): Try to read data and return */
if (timeout_duration_us == 0) { if (timeout_duration_ms == 0) {
ret = _fsm(tcb, FSM_EVENT_CALL_RECV, NULL, data, max_len); ret = _fsm(tcb, FSM_EVENT_CALL_RECV, NULL, data, max_len);
if (ret == 0) { if (ret == 0) {
ret = -EAGAIN; 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 */ /* Setup messaging */
_fsm_set_mbox(tcb, &mbox); _fsm_set_mbox(tcb, &mbox);
/* Setup connection timeout: Put timeout message in tcb's mbox on expiration */ /* Setup connection timeout */
_setup_timeout(&(tcb->timer_misc), CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, _sched_connection_timeout(&tcb->event_misc, &mbox);
_cb_mbox_put_msg, &connection_timeout_arg);
_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);
}
/* Processing loop */ /* Processing loop */
while (ret == 0) { 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 */ /* Cleanup */
_fsm_set_mbox(tcb, NULL); _fsm_set_mbox(tcb, NULL);
xtimer_remove(&(tcb->timer_misc)); _unsched_mbox(&tcb->event_misc);
xtimer_remove(&user_timeout); _unsched_mbox(&event_user_timeout);
mutex_unlock(&(tcb->function_lock)); mutex_unlock(&(tcb->function_lock));
return ret; return ret;
} }
@ -687,7 +656,6 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb)
msg_t msg; msg_t msg;
msg_t msg_queue[TCP_MSG_QUEUE_SIZE]; msg_t msg_queue[TCP_MSG_QUEUE_SIZE];
mbox_t mbox = MBOX_INIT(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 */ /* Lock the TCB for this function call */
mutex_lock(&(tcb->function_lock)); mutex_lock(&(tcb->function_lock));
@ -701,9 +669,8 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb)
/* Setup messaging */ /* Setup messaging */
_fsm_set_mbox(tcb, &mbox); _fsm_set_mbox(tcb, &mbox);
/* Setup connection timeout: Put timeout message in tcb's mbox on expiration */ /* Setup connection timeout */
_setup_timeout(&(tcb->timer_misc), CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION, _sched_connection_timeout(&tcb->event_misc, &mbox);
_cb_mbox_put_msg, &connection_timeout_arg);
/* Start connection teardown sequence */ /* Start connection teardown sequence */
_fsm(tcb, FSM_EVENT_CALL_CLOSE, NULL, NULL, 0); _fsm(tcb, FSM_EVENT_CALL_CLOSE, NULL, NULL, 0);
@ -728,7 +695,7 @@ void gnrc_tcp_close(gnrc_tcp_tcb_t *tcb)
/* Cleanup */ /* Cleanup */
_fsm_set_mbox(tcb, NULL); _fsm_set_mbox(tcb, NULL);
xtimer_remove(&(tcb->timer_misc)); _unsched_mbox(&tcb->event_misc);
mutex_unlock(&(tcb->function_lock)); mutex_unlock(&(tcb->function_lock));
} }

View File

@ -38,6 +38,39 @@
static msg_t _eventloop_msg_queue[TCP_EVENTLOOP_MSG_QUEUE_SIZE]; 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. * @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); mutex_unlock(&_list_tcb_lock);
/* Call FSM with event RCVD_PKT if a fitting TCB was found */ /* 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) { if (tcb != NULL) {
_fsm(tcb, FSM_EVENT_RCVD_PKT, pkt, NULL, 0); _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"); DEBUG("gnrc_tcp_eventloop.c : _receive() : Can't find fitting tcb\n");
if ((ctl & MSK_RST) != MSK_RST) { if ((ctl & MSK_RST) != MSK_RST) {
_pkt_build_reset_from_pkt(&reset, pkt); _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"); DEBUG("gnrc_tcp_eventloop.c : _receive() : unable to send reset packet\n");
gnrc_pktbuf_release(reset); gnrc_pktbuf_release(reset);
} }
@ -240,13 +276,13 @@ static int _receive(gnrc_pktsnip_t *pkt)
return 0; return 0;
} }
void *_event_loop(__attribute__((unused)) void *arg) static void *_event_loop(__attribute__((unused)) void *arg)
{ {
msg_t msg; msg_t msg;
msg_t reply; msg_t reply;
/* Store pid */ /* Store pid */
gnrc_tcp_pid = thread_getpid(); _tcp_eventloop_pid = thread_getpid();
/* Setup reply message */ /* Setup reply message */
reply.type = GNRC_NETAPI_MSG_TYPE_ACK; 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 */ /* Register GNRC TCPs handling thread in netreg */
gnrc_netreg_entry_t entry; 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); gnrc_netreg_register(GNRC_NETTYPE_TCP, &entry);
/* dispatch NETAPI messages */ /* dispatch NETAPI messages */
@ -303,3 +339,18 @@ void *_event_loop(__attribute__((unused)) void *arg)
/* Never reached */ /* Never reached */
return NULL; 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 "random.h"
#include "net/af.h" #include "net/af.h"
#include "net/gnrc.h" #include "net/gnrc.h"
#include "evtimer.h"
#include "evtimer_msg.h"
#include "internal/common.h" #include "internal/common.h"
#include "internal/eventloop.h"
#include "internal/pkt.h" #include "internal/pkt.h"
#include "internal/option.h" #include "internal/option.h"
#include "internal/rcvbuf.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) static int _clear_retransmit(gnrc_tcp_tcb_t *tcb)
{ {
if (tcb->pkt_retransmit != NULL) { if (tcb->pkt_retransmit != NULL) {
_gnrc_tcp_event_loop_unsched(&tcb->event_retransmit);
gnrc_pktbuf_release(tcb->pkt_retransmit); gnrc_pktbuf_release(tcb->pkt_retransmit);
xtimer_remove(&(tcb->timer_retransmit));
tcb->pkt_retransmit = NULL; tcb->pkt_retransmit = NULL;
} }
return 0; 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) static int _restart_timewait_timer(gnrc_tcp_tcb_t *tcb)
{ {
xtimer_remove(&tcb->timer_retransmit); _gnrc_tcp_event_loop_unsched(&tcb->event_retransmit);
tcb->msg_retransmit.type = MSG_TYPE_TIMEWAIT; _gnrc_tcp_event_loop_sched(&tcb->event_retransmit, 2 * CONFIG_GNRC_TCP_MSL_MS,
tcb->msg_retransmit.content.ptr = (void *)tcb; MSG_TYPE_TIMEWAIT, tcb);
xtimer_set_msg(&(tcb->timer_retransmit), 2 * CONFIG_GNRC_TCP_MSL, &(tcb->msg_retransmit),
gnrc_tcp_pid);
return 0; 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) { if (ringbuffer_get_free(&tcb->rcv_buf) >= CONFIG_GNRC_TCP_MSS) {
tcb->rcv_wnd = ringbuffer_get_free(&(tcb->rcv_buf)); 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; gnrc_pktsnip_t *out_pkt = NULL;
uint16_t seq_con = 0; uint16_t seq_con = 0;
_pkt_build(tcb, &out_pkt, &seq_con, MSK_ACK, tcb->snd_nxt, tcb->rcv_nxt, NULL, 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 <utlist.h>
#include <errno.h> #include <errno.h>
#include "byteorder.h" #include "byteorder.h"
#include "evtimer.h"
#include "evtimer_msg.h"
#include "net/inet_csum.h" #include "net/inet_csum.h"
#include "net/gnrc.h" #include "net/gnrc.h"
#include "internal/common.h" #include "internal/common.h"
#include "internal/eventloop.h"
#include "internal/option.h" #include "internal/option.h"
#include "internal/pkt.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) { if (!retransmit) {
tcb->retries = 0; tcb->retries = 0;
tcb->snd_nxt += seq_con; tcb->snd_nxt += seq_con;
tcb->rtt_start = xtimer_now().ticks32; tcb->rtt_start = evtimer_now_msec();
} }
else { else {
tcb->retries += 1; tcb->retries += 1;
} }
/* Pass packet down the network stack */ /* 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"); DEBUG("gnrc_tcp_pkt.c : _pkt_send() : unable to send packet\n");
gnrc_pktbuf_release(out_pkt); 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 (!retransmit) {
/* If this is the first transmission: rto is 1 sec (Lower Bound) */ /* If this is the first transmission: rto is 1 sec (Lower Bound) */
if (tcb->srtt == RTO_UNINITIALIZED || tcb->rtt_var == RTO_UNINITIALIZED) { 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 { 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 { 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 */ /* Perform boundary checks on current RTO before usage */
if (tcb->rto < (int32_t) 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; tcb->rto = CONFIG_GNRC_TCP_RTO_LOWER_BOUND_MS;
} }
else if (tcb->rto > (int32_t) 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; tcb->rto = CONFIG_GNRC_TCP_RTO_UPPER_BOUND_MS;
} }
/* Setup retransmission timer, msg to TCP thread with ptr to TCB */ /* Setup retransmission timer, msg to TCP thread with ptr to TCB */
tcb->msg_retransmit.type = MSG_TYPE_RETRANSMISSION; _gnrc_tcp_event_loop_sched(&tcb->event_retransmit, tcb->rto,
tcb->msg_retransmit.content.ptr = (void *) tcb; MSG_TYPE_RETRANSMISSION, tcb);
xtimer_set_msg(&tcb->timer_retransmit, tcb->rto, &tcb->msg_retransmit, gnrc_tcp_pid);
return 0; 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 segment can be acknowledged -> stop timer, release packet from pktbuf and update rto. */
if (LSS_32_BIT(seg, ack)) { 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); gnrc_pktbuf_release(tcb->pkt_retransmit);
tcb->pkt_retransmit = NULL; tcb->pkt_retransmit = NULL;
/* Measure round trip time */ /* 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) */ /* Use time only if there was no timer overflow and no retransmission (Karns Algorithm) */
if (tcb->retries == 0 && rtt > 0) { if (tcb->retries == 0 && rtt > 0) {

View File

@ -25,6 +25,7 @@
#include "kernel_types.h" #include "kernel_types.h"
#include "thread.h" #include "thread.h"
#include "mutex.h" #include "mutex.h"
#include "evtimer.h"
#include "net/gnrc/netapi.h" #include "net/gnrc/netapi.h"
#include "net/gnrc/tcp/tcb.h" #include "net/gnrc/tcp/tcb.h"
@ -113,11 +114,6 @@ extern "C" {
*/ */
#define GET_OFFSET( x ) (((x) & MSK_OFFSET) >> 12) #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. * @brief Head of linked TCB list.
*/ */

View File

@ -20,18 +20,43 @@
#ifndef EVENTLOOP_H #ifndef EVENTLOOP_H
#define EVENTLOOP_H #define EVENTLOOP_H
#include <stdint.h>
#include "evtimer_msg.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/** /**
* @brief GNRC TCPs main processing thread. * @brief Starts GNRC TCP's main processing thread.
* *
* @param[in] arg Thread arguments (unused). * @retval PID of processing thread on success
* * @retval -EEXIST if processing thread was already started
* @returns Never, its an endless loop * @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 #ifdef __cplusplus
} }

View File

@ -5,8 +5,8 @@ BOARD ?= native
TAP ?= tap0 TAP ?= tap0
# Shorten default TCP timeouts to speedup testing # Shorten default TCP timeouts to speedup testing
MSL_US ?= 1000000 MSL_MS ?= 1000
TIMEOUT_US ?= 3000000 TIMEOUT_MS ?= 3000
# This test depends on tap device setup (only allowed by root) # This test depends on tap device setup (only allowed by root)
# Suppress test execution to avoid CI errors # Suppress test execution to avoid CI errors
@ -45,12 +45,12 @@ ethos:
include $(RIOTBASE)/Makefile.include include $(RIOTBASE)/Makefile.include
# Set CONFIG_GNRC_TCP_MSL via CFLAGS if not being set via Kconfig # Set CONFIG_GNRC_TCP_MSL via CFLAGS if not being set via Kconfig
ifndef CONFIG_GNRC_TCP_MSL ifndef CONFIG_GNRC_TCP_MSL_MS
CFLAGS += -DCONFIG_GNRC_TCP_MSL=$(MSL_US) CFLAGS += -DCONFIG_GNRC_TCP_MSL_MS=$(MSL_MS)
endif endif
# Set CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION via CFLAGS if not being set # Set CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION via CFLAGS if not being set
# via Kconfig # via Kconfig
ifndef CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION ifndef CONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS
CFLAGS += -DCONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION=$(TIMEOUT_US) CFLAGS += -DCONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS=$(TIMEOUT_MS)
endif endif