Skip to content

Commit

Permalink
gnrc_tcp: align with sock_tcp
Browse files Browse the repository at this point in the history
  • Loading branch information
brummer-simon committed Jul 2, 2021
1 parent 0886675 commit 3dc23a7
Show file tree
Hide file tree
Showing 5 changed files with 395 additions and 8 deletions.
51 changes: 51 additions & 0 deletions sys/include/net/gnrc/tcp.h
Expand Up @@ -101,6 +101,14 @@ int gnrc_tcp_init(void);
*/
void gnrc_tcp_tcb_init(gnrc_tcp_tcb_t *tcb);

/**
* @brief Initialize Transmission Control Block (TCB) queue
* @pre @p queue must not be NULL.
*
* @param[in,out] queue TCB queue to initialize.
*/
void gnrc_tcp_tcb_queue_init(gnrc_tcp_tcb_queue_t *queue);

/**
* @brief Opens a connection.
*
Expand Down Expand Up @@ -168,6 +176,7 @@ int gnrc_tcp_listen(gnrc_tcp_tcb_queue_t *queue, gnrc_tcp_tcb_t *tcbs, size_t tc
*
* @return 0 on success.
* @return -ENOMEM if all connection in @p queue were already accepted.
* @return -EINVAL if listen was never called on queue.
* @return -EAGAIN if @p user_timeout_duration_ms was 0 and no connection is ready to accept.
* @return -ETIMEDOUT if @p user_timeout_duration_ms was not 0 and no connection
* could be established.
Expand Down Expand Up @@ -263,6 +272,48 @@ void gnrc_tcp_abort(gnrc_tcp_tcb_t *tcb);
*/
void gnrc_tcp_stop_listen(gnrc_tcp_tcb_queue_t *queue);

/**
* @brief Get the local end point of a connected TCB
*
* @pre tcb must not be NULL
* @pre ep must not be NULL
*
* @param[in] tcb TCB holding the connection information.
* @param[out] ep The local end point.
*
* @return 0 on success.
* @return -EADDRNOTAVAIL, when @p tcb in not in a connected state.
*/
int gnrc_tcp_get_local(gnrc_tcp_tcb_t *tcb, gnrc_tcp_ep_t *ep);

/**
* @brief Get the remote end point of a connected TCB
*
* @pre tcb must not be NULL
* @pre ep must not be NULL
*
* @param[in] tcb TCB holding the connection information.
* @param[out] ep The remote end point.
*
* @return 0 on success.
* @return -ENOTCONN, when @p tcb in not in a connected state.
*/
int gnrc_tcp_get_remote(gnrc_tcp_tcb_t *tcb, gnrc_tcp_ep_t *ep);

/**
* @brief Gets the local end point of a TCB queue
*
* @pre queue must not be NULL
* @pre ep must not be NULL
*
* @param[in] queue TCB queue to stop listening
* @param[out] ep The local end point.
*
* @return 0 on success.
* @return -EADDRNOTAVAIL, when @p queue has no local end point.
*/
int gnrc_tcp_queue_get_local(gnrc_tcp_tcb_queue_t *queue, gnrc_tcp_ep_t *ep);

