Skip to content

Commit

Permalink
gnrc_sock_tcp: integrate gnrc_tcp
Browse files Browse the repository at this point in the history
  • Loading branch information
brummer-simon committed Jul 14, 2021
1 parent 602384e commit 134180c
Show file tree
Hide file tree
Showing 12 changed files with 1,128 additions and 0 deletions.
3 changes: 3 additions & 0 deletions sys/net/gnrc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ endif
ifneq (,$(filter gnrc_sock_udp,$(USEMODULE)))
DIRS += sock/udp
endif
ifneq (,$(filter gnrc_sock_tcp,$(USEMODULE)))
DIRS += sock/tcp
endif
ifneq (,$(filter gnrc_udp,$(USEMODULE)))
DIRS += transport_layer/udp
endif
Expand Down
7 changes: 7 additions & 0 deletions sys/net/gnrc/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ ifneq (,$(filter gnrc_sock_udp,$(USEMODULE)))
USEMODULE += random # to generate random ports
endif

ifneq (,$(filter gnrc_sock_tcp,$(USEMODULE)))
USEMODULE += gnrc_tcp
endif

ifneq (,$(filter gnrc_sock,$(USEMODULE)))
USEMODULE += gnrc_netapi_mbox
USEMODULE += sock
Expand Down Expand Up @@ -396,6 +400,9 @@ ifneq (,$(filter gnrc,$(USEMODULE)))
ifneq (,$(filter sock_udp, $(USEMODULE)))
USEMODULE += gnrc_sock_udp
endif
ifneq (,$(filter sock_tcp, $(USEMODULE)))
USEMODULE += gnrc_sock_tcp
endif
endif

ifneq (,$(filter gnrc_pktbuf, $(USEMODULE)))
Expand Down
18 changes: 18 additions & 0 deletions sys/net/gnrc/sock/include/sock_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
#include "mbox.h"
#include "net/af.h"
#include "net/gnrc.h"
#include "net/gnrc/tcp.h"
#include "net/gnrc/netreg.h"
#ifdef SOCK_HAS_ASYNC
#include "net/sock/async/types.h"
#endif
#include "net/sock/ip.h"
#include "net/sock/udp.h"
#include "net/sock/tcp.h"

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -136,6 +138,22 @@ struct sock_udp {
uint16_t flags; /**< option flags */
};

/**
* @brief TCP sock type
* @internal
*/
struct sock_tcp {
gnrc_tcp_tcb_t tcb; /**< tcb */
};

/**
* @brief TCP queue sock type
* @internal
*/
struct sock_tcp_queue {
gnrc_tcp_tcb_queue_t tcb_queue; /**< tcb queue*/
};

#ifdef __cplusplus
}
#endif
Expand Down
3 changes: 3 additions & 0 deletions sys/net/gnrc/sock/tcp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE = gnrc_sock_tcp

include $(RIOTBASE)/Makefile.base
216 changes: 216 additions & 0 deletions sys/net/gnrc/sock/tcp/gnrc_sock_tcp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/*
* Copyright (C) 2021 Simon Brummer <[email protected]>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @{
*
* @file
* @brief GNRC implementation of @ref net_sock_tcp
*
* @author Simon Brummer <[email protected]>
*/

#include <assert.h>

#include "net/gnrc/tcp.h"
#include "net/sock/tcp.h"
#include "sock_types.h"

int sock_tcp_connect(sock_tcp_t *sock, const sock_tcp_ep_t *remote,
uint16_t local_port, uint16_t flags)
{
/* Asserts defined by API. */
assert(sock != NULL);
assert(remote != NULL);
assert(remote->port != 0);

/* Asserts to protect GNRC_TCP. Flags are not supported. */
assert(flags == 0);
assert(sizeof(sock_tcp_t) == sizeof(gnrc_tcp_tcb_t));
assert(sizeof(sock_tcp_ep_t) == sizeof(gnrc_tcp_ep_t));

/* NOTE: GNRC_TCP and GNRC_SOCK_TCP types must have the same memory representation. */
gnrc_tcp_tcb_t *tcb = (gnrc_tcp_tcb_t *) sock;
gnrc_tcp_ep_t *ep = (gnrc_tcp_ep_t *) remote;

/* Initialize given TCB and try to open a connection */
gnrc_tcp_tcb_init(tcb);

/* Forward call to gnrc_tcp_open. Return codes are identical except those that are
* not generated by gnrc_tcp_open: -ENETUNREACH and -EPERM */
return gnrc_tcp_open(tcb, ep, local_port);
}

