Merge pull request #4744 from brummer-simon/devel-gnrc_tcp
gnrc_tcp: initial implementationpr/spi.typo
commit
7f7329ea71
@ -0,0 +1,43 @@
|
||||
# name of your application
|
||||
APPLICATION = gnrc_tcp_cli
|
||||
|
||||
# If no BOARD is found in the environment, use this default:
|
||||
BOARD ?= native
|
||||
PORT ?= tap1
|
||||
|
||||
TCP_TARGET_ADDR ?= fe80::5c38:e9ff:fe76:6195
|
||||
TCP_TARGET_PORT ?= 80
|
||||
TCP_TEST_CYCLES ?= 10
|
||||
|
||||
# Mark Boards with insufficient memory
|
||||
BOARD_INSUFFICIENT_MEMORY := airfy-beacon arduino-duemilanove arduino-mega2560\
|
||||
arduino-uno calliope-mini chronos microbit sb-430\
|
||||
sb-430h nrf51dongle nrf6310 nucleo-f030 nucleo-f042\
|
||||
nucleo32-f042 nucleo-f070 nucleo-f072 nucleo32-f303\
|
||||
nucleo-f334 pca10000 pca10005 stm32f0discovery\
|
||||
telosb weio wsn430-v1_3b wsn430-v1_4\
|
||||
yunjia-nrf51822 z1 msb-430 msb-430h
|
||||
|
||||
# This has to be the absolute path to the RIOT base directory:
|
||||
RIOTBASE ?= $(CURDIR)/../..
|
||||
|
||||
# Target Address, Target Port and number of Test Cycles
|
||||
CFLAGS += -DTARGET_ADDR=\"$(TCP_TARGET_ADDR)\"
|
||||
CFLAGS += -DTARGET_PORT=$(TCP_TARGET_PORT)
|
||||
CFLAGS += -DCYCLES=$(TCP_TEST_CYCLES)
|
||||
|
||||
# Comment this out to disable code in RIOT that does safety checking
|
||||
# which is not needed in a production environment but helps in the
|
||||
# development process:
|
||||
#CFLAGS += -DDEVELHELP
|
||||
|
||||
# Change this to 0 show compiler invocation lines by default:
|
||||
QUIET ?= 1
|
||||
|
||||
# Modules to include
|
||||
USEMODULE += gnrc_netdev_default
|
||||
USEMODULE += auto_init_gnrc_netif
|
||||
USEMODULE += gnrc_ipv6_default
|
||||
USEMODULE += gnrc_tcp
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Simon Brummer
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "net/af.h"
|
||||
#include "random.h"
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#include "net/gnrc/tcp.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/* Number of possible parallel connections */
|
||||
#ifndef CONNS
|
||||
#define CONNS 1
|
||||
#endif
|
||||
|
||||
/* Amount of data to transmit */
|
||||
#ifndef NBYTE
|
||||
#define NBYTE (2048)
|
||||
#endif
|
||||
|
||||
/* Test Pattern used by Client Application */
|
||||
#ifndef TEST_PATERN_CLI
|
||||
#define TEST_PATERN_CLI (0xF0)
|
||||
#endif
|
||||
|
||||
/* Test Pattern used by Server Application */
|
||||
#ifndef TEST_PATERN_SRV
|
||||
#define TEST_PATERN_SRV (0xA7)
|
||||
#endif
|
||||
|
||||
uint8_t bufs[CONNS][NBYTE];
|
||||
uint8_t stacks[CONNS][THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF];
|
||||
|
||||
void *cli_thread(void *arg);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("\nStarting Client Threads. TARGET_ADDR=%s, TARGET_PORT=%d, ", TARGET_ADDR, TARGET_PORT);
|
||||
printf("CONNS=%d, NBYTE=%d, CYCLES=%d\n\n", CONNS, NBYTE, CYCLES );
|
||||
|
||||
/* Start Connection Handling Threads */
|
||||
for (int i = 0; i < CONNS; i += 1) {
|
||||
thread_create((char *)stacks[i], sizeof(stacks[i]), THREAD_PRIORITY_MAIN, 0, cli_thread,
|
||||
(void *)i, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *cli_thread(void *arg)
|
||||
{
|
||||
/* Test Program variables */
|
||||
int tid = (int) arg;
|
||||
uint32_t cycles = 0;
|
||||
uint32_t cycles_ok = 0;
|
||||
uint32_t failed_payload_verifications = 0;
|
||||
|
||||
/* Transmission Control Block */
|
||||
gnrc_tcp_tcb_t tcb;
|
||||
|
||||
/* Target Peer Address Information */
|
||||
ipv6_addr_t target_addr;
|
||||
uint16_t target_port;
|
||||
|
||||
/* Initialize Target Information */
|
||||
ipv6_addr_from_str(&target_addr, TARGET_ADDR);
|
||||
target_port = TARGET_PORT;
|
||||
|
||||
printf("Client running: TID=%d\n", tid);
|
||||
while (cycles < CYCLES) {
|
||||
/* Initialize tcb struct */
|
||||
gnrc_tcp_tcb_init(&tcb);
|
||||
|
||||
/* Connect to Peer */
|
||||
int ret = gnrc_tcp_open_active(&tcb, AF_INET6, (uint8_t *) &target_addr, target_port, 0);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
DEBUG("TID=%d : gnrc_tcp_open_active() : 0 : ok\n", tid);
|
||||
break;
|
||||
|
||||
case -EISCONN:
|
||||
printf("TID=%d : gnrc_tcp_open_active() : -EISCONN\n", tid);
|
||||
return 0;
|
||||
|
||||
case -EINVAL:
|
||||
printf("TID=%d : gnrc_tcp_open_active() : -EINVAL\n", tid);
|
||||
return 0;
|
||||
|
||||
case -EAFNOSUPPORT:
|
||||
printf("TID=%d : gnrc_tcp_open_active() : -EAFNOSUPPORT\n", tid);
|
||||
return 0;
|
||||
|
||||
case -EADDRINUSE:
|
||||
printf("TID=%d : gnrc_tcp_open_active() : -EADDRINUSE\n", tid);
|
||||
return 0;
|
||||
|
||||
case -ECONNREFUSED:
|
||||
printf("TID=%d : gnrc_tcp_open_active() : -ECONNREFUSED : retry after 10sec\n",
|
||||
tid);
|
||||
xtimer_sleep(10);
|
||||
continue;
|
||||
|
||||
case -ENOMEM:
|
||||
printf("TID=%d : gnrc_tcp_open_active() : -ENOMEM\n", tid);
|
||||
return 0;
|
||||
|
||||
case -ETIMEDOUT:
|
||||
printf("TID=%d : gnrc_tcp_open_active() : -ETIMEDOUT : retry after 10sec\n",
|
||||
tid);
|
||||
xtimer_sleep(10);
|
||||
continue;
|
||||
|
||||
default:
|
||||
printf("TID=%d : gnrc_tcp_open_active() : %d\n", tid, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fill Buffer with a test pattern */
|
||||
for (size_t i=0; i < sizeof(bufs[tid]); ++i){
|
||||
bufs[tid][i] = TEST_PATERN_CLI;
|
||||
}
|
||||
|
||||
/* Send Data, stop if errors were found */
|
||||
for (size_t sent = 0; sent < sizeof(bufs[tid]) && ret >= 0; sent += ret) {
|
||||
ret = gnrc_tcp_send(&tcb, bufs[tid] + sent, sizeof(bufs[tid]) - sent, 0);
|
||||
switch (ret) {
|
||||
case -ENOTCONN:
|
||||
printf("TID=%d : gnrc_tcp_send() : -ENOTCONN\n", tid);
|
||||
break;
|
||||
|
||||
case -ECONNABORTED:
|
||||
printf("TID=%d : gnrc_tcp_send() : -ECONNABORTED\n", tid);
|
||||
break;
|
||||
|
||||
case -ETIMEDOUT:
|
||||
printf("TID=%d : gnrc_tcp_send() : -ETIMEDOUT\n", tid);
|
||||
break;
|
||||
|
||||
case -ECONNRESET:
|
||||
printf("TID=%d : gnrc_tcp_send() : -ECONNRESET\n", tid);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ret >= 0) {
|
||||
DEBUG("TID=%d : gnrc_tcp_send() : %d Bytes sent\n", tid, ret);
|
||||
}
|
||||
else {
|
||||
printf("TID=%d : gnrc_tcp_send() : %d\n", tid, ret);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Receive Data, stop if errors were found */
|
||||
for (size_t rcvd = 0; rcvd < sizeof(bufs[tid]) && ret >= 0; rcvd += ret) {
|
||||
ret = gnrc_tcp_recv(&tcb, (void *)(bufs[tid] + rcvd), sizeof(bufs[tid]) - rcvd,
|
||||
GNRC_TCP_CONNECTION_TIMEOUT_DURATION);
|
||||
switch (ret) {
|
||||
case -ENOTCONN:
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : -ENOTCONN\n", tid);
|
||||
break;
|
||||
|
||||
case -EAGAIN:
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : -EAGAIN : retry after 10sec\n", tid);
|
||||
ret = 0;
|
||||
xtimer_sleep(10);
|
||||
break;
|
||||
|
||||
case -ECONNABORTED:
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : -ECONNABORTED\n", tid);
|
||||
break;
|
||||
|
||||
case -ECONNRESET:
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : -ECONNRESET\n", tid);
|
||||
break;
|
||||
|
||||
case -ETIMEDOUT:
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : -ETIMEDOUT\n", tid);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ret >= 0) {
|
||||
DEBUG("TID=%d : gnrc_tcp_rcvd() : %d Bytes read.\n", tid, ret);
|
||||
}
|
||||
else {
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : %d\n", tid, ret);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If there was no error: Check received pattern */
|
||||
for (size_t i=0; i < sizeof(bufs[tid]); ++i) {
|
||||
if (bufs[tid][i] != TEST_PATERN_SRV) {
|
||||
printf("TID=%d : Payload verfication failed\n", tid);
|
||||
failed_payload_verifications += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close Connection */
|
||||
gnrc_tcp_close(&tcb);
|
||||
|
||||
/* Gather Data */
|
||||
cycles += 1;
|
||||
if(ret >= 0) {
|
||||
cycles_ok += 1;
|
||||
}
|
||||
printf("TID=%d : %"PRIi32" test cycles completed. %"PRIi32" ok, %"PRIi32" faulty",
|
||||
tid, cycles, cycles_ok, cycles - cycles_ok);
|
||||
printf(", %"PRIi32" failed payload verifications\n", failed_payload_verifications);
|
||||
}
|
||||
printf("client thread terminating: TID=%d\n", tid);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
# name of your application
|
||||
APPLICATION = gnrc_tcp_srv
|
||||
|
||||
# If no BOARD is found in the environment, use this default:
|
||||
BOARD ?= native
|
||||
PORT ?= tap0
|
||||
|
||||
TCP_LOCAL_PORT ?= 80
|
||||
|
||||
# Mark Boards with insufficient memory
|
||||
BOARD_INSUFFICIENT_MEMORY := airfy-beacon arduino-duemilanove arduino-mega2560\
|
||||
arduino-uno calliope-mini chronos microbit sb-430\
|
||||
sb-430h nrf51dongle nrf6310 nucleo-f030 nucleo-f042\
|
||||
nucleo32-f042 nucleo-f070 nucleo-f072 nucleo32-f303\
|
||||
nucleo-f334 pca10000 pca10005 stm32f0discovery\
|
||||
telosb weio wsn430-v1_3b wsn430-v1_4\
|
||||
yunjia-nrf51822 z1 msb-430 msb-430h
|
||||
|
||||
# This has to be the absolute path to the RIOT base directory:
|
||||
RIOTBASE ?= $(CURDIR)/../..
|
||||
|
||||
# Specify local Port to open
|
||||
CFLAGS += -DLOCAL_PORT=$(TCP_LOCAL_PORT)
|
||||
|
||||
# Comment this out to disable code in RIOT that does safety checking
|
||||
# which is not needed in a production environment but helps in the
|
||||
# development process:
|
||||
#CFLAGS += -DDEVELHELP
|
||||
|
||||
# Change this to 0 show compiler invocation lines by default:
|
||||
QUIET ?= 1
|
||||
|
||||
# Modules to include
|
||||
USEMODULE += gnrc_netdev_default
|
||||
USEMODULE += auto_init_gnrc_netif
|
||||
USEMODULE += gnrc_ipv6_default
|
||||
USEMODULE += gnrc_tcp
|
||||
|
||||
# include this for printing IP addresses
|
||||
USEMODULE += shell_commands
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Simon Brummer
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "thread.h"
|
||||
#include "net/af.h"
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#include "net/gnrc/tcp.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/* Number of possible parallel connections */
|
||||
#ifndef CONNS
|
||||
#define CONNS 1
|
||||
#endif
|
||||
|
||||
/* Amount of data to transmit */
|
||||
#ifndef NBYTE
|
||||
#define NBYTE (2048)
|
||||
#endif
|
||||
|
||||
/* Test Pattern used by Client Application */
|
||||
#ifndef TEST_PATERN_CLI
|
||||
#define TEST_PATERN_CLI (0xF0)
|
||||
#endif
|
||||
|
||||
/* Test Pattern used by Server Application */
|
||||
#ifndef TEST_PATERN_SRV
|
||||
#define TEST_PATERN_SRV (0xA7)
|
||||
#endif
|
||||
|
||||
uint8_t bufs[CONNS][NBYTE];
|
||||
uint8_t stacks[CONNS][THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF];
|
||||
|
||||
/* ifconfig shell command */
|
||||
extern int _netif_config(int argc, char **argv);
|
||||
|
||||
/* Server Thread */
|
||||
void *srv_thread(void *arg);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
/* Print all configured addresses of the server */
|
||||
printf("\nStarting server: LOCAL_PORT=%d, CONNS=%d, NBYTE=%d\n\n", LOCAL_PORT, CONNS, NBYTE);
|
||||
printf("Printing Servers Network Configuration:\n");
|
||||
_netif_config(0, NULL);
|
||||
|
||||
/* Start Threads to handle each connection */
|
||||
for (int i = 0; i < CONNS; i += 1) {
|
||||
thread_create((char *)stacks[i], sizeof(stacks[i]), THREAD_PRIORITY_MAIN, 0, srv_thread,
|
||||
(void *)i, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *srv_thread(void *arg)
|
||||
{
|
||||
int tid = (int)arg;
|
||||
uint32_t cycles = 0;
|
||||
uint32_t cycles_ok = 0;
|
||||
uint32_t failed_payload_verifications = 0;
|
||||
|
||||
/* Transmission control block */
|
||||
gnrc_tcp_tcb_t tcb;
|
||||
|
||||
/* Connection handling code */
|
||||
printf("Server running: TID=%d\n", tid);
|
||||
while (1) {
|
||||
/* Initialize tcb struct */
|
||||
gnrc_tcp_tcb_init(&tcb);
|
||||
|
||||
/* Connect to Peer */
|
||||
int ret = gnrc_tcp_open_passive(&tcb, AF_INET6, NULL, LOCAL_PORT);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
DEBUG("TID=%d : gnrc_tcp_open_passive() : 0 : ok\n", tid);
|
||||
break;
|
||||
|
||||
case -EISCONN:
|
||||
printf("TID=%d : gnrc_tcp_open_passive() : -EISCONN\n", tid);
|
||||
return 0;
|
||||
|
||||
case -EINVAL:
|
||||
printf("TID=%d : gnrc_tcp_open_passive() : -EINVAL\n", tid);
|
||||
return 0;
|
||||
|
||||
case -EAFNOSUPPORT:
|
||||
printf("TID=%d : gnrc_tcp_open_passive() : -EAFNOSUPPORT\n", tid);
|
||||
return 0;
|
||||
|
||||
case -ENOMEM:
|
||||
printf("TID=%d : gnrc_tcp_open_passive() : -ENOMEM\n", tid);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
printf("TID=%d : gnrc_tcp_open_passive() : %d\n", tid, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Receive Data, stop if errors were found */
|
||||
for (size_t rcvd = 0; rcvd < sizeof(bufs[tid]) && ret >= 0; rcvd += ret) {
|
||||
ret = gnrc_tcp_recv(&tcb, (void *)(bufs[tid] + rcvd), sizeof(bufs[tid]) - rcvd,
|
||||
GNRC_TCP_CONNECTION_TIMEOUT_DURATION);
|
||||
switch (ret) {
|
||||
case -ENOTCONN:
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : -ENOTCONN\n", tid);
|
||||
break;
|
||||
|
||||
case -EAGAIN:
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : -EAGAIN : retry after 10sec\n", tid);
|
||||
ret = 0;
|
||||
xtimer_sleep(10);
|
||||
break;
|
||||
|
||||
case -ECONNABORTED:
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : -ECONNABORTED\n", tid);
|
||||
break;
|
||||
|
||||
case -ECONNRESET:
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : -ECONNRESET\n", tid);
|
||||
break;
|
||||
|
||||
case -ETIMEDOUT:
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : -ETIMEDOUT\n", tid);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ret >= 0) {
|
||||
DEBUG("TID=%d : gnrc_tcp_rcvd() : %d Bytes read\n", tid, ret);
|
||||
}
|
||||
else {
|
||||
printf("TID=%d : gnrc_tcp_rcvd() : %d\n", tid, ret);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check received pattern */
|
||||
for (size_t i=0; i < sizeof(bufs[tid]); ++i) {
|
||||
if (bufs[tid][i] != TEST_PATERN_CLI) {
|
||||
printf("TID=%d : Payload verfication failed\n", tid);
|
||||
failed_payload_verifications += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill Buffer with a test pattern */
|
||||
for (size_t i=0; i < sizeof(bufs[tid]); ++i) {
|
||||
bufs[tid][i] = TEST_PATERN_SRV;
|
||||
}
|
||||
|
||||
/* Send Data, stop if errors were found */
|
||||
for (size_t sent = 0; sent < sizeof(bufs[tid]) && ret >= 0; sent += ret) {
|
||||
ret = gnrc_tcp_send(&tcb, bufs[tid] + sent, sizeof(bufs[tid]) - sent, 0);
|
||||
switch (ret) {
|
||||
case -ENOTCONN:
|
||||
printf("TID=%d : gnrc_tcp_send() : -ENOTCONN\n", tid);
|
||||
break;
|
||||
|
||||
case -ECONNABORTED:
|
||||
printf("TID=%d : gnrc_tcp_send() : -ECONNABORTED\n", tid);
|
||||
break;
|
||||
|
||||
case -ETIMEDOUT:
|
||||
printf("TID=%d : gnrc_tcp_send() : -ETIMEDOUT\n", tid);
|
||||
break;
|
||||
|
||||
case -ECONNRESET:
|
||||
printf("TID=%d : gnrc_tcp_send() : -ECONNRESET\n", tid);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ret >= 0) {
|
||||
DEBUG("TID=%d : gnrc_tcp_send() : %d Bytes sent.\n", tid, ret);
|
||||
}
|
||||
else {
|
||||
printf("TID=%d : gnrc_tcp_send() : %d\n", tid, ret);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Close Connection */
|
||||
gnrc_tcp_close(&tcb);
|
||||
|
||||
/* Gather Data */
|
||||
cycles += 1;
|
||||
if(ret >= 0) {
|
||||
cycles_ok += 1;
|
||||
}
|
||||
printf("TID=%d : %"PRIi32" test cycles completed. %"PRIi32" ok, %"PRIi32" faulty",
|
||||
tid, cycles, cycles_ok, cycles - cycles_ok);
|
||||
printf(", %"PRIi32" failed payload verifications\n", failed_payload_verifications);
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Simon Brummer
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_tcp TCP
|
||||
* @ingroup net_gnrc
|
||||
* @brief RIOT's tcp implementation for the gnrc stack
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief TCP interface definition
|
||||
*
|
||||
* @author Simon Brummer <simon.brummer@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#ifndef GNRC_TCP_H_
|
||||
#define GNRC_TCP_H_
|
||||
|
||||
#include "net/gnrc/netapi.h"
|
||||
#include "net/gnrc/nettype.h"
|
||||
#include "net/gnrc/tcp/hdr.h"
|
||||
#include "net/gnrc/tcp/tcb.h"
|
||||
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Port unspecified.
|
||||
*
|
||||
* @note PORT 0 is reserved, according to rfc 1700(https://www.ietf.org/rfc/rfc1700.txt)
|
||||
*/
|
||||
#define GNRC_TCP_PORT_UNSPEC 0
|
||||
|
||||
/**
|
||||
* @brief Head of conn linked list.
|
||||
*/
|
||||
extern gnrc_tcp_tcb_t *_list_gnrc_tcp_tcb_head;
|
||||
|
||||
/**
|
||||
* @brief Mutex to protect linked list.
|
||||
*/
|
||||
extern mutex_t _list_gnrc_tcp_tcb_lock;
|
||||
|
||||
/**
|
||||
* @brief Initialize and start TCP
|
||||
*
|
||||
* @return PID of TCP thread on success
|
||||
* @return -1 if thread is already running.
|
||||
* @return -EINVAL, if priority is greater than or equal SCHED_PRIO_LEVELS
|
||||
* @return -EOVERFLOW, if there are too many threads running.
|
||||
*/
|
||||
int gnrc_tcp_init(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize Transmission Control Block (tcb)
|
||||
* @pre tcb must not be NULL.
|
||||
*
|
||||
* @param[in,out] tcb Transmission that should be initialized.
|
||||
*/
|
||||
void gnrc_tcp_tcb_init(gnrc_tcp_tcb_t* tcb);
|
||||
|
||||
/**
|
||||
* @brief Opens a connection actively.
|
||||
*
|
||||
* @pre gnrc_tcp_tcb_init() must have been successfully called.
|
||||
* @pre tcb must not be NULL
|
||||
* @pre target_addr must not be NULL.
|
||||
* @pre target_port must not be 0.
|
||||
*
|
||||
* @note Blocks until a connection has been established or an error occured.
|
||||
*
|
||||
* @param[in,out] tcb This connections Transmission control block.
|
||||
* @param[in] address_family Address Family of @p target_addr.
|
||||
* @param[in] target_addr Pointer to target address.
|
||||
* @param[in] target_port Targets port number.
|
||||
* @param[in] local_port If zero or GNRC_TCP_PORT_UNSPEC, the connections
|
||||
* source port is randomly choosen. If local_port is non-zero
|
||||
* the local_port is used as source port.
|
||||
*
|
||||
* @return Zero on success.
|
||||
* @return -EAFNOSUPPORT if @p address_family is not supported.
|
||||
* @return -EINVAL if @p address_family is not the same the address_family use by the tcb.
|
||||
* @return -EISCONN if transmission control block is already in use.
|
||||
* @return -ENOMEM if the receive buffer for the tcb could not be allocated.
|
||||
* Increase "GNRC_TCP_RCV_BUFFERS".
|
||||
* @return -EADDRINUSE if @p local_port is already used by another connection.
|
||||
* @return -ETIMEDOUT if the connection could not be opened.
|
||||
* @return -ECONNREFUSED if the connection was resetted by the peer.
|
||||
*/
|
||||
int gnrc_tcp_open_active(gnrc_tcp_tcb_t *tcb, const uint8_t address_family,
|
||||
const uint8_t *target_addr, const uint16_t target_port,
|
||||
const uint16_t local_port);
|
||||
|
||||
/**
|
||||
* @brief Opens a connection passively, by waiting for an incomming request.
|
||||
*
|
||||
* @pre gnrc_tcp_tcb_init() must have been successfully called.
|
||||
* @pre tcb must not be NULL.
|
||||
* @pre if local_addr is not NULL, local_addr must be assigned to a network interface.
|
||||
* @pre if local_port is not zero.
|
||||
*
|
||||
* @note Blocks until a connection has been established (incomming connection request
|
||||
* to @p local_port) or an error occured.
|
||||
*
|
||||
* @param[in,out] tcb This connections Transmission control block.
|
||||
* @param[in] address_family Address Family of @p local_addr.
|
||||
* If local_addr == NULL, address_family is ignored.
|
||||
* @param[in] local_addr If not NULL the connection is bound to the address in @p local_addr.
|
||||
* If NULL a connection request to every local ip address is valid.
|
||||
* @param[in] local_port Portnumber that should used for incomming connection requests.
|
||||
*
|
||||
* @return Zero on success
|
||||
* @return -EAFNOSUPPORT if local_addr != NULL and @p address_family is not supported.
|
||||
* @return -EINVAL if @p address_family is not the same the address_family use by the tcb.
|
||||
* @return -EISCONN if transmission control block is already in use.
|
||||
* @return -ENOMEM if the receive buffer for the tcb could not be allocated.
|
||||
* Increase "GNRC_TCP_RCV_BUFFERS".
|
||||
*/
|
||||
int gnrc_tcp_open_passive(gnrc_tcp_tcb_t *tcb, const uint8_t address_family,
|
||||
const uint8_t *local_addr, const uint16_t local_port);
|
||||
|
||||
/**
|
||||
* @brief Transmit Data to Peer.
|
||||
*
|
||||
* @pre gnrc_tcp_tcb_init() must have been successfully called.
|
||||
* @pre tcb must not be NULL.
|
||||
* @pre data must not be NULL.
|
||||
*
|
||||
* @note Blocks until up to @p len bytes were transmitted or an error occured.
|
||||
*
|
||||
* @param[in,out] tcb This connections Transmission control block.
|
||||
* @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 were not data transmitted
|
||||
* successfully, the function call returns after
|
||||
* user_timeout_duration_us. If zero not timeout will be
|
||||
* triggered.
|
||||
*
|
||||
* @return On success, the number of successfully transmitted bytes.
|
||||
* @return -ENOTCONN if connection is not established.
|
||||
* @return -ECONNRESET if connection was resetted by the peer.
|
||||
* @return -ECONNABORTED if the connection was aborted.
|
||||
* @return -ETIMEDOUT if @p user_timeout_duration_us 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);
|
||||
|
||||
/**
|
||||
* @brief Receive Data from the Peer.
|
||||
*
|
||||
* @pre gnrc_tcp_tcb_init() must have been successfully called.
|
||||
* @pre tcb must not be NULL.
|
||||
* @pre data must not be NULL.
|
||||
*
|
||||
* @note Function blocks if user_timeout_duration_us is not zero.
|
||||
*
|
||||
* @param[in,out] tcb This connections Transmission control block.
|
||||
* @param[out] data Pointer to the buffer where the received data
|
||||
* should be copied into.
|
||||
* @param[in] max_len Maximum amount to bytes that should be reeived.
|
||||
* Should not exceed size of @p data.
|
||||
* @param[in] user_timeout_duration_us Timeout for receive in microseconds. If zero and no data
|
||||
* is available, the function returns immediately. If not
|
||||
* zero the function block until data is available or
|
||||
* user_timeout_duration_us microseconds have passed.
|
||||
*
|
||||
* @return On success, the number of bytes read into @p data.
|
||||
* @return -ENOTCONN if connection is not established.
|
||||
* @return -EAGAIN if user_timeout_duration_us is zero and no data is available.
|
||||
* @return -ECONNRESET if connection was resetted by the peer.
|
||||
* @return -ECONNABORTED if the connection was aborted.
|
||||
* @return -ETIMEDOUT if @p user_timeout_duration_us 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);
|
||||
|
||||
/**
|
||||
* @brief Close a tcp connection.
|
||||
*
|
||||
* @pre gnrc_tcp_tcb_init() must have been successfully called.
|
||||
* @pre tcb must not be NULL.
|
||||
*
|
||||
* @param[in,out] tcb This connections Transmission control block.
|
||||
*
|
||||
* @return Zero on success.
|
||||
*/
|
||||
int gnrc_tcp_close(gnrc_tcp_tcb_t *tcb);
|
||||
|
||||
/**
|
||||
* @brief Set checksum calculated from tcp and network-layer header in tcp-header.
|
||||
*
|
||||
* @param[in] hdr ng_pktsnip that contains tcp header.
|
||||
* @param[in] pseudo_hdr ng_pktsnip that contains networklayer header.
|
||||
*
|
||||
* @return zero on succeed.
|
||||
* @return -EFAULT if hdr or pseudo_hdr were NULL
|
||||
* @return -EBADMSG if hdr is not of type GNRC_NETTYPE_TCP
|
||||
* @return -ENOENT if pseudo_hdr protocol is unsupported.
|
||||
*/
|
||||
int gnrc_tcp_calc_csum(const gnrc_pktsnip_t *hdr, const gnrc_pktsnip_t *pseudo_hdr);
|
||||
|
||||
/**
|
||||
* @brief Adds a tcp header to a given payload. Be carefull, leads to huge headers.
|
||||
* Allocates all option bytes
|
||||
*
|
||||
* @param[in] payload payload that follows the tcp header
|
||||
* @param[in] src Source port in host byte order
|
||||
* @param[in] dst Destination port in host byte order
|
||||
*
|
||||
* @return NULL, if paket buffer is full
|
||||
* @return Not NULL on success
|
||||
*/
|
||||
gnrc_pktsnip_t *gnrc_tcp_hdr_build(gnrc_pktsnip_t *payload, uint16_t src, uint16_t dst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GNRC_TCP_H_ */
|
||||
/** @} */
|
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Simon Brummer
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_tcp TCP
|
||||
* @ingroup net_gnrc
|
||||
* @brief RIOT's tcp implementation for the gnrc stack
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief TCP configuration, includes buffersizes, timeout durations
|
||||
*
|
||||
* @author Simon Brummer <simon.brummer@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#ifndef GNRC_TCP_CONFIG_H_
|
||||
#define GNRC_TCP_CONFIG_H_
|
||||
|
||||
#include "timex.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Status Flags for TCP
|
||||
* @{
|
||||
*/
|
||||
#define GNRC_TCP_STATUS_PASSIVE (1 << 0)
|
||||
#define GNRC_TCP_STATUS_ACCEPTED (1 << 1)
|
||||
#define GNRC_TCP_STATUS_ALLOW_ANY_ADDR (1 << 2)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Timeout Duration for user calls. Default 2 minutes
|
||||
*/
|
||||
#ifndef GNRC_TCP_CONNECTION_TIMEOUT_DURATION
|
||||
#define GNRC_TCP_CONNECTION_TIMEOUT_DURATION (120 * US_PER_SEC)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Maximum Segment Lifetime. Default 30 secounds
|
||||
*/
|
||||
#ifndef GNRC_TCP_MSL
|
||||
#define GNRC_TCP_MSL (30 * US_PER_SEC)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Message queue size for the TCP handling thread
|
||||
*/
|
||||
#ifndef GNRC_TCP_MSG_QUEUE_SIZE
|
||||
#define GNRC_TCP_MSG_QUEUE_SIZE (8U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Priority of the tcp handling thread, must be lower than the applications prio.
|
||||
*/
|
||||
#ifndef GNRC_TCP_PRIO
|
||||
#define GNRC_TCP_PRIO (THREAD_PRIORITY_MAIN - 2U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default stack size for the TCP handling thread
|
||||
*/
|
||||
#ifndef GNRC_TCP_STACK_SIZE
|
||||
#define GNRC_TCP_STACK_SIZE (THREAD_STACKSIZE_DEFAULT)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Maximum Segement Size
|
||||
*/
|
||||
#ifndef GNRC_TCP_MSS
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
#define GNRC_TCP_MSS (1220U) /**< If IPv6 is used. Get MSS = 1280 - IPv6-Hdr - TCP-Hdr = 1220 */
|
||||
#else
|
||||
#define GNRC_TCP_MSS (576U) /**< Default MSS */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MSS Multiplicator = Number of MSS sized packets stored in receive buffer
|
||||
*/
|
||||
#ifndef GNRC_TCP_MSS_MULTIPLICATOR
|
||||
#define GNRC_TCP_MSS_MULTIPLICATOR (1U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default Window Size
|
||||
*/
|
||||
#ifndef GNRC_TCP_DEFAULT_WINDOW
|
||||
#define GNRC_TCP_DEFAULT_WINDOW (GNRC_TCP_MSS * GNRC_TCP_MSS_MULTIPLICATOR)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of preallocated receive buffers
|
||||
*/
|
||||
#ifndef GNRC_TCP_RCV_BUFFERS
|
||||
#define GNRC_TCP_RCV_BUFFERS 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default Receive Buffer Size
|
||||
*/
|
||||
#ifndef GNRC_TCP_RCV_BUF_SIZE
|
||||
#define GNRC_TCP_RCV_BUF_SIZE (GNRC_TCP_DEFAULT_WINDOW)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Lower Bound for RTO = 1 sec (see RFC 6298)
|
||||
*/
|
||||
#ifndef GNRC_TCP_RTO_LOWER_BOUND
|
||||
#define GNRC_TCP_RTO_LOWER_BOUND (1 * US_PER_SEC)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Upper Bound for RTO = 60 sec (see RFC 6298)
|
||||
*/
|
||||
#ifndef GNRC_TCP_RTO_UPPER_BOUND
|
||||
#define GNRC_TCP_RTO_UPPER_BOUND (60 * US_PER_SEC)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Assumes clock granularity for TCP of 10 ms (see RFC 6298)
|
||||
*/
|
||||
#ifndef GNRC_TCP_RTO_GRANULARITY
|
||||
#define GNRC_TCP_RTO_GRANULARITY (10 * MS_PER_SEC)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Alpha value for RTO calculation, default is 1/8
|
||||
*/
|
||||
#ifndef GNRC_TCP_RTO_A_DIV
|
||||
#define GNRC_TCP_RTO_A_DIV (8U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Beta value for RTO calculation, default is 1/4
|
||||
*/
|
||||
#ifndef GNRC_TCP_RTO_B_DIV
|
||||
#define GNRC_TCP_RTO_B_DIV (4U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief K value for RTO calculation, default is 4
|
||||
*/
|
||||
#ifndef GNRC_TCP_RTO_K
|
||||
#define GNRC_TCP_RTO_K (4U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro to mark is the time measurement is uninitialized
|
||||
*/
|
||||
#ifndef GNRC_TCP_RTO_UNINITIALIZED
|
||||
#define GNRC_TCP_RTO_UNINITIALIZED (-1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Lower Bound for the duration between probes
|
||||
*/
|
||||
#ifndef GNRC_TCP_PROBE_LOWER_BOUND
|
||||
#define GNRC_TCP_PROBE_LOWER_BOUND (1 * US_PER_SEC)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Upper Bound for the duration between probes
|
||||
*/
|
||||
#ifndef GNRC_TCP_PROBE_UPPER_BOUND
|
||||
#define GNRC_TCP_PROBE_UPPER_BOUND (60 * US_PER_SEC)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GNRC_TCP_CONFIG_H_ */
|
||||
/** @} */
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Simon Brummer
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_tcp TCP
|
||||
* @ingroup net_gnrc
|
||||
* @brief RIOT's tcp implementation for the gnrc stack
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Definies states and events for TCP finite state maschine
|
||||
*
|
||||
* @author Simon Brummer <brummer.simon@googlemail.com>
|
||||
*/
|
||||
|
||||
#ifndef GNRC_TCP_FSM_H_
|
||||
#define GNRC_TCP_FSM_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief The TCP FSM States.
|
||||
*/
|
||||
typedef enum {
|
||||
GNRC_TCP_FSM_STATE_CLOSED,
|
||||
GNRC_TCP_FSM_STATE_LISTEN,
|
||||
GNRC_TCP_FSM_STATE_SYN_SENT,
|
||||
GNRC_TCP_FSM_STATE_SYN_RCVD,
|
||||
GNRC_TCP_FSM_STATE_ESTABLISHED,
|
||||
GNRC_TCP_FSM_STATE_CLOSE_WAIT,
|
||||
GNRC_TCP_FSM_STATE_LAST_ACK,
|
||||
GNRC_TCP_FSM_STATE_FIN_WAIT_1,
|
||||
GNRC_TCP_FSM_STATE_FIN_WAIT_2,
|
||||
GNRC_TCP_FSM_STATE_CLOSING,
|
||||
GNRC_TCP_FSM_STATE_TIME_WAIT
|
||||
} gnrc_tcp_fsm_state_t;
|
||||
|
||||
/**
|
||||
* @brief Events that trigger translations in TCP FSM.
|
||||
*/
|
||||
typedef enum {
|
||||
GNRC_TCP_FSM_EVENT_CALL_OPEN, /* User function call: open */
|
||||
GNRC_TCP_FSM_EVENT_CALL_SEND, /* User function call: send */
|
||||
GNRC_TCP_FSM_EVENT_CALL_RECV, /* User function call: recv */
|
||||
GNRC_TCP_FSM_EVENT_CALL_CLOSE, /* User function call: close */
|
||||
GNRC_TCP_FSM_EVENT_CALL_ABORT, /* User function call: abort */
|
||||
GNRC_TCP_FSM_EVENT_RCVD_PKT, /* Paket received from peer */
|
||||
GNRC_TCP_FSM_EVENT_TIMEOUT_TIMEWAIT, /* Timeout: Timewait */
|
||||
GNRC_TCP_FSM_EVENT_TIMEOUT_RETRANSMIT, /* Timeout: Retransmit */
|
||||
GNRC_TCP_FSM_EVENT_TIMEOUT_CONNECTION, /* Timeout: Connection */
|
||||
GNRC_TCP_FSM_EVENT_SEND_PROBE, /* Send a Zero Window Probe */
|
||||
GNRC_TCP_FSM_EVENT_CLEAR_RETRANSMIT /* Clear Retransmission Mechanism */
|
||||
} gnrc_tcp_fsm_event_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GNRC_TCP_FSM_H_ */
|
||||
/** @} */
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Simon Brummer
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_tcp TCP
|
||||
* @ingroup net_gnrc
|
||||
* @brief RIOT's tcp implementation for the gnrc stack
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief TCP Header
|
||||
*
|
||||
* @author Simon Brummer <brummer.simon@googlemail.com>
|
||||
*/
|
||||
|
||||
#ifndef GNRC_TCP_HDR_H_
|
||||
#define GNRC_TCP_HDR_H_
|
||||
|
||||
#include "byteorder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TCP Options could contain up to 10 32-Bit values of Information.
|
||||
*/
|
||||
#define TCP_MAX_HDR_OPTIONS 10
|
||||
|
||||
/**
|
||||
* @brief TCP header definition
|
||||
*/
|
||||
typedef struct __attribute__((packed)) {
|
||||
network_uint16_t src_port; /**< source port, in network byte order */
|
||||
network_uint16_t dst_port; /**< destination port, in network byte order */
|
||||
network_uint32_t seq_num; /**< sequence number, in network byte order */
|
||||
network_uint32_t ack_num; /**< Acknowledgement number, in network byte order */
|
||||
network_uint16_t off_ctl; /**< Data Offset and control Bits in network byte order */
|
||||
network_uint16_t window; /**< window, in network byte order */
|
||||
network_uint16_t checksum; /**< checksum, in network byte order */
|
||||
network_uint16_t urgent_ptr; /**< urgent pointer, in network byte order */
|
||||
network_uint32_t options[TCP_MAX_HDR_OPTIONS]; /**< Option Fields (Optional) */
|
||||
} tcp_hdr_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GNRC_TCP_TCB_H_ */
|
||||
/** @} */
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Simon Brummer
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_tcp TCP
|
||||
* @ingroup net_gnrc
|
||||
* @brief RIOT's tcp implementation for the gnrc stack
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Transmission Control Block definition
|
||||
*
|
||||
* @author Simon Brummer <simon.brummer@haw-hamburg.de>
|
||||
*/
|
||||
|
||||
#ifndef GNRC_TCP_TCB_H_
|
||||
#define GNRC_TCP_TCB_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ringbuffer.h>
|
||||
#include <xtimer.h>
|
||||
#include <mutex.h>
|
||||
#include <msg.h>
|
||||
#include "net/gnrc.h"
|
||||
#include "fsm.h"
|
||||
#include "config.h"
|
||||
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief transmission control block of gnrc_tcp
|
||||
*/
|
||||
typedef struct _transmission_control_block {
|
||||
uint8_t address_family; /**< Address Family of local_addr and peer_addr */
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
uint8_t local_addr[sizeof(ipv6_addr_t)]; /**< local IP address */
|
||||
uint8_t peer_addr[sizeof(ipv6_addr_t)]; /**< peer IP address */
|
||||
#endif
|
||||
uint16_t local_port; /**< local connections port number */
|
||||
uint16_t peer_port; /**< port connections port number */
|
||||
gnrc_tcp_fsm_state_t state; /**< Connections state */
|
||||
uint8_t status; /**< A connections status flags */
|
||||
uint32_t snd_una; /**< Send Unacknowledged */
|
||||
uint32_t snd_nxt; /**< Send Next */
|
||||
uint16_t snd_wnd; /**< Send Window */
|
||||
uint32_t snd_wl1; /**< SeqNo. Last Windowupdate */
|
||||
uint32_t snd_wl2; /**< AckNo. Last Windowupdate */
|
||||
uint32_t rcv_nxt; /**< Receive Next */
|
||||
uint16_t rcv_wnd; /**< Receive Window */
|
||||
uint32_t iss; /**< Initial Sequence Number */
|
||||
uint32_t irs; /**< Initial Received Sequence Number */
|
||||
uint16_t mss; /**< The peers MSS */
|
||||
uint32_t rtt_start; /**< Timer value for rtt estimation */
|
||||
int32_t rtt_var; /**< Round Trip Time variance */
|
||||
int32_t srtt; /**< Smoothed Round Trip Time */
|
||||
int32_t rto; /**< Retransmission Timeout Duration */
|
||||
uint8_t retries; /**< Number of Retransmissions */
|
||||
xtimer_t tim_tout; /**< Timer struct for timeouts */
|
||||
msg_t msg_tout; /**< Message, sent on timeouts */
|
||||
gnrc_pktsnip_t *pkt_retransmit; /**< Pointer to Packet in "retransmit queue" */
|
||||
kernel_pid_t owner; /**< PID of this connection handling thread */
|
||||
msg_t msg_queue[GNRC_TCP_MSG_QUEUE_SIZE]; /**< Message queue used for asynchronious operation */
|
||||
uint8_t *rcv_buf_raw; /**< Pointer to the receive buffer */
|
||||
ringbuffer_t rcv_buf; /**< Receive Buffer data structure */
|
||||
mutex_t fsm_lock; /**< Mutex for FSM access synchronization */
|
||||
mutex_t function_lock; /**< Mutex for Function call synchronization */
|
||||
struct _transmission_control_block *next; /**< Pointer next TCP connection */
|
||||
} gnrc_tcp_tcb_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* GNRC_TCP_TCB_H_ */
|
||||
/** @} */
|
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_tcp
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
@ -0,0 +1,616 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Simon Brummer
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup net_gnrc
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief GNRC's TCP implementation
|
||||
*
|
||||
* @author Simon Brummer <brummer.simon@googlemail.com>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <utlist.h>
|
||||
#include "msg.h"
|
||||
#include "assert.h"
|
||||
#include "thread.h"
|
||||
#include "byteorder.h"
|
||||
#include "random.h"
|
||||
#include "xtimer.h"
|
||||
#include "mutex.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "net/af.h"
|
||||
#include "net/gnrc/nettype.h"
|
||||
#include "net/gnrc/netapi.h"
|
||||
#include "net/gnrc/netreg.h"
|
||||
#include "net/gnrc/pktbuf.h"
|
||||
#include "net/gnrc/tcp.h"
|
||||
|
||||
#include "internal/fsm.h"
|
||||
#include "internal/pkt.h"
|
||||
#include "internal/option.h"
|
||||
#include "internal/helper.h"
|
||||
#include "internal/eventloop.h"
|
||||
#include "internal/rcvbuf.h"
|
||||
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#endif
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Allocate memory for TCP thread's stack
|
||||
*/
|
||||
#if ENABLE_DEBUG
|
||||
static char _stack[GNRC_TCP_STACK_SIZE + THREAD_EXTRA_STACKSIZE_PRINTF];
|
||||
#else
|
||||
static char _stack[GNRC_TCP_STACK_SIZE];
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief TCPs eventloop pid, declared externally
|
||||
*/
|
||||
kernel_pid_t _gnrc_tcp_pid = KERNEL_PID_UNDEF;
|
||||
|
||||
/**
|
||||
* @brief Head of liked list of active connections
|
||||
*/
|
||||
gnrc_tcp_tcb_t *_list_gnrc_tcp_tcb_head;
|
||||
|
||||
/**
|
||||
* @brief Mutex to protect the connection list
|
||||
*/
|
||||
mutex_t _list_gnrc_tcp_tcb_lock;
|
||||
|
||||
/**
|
||||
* @brief Establishes a new TCP connection
|
||||
*
|
||||
* @param[in/out] tcb This connections Transmission control block.
|
||||
* @param[in] target_addr Target Address to connect to, if this is a active connection.
|
||||
* @param[in] target_port Target Port to connect to, if this is a active connection.
|
||||
* @param[in] local_addr Local Address to bind on, if this is a passive connection.
|
||||
* @param[in] local_port Local Port to bind on, if this is a passive connection.
|
||||
* @param[in] passive Flag to indicate if this is a active or passive open.
|
||||
*
|
||||
* @return 0 on success.
|
||||
* @return -EISCONN if transmission control block is already in use.
|
||||
* @return -ENOMEM if the receive buffer for the tcb could not be allocated.
|
||||
* Increase "GNRC_TCP_RCV_BUFFERS".
|
||||
* @return -EADDRINUSE if @p local_port is already used by another connection. Only active mode.
|
||||
* @return -ETIMEDOUT if the connection could not be opened. Only active mode.
|
||||
* @return -ECONNREFUSED if the connection was resetted by the peer.
|
||||
*/
|
||||
static int _gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const uint8_t *target_addr, uint16_t target_port,
|
||||
const uint8_t *local_addr, uint16_t local_port, uint8_t passive)
|
||||
{
|
||||
msg_t msg; /* Message for incomming Messages */
|
||||
msg_t connection_timeout_msg; /* Connection Timeout Message */
|
||||
xtimer_t connection_timeout_timer; /* Connection Timeout Timer */
|
||||
int8_t ret = 0; /* Return Value */
|
||||
|
||||
/* Lock the tcb for this function call */
|
||||
mutex_lock(&(tcb->function_lock));
|
||||
|
||||
/* Connection is already connected: Return -EISCONN */
|
||||
if (tcb->state != GNRC_TCP_FSM_STATE_CLOSED) {
|
||||
mutex_unlock(&(tcb->function_lock));
|
||||
return -EISCONN;
|
||||
}
|
||||
|
||||
/* Setup connection (common parts) */
|
||||
msg_init_queue(tcb->msg_queue, GNRC_TCP_MSG_QUEUE_SIZE);
|
||||
tcb->owner = thread_getpid();
|
||||
|
||||
/* Setup passive connection */
|
||||
if (passive){
|
||||
/* Set Status Flags */
|
||||
tcb->status |= GNRC_TCP_STATUS_PASSIVE;
|
||||
if (local_addr == NULL) {
|
||||
tcb->status |= GNRC_TCP_STATUS_ALLOW_ANY_ADDR;
|
||||
}
|
||||
/* If local address is specified: Copy it into tcb: only connections to this addr are ok */
|
||||
else {
|
||||
switch (tcb->address_family) {
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
case AF_INET6:
|
||||
memcpy(tcb->local_addr, local_addr, sizeof(ipv6_addr_t));
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Assign Port to listen on, to tcb */
|
||||
tcb->local_port = local_port;
|
||||
}
|
||||
/* Setup active connection */
|
||||
else{
|
||||
/* Copy Target Address and Port into tcb structure */
|
||||
if (target_addr != NULL) {
|
||||
switch (tcb->address_family) {
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
case AF_INET6:
|
||||
memcpy(tcb->peer_addr, target_addr, sizeof(ipv6_addr_t));
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/* Copy Port Information, verfication happens in fsm */
|
||||
tcb->local_port = local_port;
|
||||
tcb->peer_port = target_port;
|
||||
|
||||
/* Setup Timeout: If connection could not be established before */
|
||||
/* the timer expired, the connection attempt failed */
|
||||
connection_timeout_msg.type = MSG_TYPE_CONNECTION_TIMEOUT;
|
||||
xtimer_set_msg(&connection_timeout_timer, GNRC_TCP_CONNECTION_TIMEOUT_DURATION,
|
||||
&connection_timeout_msg, tcb->owner);
|
||||
}
|
||||
|
||||
/* Call FSM with Event: CALL_OPEN */
|
||||
ret = _fsm(tcb, GNRC_TCP_FSM_EVENT_CALL_OPEN, NULL, NULL, 0);
|
||||
if (ret == -ENOMEM) {
|
||||
DEBUG("gnrc_tcp.c : gnrc_tcp_connect() : Out of receive buffers.\n");
|
||||
} else if(ret == -EADDRINUSE) {
|
||||
DEBUG("gnrc_tcp.c : gnrc_tcp_connect() : local_port is already in use.\n");
|
||||
}
|
||||
|
||||
/* Wait until a connection was established or closed */
|
||||
while (ret >= 0 && tcb->state != GNRC_TCP_FSM_STATE_CLOSED
|
||||
&& tcb->state != GNRC_TCP_FSM_STATE_ESTABLISHED
|
||||
&& tcb->state != GNRC_TCP_FSM_STATE_CLOSE_WAIT
|
||||
) {
|
||||
msg_receive(&msg);
|
||||
switch (msg.type) {
|
||||
case MSG_TYPE_CONNECTION_TIMEOUT:
|
||||
DEBUG("gnrc_tcp.c : _gnrc_tcp_open() : CONNECTION_TIMEOUT\n");
|
||||
_fsm(tcb, GNRC_TCP_FSM_EVENT_TIMEOUT_CONNECTION, NULL, NULL, 0);
|
||||
ret = -ETIMEDOUT;
|
||||
break;
|
||||
|
||||
case MSG_TYPE_NOTIFY_USER:
|
||||
DEBUG("gnrc_tcp.c : _gnrc_tcp_open() : MSG_TYPE_NOTIFY_USER\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG("gnrc_tcp.c : _gnrc_tcp_open() : other message type\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
xtimer_remove(&connection_timeout_timer);
|
||||
if (tcb->state == GNRC_TCP_FSM_STATE_CLOSED && ret == 0) {
|
||||
ret = -ECONNREFUSED;
|
||||
}
|
||||
tcb->owner = KERNEL_PID_UNDEF;
|
||||
mutex_unlock(&(tcb->function_lock));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* External GNRC_TCP API */
|
||||
int gnrc_tcp_init(void)
|
||||
{
|
||||
/* Guard: Check if thread is already running */
|
||||
if (_gnrc_tcp_pid != KERNEL_PID_UNDEF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize Mutex for linked-list synchronization */
|
||||
mutex_init(&(_list_gnrc_tcp_tcb_lock));
|
||||
|
||||
/* Initialize Linked-List for connection storage */
|
||||
_list_gnrc_tcp_tcb_head = NULL;
|
||||
|
||||
/* Initialize receive buffers */
|
||||
_rcvbuf_init();
|
||||
|
||||
/* Start TCP processing loop */
|
||||
return thread_create(_stack, sizeof(_stack), GNRC_TCP_PRIO, 0, _event_loop, NULL, "gnrc_tcp");
|
||||
}
|
||||
|
||||
void gnrc_tcp_tcb_init(gnrc_tcp_tcb_t* tcb)
|
||||
{
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
tcb->address_family = AF_INET6;
|
||||
ipv6_addr_set_unspecified((ipv6_addr_t *) tcb->local_addr);
|
||||
ipv6_addr_set_unspecified((ipv6_addr_t *) tcb->peer_addr);
|
||||
#else
|
||||
tcb->address_family = AF_UNSPEC;
|
||||
DEBUG("gnrc_tcp.c : gnrc_tcp_tcb_init() : Address unspec, add netlayer module to makefile\n");
|
||||
#endif
|
||||
tcb->local_port = GNRC_TCP_PORT_UNSPEC;
|
||||
tcb->peer_port = GNRC_TCP_PORT_UNSPEC;
|
||||
tcb->state = GNRC_TCP_FSM_STATE_CLOSED;
|
||||
tcb->status = 0;
|
||||
tcb->snd_una = 0;
|
||||
tcb->snd_nxt = 0;
|
||||
tcb->snd_wnd = 0;
|
||||
tcb->snd_wl1 = 0;
|
||||
tcb->snd_wl2 = 0;
|
||||
tcb->rcv_nxt = 0;
|
||||
tcb->rcv_wnd = 0;
|
||||
tcb->iss = 0;
|
||||
tcb->irs = 0;
|
||||
tcb->mss = 0;
|
||||
tcb->rtt_start = 0;
|
||||
tcb->rtt_var = GNRC_TCP_RTO_UNINITIALIZED;
|
||||
tcb->srtt = GNRC_TCP_RTO_UNINITIALIZED;
|
||||
tcb->rto = GNRC_TCP_RTO_UNINITIALIZED;
|
||||
tcb->retries = 0;
|
||||
tcb->pkt_retransmit = NULL;
|
||||
tcb->owner = KERNEL_PID_UNDEF;
|
||||
tcb->rcv_buf_raw = NULL;
|
||||
mutex_init(&(tcb->fsm_lock));
|
||||
mutex_init(&(tcb->function_lock));
|
||||
tcb->next = NULL;
|
||||
}
|
||||
|
||||
int gnrc_tcp_open_active(gnrc_tcp_tcb_t *tcb, const uint8_t address_family,
|
||||
const uint8_t *target_addr, const uint16_t target_port,
|
||||
const uint16_t local_port)
|
||||
{
|
||||
assert(tcb != NULL);
|
||||
assert(target_addr != NULL);
|
||||
assert(target_port != GNRC_TCP_PORT_UNSPEC);
|
||||
|
||||
/* Check AF-Family Support from target_addr */
|
||||
switch (address_family) {
|
||||
#ifdef MODULE_GNRC_IPV6
|
||||
case AF_INET6:
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
/* Check if AF-Family for Target Address matches internally used AF-Family */
|
||||
if (tcb->address_family != address_family) {
|
||||
return -EINVAL;
|
||||
}
|
||||
return _gnrc_tcp_open(tcb, target_addr, target_port, NULL, local_port, 0);
|
||||
}
|
||||
|
||||
int gnrc_tcp_open_passive(gnrc_tcp_tcb_t *tcb, const uint8_t address_family,
|
||||
const uint8_t *local_addr, const uint16_t local_port)
|
||||
{
|
||||
assert(tcb != |