/**
* @brief Calculate and set checksum in TCP header.
*
Expand Down
130 changes: 127 additions & 3 deletions sys/net/gnrc/transport_layer/tcp/gnrc_tcp.c
Expand Up @@ -310,6 +310,8 @@ int gnrc_tcp_init(void)
void gnrc_tcp_tcb_init(gnrc_tcp_tcb_t *tcb)
{
TCP_DEBUG_ENTER;
assert(tcb != NULL);

memset(tcb, 0, sizeof(gnrc_tcp_tcb_t));
#ifdef MODULE_GNRC_IPV6
tcb->address_family = AF_INET6;
Expand All @@ -324,6 +326,16 @@ void gnrc_tcp_tcb_init(gnrc_tcp_tcb_t *tcb)
TCP_DEBUG_LEAVE;
}

void gnrc_tcp_tcb_queue_init(gnrc_tcp_tcb_queue_t *queue)
{
TCP_DEBUG_ENTER;
assert(queue != NULL);

mutex_init(&queue->lock);
queue->tcbs = NULL;
queue->tcbs_len = 0;
TCP_DEBUG_LEAVE;
}

int gnrc_tcp_open(gnrc_tcp_tcb_t *tcb, const gnrc_tcp_ep_t *remote, uint16_t local_port)
{
Expand Down Expand Up @@ -561,14 +573,19 @@ int gnrc_tcp_accept(gnrc_tcp_tcb_queue_t *queue, gnrc_tcp_tcb_t **tcb,
++avail_tcbs;
}

/* Return if a connection was found, accept was called as non-blocking or all
* TCBs were already accepted.
/* Return if a connection was found, queue is not listening, accept was called as non-blocking
* or all TCBs were already accepted.
*/
if ((*tcb) || (user_timeout_duration_ms == 0) || (avail_tcbs == 0)) {
if ((*tcb) || (queue->tcbs == NULL) || (user_timeout_duration_ms == 0) ||
(avail_tcbs == 0)) {
if (*tcb) {
TCP_DEBUG_INFO("Accepting connection.");
ret = 0;
}
else if (queue->tcbs == NULL) {
TCP_DEBUG_ERROR("-EINVAL: Queue is not listening.");
ret = -EINVAL;
}
else if (avail_tcbs == 0) {
TCP_DEBUG_ERROR("-ENOMEM: All TCBs are currently accepted.");
ret = -ENOMEM;
Expand Down Expand Up @@ -933,6 +950,113 @@ void gnrc_tcp_stop_listen(gnrc_tcp_tcb_queue_t *queue)
TCP_DEBUG_LEAVE;
}

int gnrc_tcp_get_local(gnrc_tcp_tcb_t *tcb, gnrc_tcp_ep_t *ep)
{
TCP_DEBUG_ENTER;
assert(tcb != NULL);
assert(ep != NULL);

int ret = 0;

/* Lock the TCB for this function call */
mutex_lock(&(tcb->function_lock));
_gnrc_tcp_fsm_state_t state =_gnrc_tcp_fsm_get_state(tcb);

/* Check if connection is established */
if ((state == FSM_STATE_ESTABLISHED) || (state == FSM_STATE_CLOSE_WAIT)) {
/* Construct endpoint from connection parameters */
ep->family = tcb->address_family;
ep->port = tcb->local_port;
ep->netif = tcb->ll_iface;
#ifdef MODULE_GNRC_IPV6
if (ep->family == AF_INET6) {
memcpy(ep->addr.ipv6, tcb->local_addr, sizeof(ep->addr.ipv6));
}
#endif
} else {
TCP_DEBUG_ERROR("-EADDRNOTAVAIL: TCB is not connected.");
ret = -EADDRNOTAVAIL;
}

mutex_unlock(&(tcb->function_lock));
TCP_DEBUG_LEAVE;
return ret;
}

int gnrc_tcp_get_remote(gnrc_tcp_tcb_t *tcb, gnrc_tcp_ep_t *ep)
{
TCP_DEBUG_ENTER;
assert(tcb != NULL);
assert(ep != NULL);

int ret = 0;

/* Lock the TCB for this function call */
mutex_lock(&(tcb->function_lock));
_gnrc_tcp_fsm_state_t state =_gnrc_tcp_fsm_get_state(tcb);

/* Check if connection is established */
if ((state == FSM_STATE_ESTABLISHED) || (state == FSM_STATE_CLOSE_WAIT)) {
/* Construct endpoint from connection parameters */
ep->family = tcb->address_family;
ep->port = tcb->peer_port;
ep->netif = 0;
#ifdef MODULE_GNRC_IPV6
if (ep->family == AF_INET6) {
memcpy(ep->addr.ipv6, tcb->peer_addr, sizeof(ep->addr.ipv6));
}
#endif
} else {
TCP_DEBUG_ERROR("-ENOTCONN: TCB is not connected.");
ret = -ENOTCONN;
}

mutex_unlock(&(tcb->function_lock));
TCP_DEBUG_LEAVE;
return ret;
}

int gnrc_tcp_queue_get_local(gnrc_tcp_tcb_queue_t *queue, gnrc_tcp_ep_t *ep)
{
TCP_DEBUG_ENTER;
assert(queue != NULL);
assert(ep != NULL);

int ret = 0;

/* Lock the TCB queue for this function call */
mutex_lock(&(queue->lock));

/* Check if queue has associated TCBs */
if (queue->tcbs) {
/* There are listening TCBs: Construct ep from first TCB. */
gnrc_tcp_tcb_t *tcb = queue->tcbs;
mutex_lock(&(tcb->function_lock));

/* Construct endpoint from tcbs connection parameters */
ep->family = tcb->address_family;
ep->port = tcb->local_port;
ep->netif = 0;
#ifdef MODULE_GNRC_IPV6
if (ep->family == AF_INET6) {
if (tcb->status & STATUS_ALLOW_ANY_ADDR) {
ipv6_addr_set_unspecified((ipv6_addr_t *) ep->addr.ipv6);
} else {
memcpy(ep->addr.ipv6, tcb->local_addr, sizeof(ep->addr.ipv6));
}
}
#endif
mutex_unlock(&(tcb->function_lock));
} else {
TCP_DEBUG_ERROR("-EADDRNOTAVAIL: queue was never listening.");
ret = -EADDRNOTAVAIL;
}

mutex_unlock(&(queue->lock));
TCP_DEBUG_LEAVE;
return ret;
}

int gnrc_tcp_calc_csum(const gnrc_pktsnip_t *hdr, const gnrc_pktsnip_t *pseudo_hdr)
{
TCP_DEBUG_ENTER;
Expand Down
82 changes: 82 additions & 0 deletions tests/gnrc_tcp/main.c
Expand Up @@ -217,6 +217,10 @@ int gnrc_tcp_accept_cmd(int argc, char **argv)
int timeout = atol(argv[1]);
int err = gnrc_tcp_accept(&queue, &tmp, timeout);
switch (err) {
case -EINVAL:
printf("%s: returns -EINVAL\n", argv[0]);
break;

case -EAGAIN:
printf("%s: returns -EAGAIN\n", argv[0]);
break;
Expand Down Expand Up @@ -341,6 +345,78 @@ int gnrc_tcp_stop_listen_cmd(int argc, char **argv)
return 0;
}

int gnrc_tcp_get_local_cmd(int argc, char **argv)
{
dump_args(argc, argv);
gnrc_tcp_ep_t ep;

int err = gnrc_tcp_get_local(tcb, &ep);
switch (err) {
case 0:
printf("%s: returns 0\n", argv[0]);
printf("Endpoint: addr.ipv6=");
ipv6_addr_print((ipv6_addr_t *) ep.addr.ipv6);
printf(" netif=%u port=%u\n", ep.netif, ep.port);
break;

case -EADDRNOTAVAIL:
printf("%s: returns -EADDRNOTAVAIL\n", argv[0]);
break;

default:
printf("%s: returns %d\n", argv[0], err);
}
return 0;
}

int gnrc_tcp_get_remote_cmd(int argc, char **argv)
{
dump_args(argc, argv);
gnrc_tcp_ep_t ep;

int err = gnrc_tcp_get_remote(tcb, &ep);
switch (err) {
case 0:
printf("%s: returns 0\n", argv[0]);
printf("Endpoint: addr.ipv6=");
ipv6_addr_print((ipv6_addr_t *) ep.addr.ipv6);
printf(" netif=%u port=%u\n", ep.netif, ep.port);
break;

case -ENOTCONN:
printf("%s: returns -ENOTCONN\n", argv[0]);
break;

default:
printf("%s: returns %d\n", argv[0], err);
}
return 0;
}

int gnrc_tcp_queue_get_local_cmd(int argc, char **argv)
{
dump_args(argc, argv);
gnrc_tcp_ep_t ep;

int err = gnrc_tcp_queue_get_local(&queue, &ep);
switch (err) {
case 0:
printf("%s: returns 0\n", argv[0]);
printf("Endpoint: addr.ipv6=");
ipv6_addr_print((ipv6_addr_t *) ep.addr.ipv6);
printf(" netif=%u port=%u\n", ep.netif, ep.port);
break;

case -EADDRNOTAVAIL:
printf("%s: returns -EADDRNOTAVAIL\n", argv[0]);
break;

default:
printf("%s: returns %d\n", argv[0], err);
}
return 0;
}

/* Exporting GNRC TCP Api to for shell usage */
static const shell_command_t shell_commands[] = {
{ "gnrc_tcp_ep_from_str", "Build endpoint from string",
Expand All @@ -363,6 +439,12 @@ static const shell_command_t shell_commands[] = {
gnrc_tcp_abort_cmd },
{ "gnrc_tcp_stop_listen", "gnrc_tcp: stop listening",
gnrc_tcp_stop_listen_cmd },
{ "gnrc_tcp_get_local", "gnrc_tcp: get local",
gnrc_tcp_get_local_cmd },
{ "gnrc_tcp_get_remote", "gnrc_tcp: get remote",
gnrc_tcp_get_remote_cmd },
{ "gnrc_tcp_queue_get_local", "gnrc_tcp: get queue local",
gnrc_tcp_queue_get_local_cmd },
{ "buffer_init", "init internal buffer",
buffer_init_cmd },
{ "buffer_get_max_size", "get max size of internal buffer",
Expand Down

0 comments on commit 3dc23a7

Please sign in to comment.