int sock_tcp_listen(sock_tcp_queue_t *queue, const sock_tcp_ep_t *local,
sock_tcp_t *queue_array, unsigned queue_len, uint16_t flags)
{
/* Asserts defined by API. */
assert(queue != NULL);
assert(local != NULL);
assert(local->port != 0);
assert(queue_array != NULL);
assert(queue_len != 0);

/* Asserts to protect GNRC_TCP. Flags are not supported. */
assert(flags == 0);
assert(sizeof(sock_tcp_queue_t) == sizeof(gnrc_tcp_tcb_queue_t));
assert(sizeof(sock_tcp_t) == sizeof(gnrc_tcp_tcb_t));
assert(sizeof(sock_tcp_ep_t) == sizeof(gnrc_tcp_ep_t));

/* NOTE: GNRC_TCP and GNRC_SOCK_TCP types must have the same memory representation. */
gnrc_tcp_tcb_queue_t *tcb_queue = (gnrc_tcp_tcb_queue_t *) queue;
gnrc_tcp_tcb_t *tcbs = (gnrc_tcp_tcb_t *) queue_array;
gnrc_tcp_ep_t *ep = (gnrc_tcp_ep_t *) local;

/* Initialize given TCB queue, all given tcbs and forward call */
gnrc_tcp_tcb_queue_init(tcb_queue);
for (unsigned i = 0; i < queue_len; ++i) {
gnrc_tcp_tcb_init(&tcbs[i]);
}
return gnrc_tcp_listen(tcb_queue, tcbs, queue_len, ep);
}

void sock_tcp_disconnect(sock_tcp_t *sock)
{
/* Asserts defined by API. */
assert(sock != NULL);

/* Asserts to protect GNRC_TCP. */
assert(sizeof(sock_tcp_t) == sizeof(gnrc_tcp_tcb_t));

/* NOTE: GNRC_TCP and GNRC_SOCK_TCP types must have the same memory representation. */
gnrc_tcp_tcb_t *tcb = (gnrc_tcp_tcb_t *) sock;
gnrc_tcp_close(tcb);
}

void sock_tcp_stop_listen(sock_tcp_queue_t *queue)
{
/* Asserts defined by API. */
assert(queue != NULL);

/* Asserts to protect GNRC_TCP. */
assert(sizeof(sock_tcp_queue_t) == sizeof(gnrc_tcp_tcb_queue_t));

/* NOTE: GNRC_TCP and GNRC_SOCK_TCP types must have the same memory representation. */
gnrc_tcp_tcb_queue_t *tcb_queue = (gnrc_tcp_tcb_queue_t *) queue;
gnrc_tcp_stop_listen(tcb_queue);
}

int sock_tcp_get_local(sock_tcp_t *sock, sock_tcp_ep_t *ep)
{
/* Asserts defined by API. */
assert(sock != NULL);
assert(ep != NULL);

/* Asserts to protect GNRC_TCP. */
assert(sizeof(sock_tcp_t) == sizeof(gnrc_tcp_tcb_t));
assert(sizeof(sock_tcp_ep_t) == sizeof(gnrc_tcp_ep_t));

/* NOTE: GNRC_TCP and GNRC_SOCK_TCP types must have the same memory representation. */
gnrc_tcp_tcb_t *tcb = (gnrc_tcp_tcb_t *) sock;
gnrc_tcp_ep_t *local = (gnrc_tcp_ep_t *) ep;
return gnrc_tcp_get_local(tcb, local);
}

int sock_tcp_get_remote(sock_tcp_t *sock, sock_tcp_ep_t *ep)
{
/* Asserts defined by API. */
assert(sock != NULL);
assert(ep != NULL);

/* Asserts to protect GNRC_TCP. */
assert(sizeof(sock_tcp_t) == sizeof(gnrc_tcp_tcb_t));
assert(sizeof(sock_tcp_ep_t) == sizeof(gnrc_tcp_ep_t));

/* NOTE: GNRC_TCP and GNRC_SOCK_TCP types must have the same memory representation. */
gnrc_tcp_tcb_t *tcb = (gnrc_tcp_tcb_t *) sock;
gnrc_tcp_ep_t *remote = (gnrc_tcp_ep_t *) ep;
return gnrc_tcp_get_remote(tcb, remote);
}

int sock_tcp_queue_get_local(sock_tcp_queue_t *queue, sock_tcp_ep_t *ep)
{
/* Asserts defined by API. */
assert(queue != NULL);
assert(ep != NULL);

/* Asserts to protect GNRC_TCP. */
assert(sizeof(sock_tcp_queue_t) == sizeof(gnrc_tcp_tcb_queue_t));
assert(sizeof(sock_tcp_ep_t) == sizeof(gnrc_tcp_ep_t));

/* NOTE: GNRC_TCP and GNRC_SOCK_TCP types must have the same memory representation. */
gnrc_tcp_tcb_queue_t *tcb_queue = (gnrc_tcp_tcb_queue_t *) queue;
gnrc_tcp_ep_t *local = (gnrc_tcp_ep_t *) ep;
return gnrc_tcp_queue_get_local(tcb_queue, local);
}

int sock_tcp_accept(sock_tcp_queue_t *queue, sock_tcp_t **sock, uint32_t timeout)
{
/* Asserts defined by API. */
assert(queue != NULL);
assert(sock != NULL);

/* Asserts to protect GNRC_TCP. */
assert(sizeof(sock_tcp_queue_t) == sizeof(gnrc_tcp_tcb_queue_t));
assert(sizeof(sock_tcp_t) == sizeof(gnrc_tcp_tcb_t));

/* NOTE: GNRC_TCP and GNRC_SOCK_TCP types must have the same memory representation. */
gnrc_tcp_tcb_queue_t *tcb_queue = (gnrc_tcp_tcb_queue_t *) queue;
gnrc_tcp_tcb_t **tcb = (gnrc_tcp_tcb_t **) sock;

/* Map SOCK_NO_TIMEOUT to 0. 0 is used in GNRC_TCP for no timeout */
if (timeout == SOCK_NO_TIMEOUT) {
timeout = 0;
}

/* Forward call to gnrc_tcp_accept.
* NOTE: Errorcodes -ECONNABORTED, -EPERM are not returned by
* gnrc_tcp_accept. All other error codes share the same semantics. */
return gnrc_tcp_accept(tcb_queue, tcb, timeout);
}

ssize_t sock_tcp_read(sock_tcp_t *sock, void *data, size_t max_len, uint32_t timeout)
{
/* Asserts defined by API. */
assert(sock != NULL);
assert(data != NULL);
assert(max_len > 0);

/* Asserts to protect GNRC_TCP. */
assert(sizeof(sock_tcp_t) == sizeof(gnrc_tcp_tcb_t));

/* NOTE: GNRC_TCP and GNRC_SOCK_TCP types must have the same memory representation. */
gnrc_tcp_tcb_t *tcb = (gnrc_tcp_tcb_t *) sock;

/* Map SOCK_NO_TIMEOUT to 0. 0 is used in GNRC_TCP for no timeout */
if (timeout == SOCK_NO_TIMEOUT) {
timeout = 0;
}

/* Forward call to gnrc_tcp_recv: All error codes share the same semantics */
return gnrc_tcp_recv(tcb, data, max_len, timeout);
}

ssize_t sock_tcp_write(sock_tcp_t *sock, const void *data, size_t len)
{
/* Asserts defined by API. */
assert(sock != NULL);
assert(data != NULL);
assert(len > 0);

/* Asserts to protect GNRC_TCP. */
assert(sizeof(sock_tcp_t) == sizeof(gnrc_tcp_tcb_t));

/* NOTE: GNRC_TCP and GNRC_SOCK_TCP types must have the same memory representation. */
gnrc_tcp_tcb_t *tcb = (gnrc_tcp_tcb_t *) sock;

/* Forward call to gnrc_tcp_send.
* NOTE: gnrc_tcp_send offers a timeout. By setting it to 0, the call blocks
* until at least some data was transmitted. */
return gnrc_tcp_send(tcb, data, len, 0);
}
59 changes: 59 additions & 0 deletions tests/gnrc_sock_tcp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
include ../Makefile.tests_common

# Basic Configuration
BOARD ?= native
TAP ?= tap0

# Shorten default TCP timeouts to speedup testing
MSL_MS ?= 1000
TIMEOUT_MS ?= 3000

# This test depends on tap device setup (only allowed by root)
# Suppress test execution to avoid CI errors
TEST_ON_CI_BLACKLIST += all

ifeq (native,$(BOARD))
TERMFLAGS ?= $(TAP)
else
ETHOS_BAUDRATE ?= 115200
CFLAGS += -DETHOS_BAUDRATE=$(ETHOS_BAUDRATE)
TERMDEPS += ethos
TERMPROG ?= sudo $(RIOTTOOLS)/ethos/ethos
TERMFLAGS ?= $(TAP) $(PORT) $(ETHOS_BAUDRATE)
endif

USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc_ipv6_default
USEMODULE += gnrc_sock_tcp
USEMODULE += gnrc_pktbuf_cmd
USEMODULE += gnrc_netif_single # Only one interface used and it makes
# shell commands easier
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += od

# Export used tap device to environment
export TAPDEV = $(TAP)

.PHONY: ethos

ethos:
$(Q)env -u CC -u CFLAGS $(MAKE) -C $(RIOTTOOLS)/ethos

include $(RIOTBASE)/Makefile.include

# Set CONFIG_GNRC_TCP_MSL via CFLAGS if not being set via Kconfig
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_MS
CFLAGS += -DCONFIG_GNRC_TCP_CONNECTION_TIMEOUT_DURATION_MS=$(TIMEOUT_MS)
endif

# Set the shell echo configuration via CFLAGS if not being controlled via Kconfig
ifndef CONFIG_KCONFIG_USEMODULE_SHELL
CFLAGS += -DCONFIG_SHELL_NO_ECHO
endif
6 changes: 6 additions & 0 deletions tests/gnrc_sock_tcp/Makefile.board.dep
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Put board specific dependencies here
ifeq (native,$(BOARD))
USEMODULE += netdev_tap
else
USEMODULE += stdio_ethos
endif
Loading

0 comments on commit 134180c

Please sign in to comment.