/* * Copyright (C) 2018 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 #include #include "shell.h" #include "msg.h" #include "net/af.h" #include "net/gnrc/tcp.h" #define MAIN_QUEUE_SIZE (8) #define TCB_QUEUE_SIZE (1) #define BUFFER_SIZE (2049) static msg_t main_msg_queue[MAIN_QUEUE_SIZE]; static gnrc_tcp_tcb_t tcbs[TCB_QUEUE_SIZE]; static gnrc_tcp_tcb_t *tcb = tcbs; static gnrc_tcp_tcb_queue_t queue = GNRC_TCP_TCB_QUEUE_INIT; static char buffer[BUFFER_SIZE]; void dump_args(int argc, char **argv) { printf("%s: ", argv[0]); printf("argc=%d", argc); for (int i = 0; i < argc; ++i) { printf(", argv[%d] = %s", i, argv[i]); } printf("\n"); } /* API Export for test script */ int buffer_init_cmd(int argc, char **argv) { dump_args(argc, argv); memset(buffer, '\0', sizeof(buffer)); return 0; } int buffer_get_max_size_cmd(int argc, char **argv) { dump_args(argc, argv); printf("%s: returns %d\n", argv[0], BUFFER_SIZE - 1); return 0; } int buffer_write_cmd(int argc, char **argv) { dump_args(argc, argv); size_t offset = atol(argv[1]); char *src = argv[2]; size_t src_len = strlen(src); char *dst = buffer + offset; memcpy(dst, src, src_len); return 0; } int buffer_read_cmd(int argc, char **argv) { dump_args(argc, argv); size_t offset = atol(argv[1]); size_t size = atol(argv[2]); /* Calculate Start and End of readout */ char *begin = buffer + offset; char *end = begin + size; /* Place temporary endmarker in buffer and print */ char tmp = *end; *end = '\0'; printf("%s: %s\n", argv[0], begin); *end = tmp; return 0; } int gnrc_tcp_ep_from_str_cmd(int argc, char **argv) { dump_args(argc, argv); gnrc_tcp_ep_t ep; int err = gnrc_tcp_ep_from_str(&ep, argv[1]); switch (err) { case -EINVAL: printf("%s: returns -EINVAL\n", argv[0]); break; default: printf("%s: returns %d\n", argv[0], err); } if (err == 0) { char addr_as_str[IPV6_ADDR_MAX_STR_LEN]; switch (ep.family) { case AF_INET6: printf("Family: AF_INET6\n"); ipv6_addr_to_str(addr_as_str, (ipv6_addr_t *) ep.addr.ipv6, sizeof(addr_as_str)); printf("Addr: %s\n", addr_as_str); break; case AF_INET: printf("Family: AF_INET\n"); break; default: printf("Family: %d\n", ep.family); } printf("Port: %d\n", ep.port); printf("Netif: %d\n", ep.netif); } return err; } int gnrc_tcp_tcb_init_cmd(int argc, char **argv) { dump_args(argc, argv); // Initialize all given TCBs for (int i = 0; i < TCB_QUEUE_SIZE; ++i) { gnrc_tcp_tcb_init(&(tcbs[i])); } printf("%s: returns 0\n", argv[0]); return 0; } int gnrc_tcp_open_cmd(int argc, char **argv) { dump_args(argc, argv); gnrc_tcp_ep_t remote; gnrc_tcp_ep_from_str(&remote, argv[1]); uint16_t local_port = atol(argv[2]); int err = gnrc_tcp_open(tcb, &remote, local_port); switch (err) { case -EAFNOSUPPORT: printf("%s: returns -EAFNOSUPPORT\n", argv[0]); break; case -EINVAL: printf("%s: returns -EINVAL\n", argv[0]); break; case -EISCONN: printf("%s: returns -EISCONN\n", argv[0]); break; case -ENOMEM: printf("%s: returns -ENOMEM\n", argv[0]); break; case -EADDRINUSE: printf("%s: returns -EADDRINUSE\n", argv[0]); break; case -ETIMEDOUT: printf("%s: returns -ETIMEOUT\n", argv[0]); break; case -ECONNREFUSED: printf("%s: returns -ECONNREFUSED\n", argv[0]); break; default: printf("%s: returns %d\n", argv[0], err); } return err; } int gnrc_tcp_listen_cmd(int argc, char **argv) { dump_args(argc, argv); gnrc_tcp_ep_t local; gnrc_tcp_ep_from_str(&local, argv[1]); int err = gnrc_tcp_listen(&queue, tcbs, ARRAY_SIZE(tcbs), &local); switch (err) { case -EAFNOSUPPORT: printf("%s: returns -EAFNOSUPPORT\n", argv[0]); break; case -EINVAL: printf("%s: returns -EINVAL\n", argv[0]); break; case -EISCONN: printf("%s: returns -EISCONN\n", argv[0]); break; case -ENOMEM: printf("%s: returns -ENOMEM\n", argv[0]); break; default: printf("%s: returns %d\n", argv[0], err); } return err; } int gnrc_tcp_accept_cmd(int argc, char **argv) { dump_args(argc, argv); gnrc_tcp_tcb_t *tmp = NULL; 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; case -ENOMEM: printf("%s: returns -ENOMEM\n", argv[0]); break; case -ETIMEDOUT: printf("%s: returns -ETIMEDOUT\n", argv[0]); break; default: printf("%s: returns %d\n", argv[0], err); } if (tmp) { tcb = tmp; } return err; } int gnrc_tcp_send_cmd(int argc, char **argv) { dump_args(argc, argv); size_t timeout = atol(argv[1]); size_t to_send = atol(argv[2]); size_t sent = 0; do { int ret = gnrc_tcp_send(tcb, buffer + sent, to_send - sent, timeout); switch (ret) { case 0: printf("%s: returns 0\n", argv[0]); return ret; case -ENOTCONN: printf("%s: returns -ENOTCONN\n", argv[0]); return ret; case -ECONNRESET: printf("%s: returns -ECONNRESET\n", argv[0]); return ret; case -ECONNABORTED: printf("%s: returns -ECONNABORTED\n", argv[0]); return ret; case -ETIMEDOUT: printf("%s: returns -ETIMEDOUT\n", argv[0]); return ret; } sent += ret; } while (sent < to_send); printf("%s: sent %u\n", argv[0], (unsigned)sent); return sent; } int gnrc_tcp_recv_cmd(int argc, char **argv) { dump_args(argc, argv); int timeout = atol(argv[1]); size_t to_receive = atol(argv[2]); size_t rcvd = 0; do { int ret = gnrc_tcp_recv(tcb, buffer + rcvd, to_receive - rcvd, timeout); switch (ret) { case 0: printf("%s: returns 0\n", argv[0]); return ret; case -EAGAIN: printf("%s: returns -EAGAIN\n", argv[0]); continue; case -ETIMEDOUT: printf("%s: returns -ETIMEDOUT\n", argv[0]); continue; case -ENOTCONN: printf("%s: returns -ENOTCONN\n", argv[0]); return ret; case -ECONNRESET: printf("%s: returns -ECONNRESET\n", argv[0]); return ret; case -ECONNABORTED: printf("%s: returns -ECONNABORTED\n", argv[0]); return ret; } rcvd += ret; } while (rcvd < to_receive); printf("%s: received %u\n", argv[0], (unsigned)rcvd); return 0; } int gnrc_tcp_close_cmd(int argc, char **argv) { dump_args(argc, argv); gnrc_tcp_close(tcb); printf("%s: returns\n", argv[0]); return 0; } int gnrc_tcp_abort_cmd(int argc, char **argv) { dump_args(argc, argv); gnrc_tcp_abort(tcb); printf("%s: returns\n", argv[0]); return 0; } int gnrc_tcp_stop_listen_cmd(int argc, char **argv) { dump_args(argc, argv); gnrc_tcp_stop_listen(&queue); printf("%s: returns\n", argv[0]); 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", gnrc_tcp_ep_from_str_cmd }, { "gnrc_tcp_tcb_init", "gnrc_tcp: init tcb", gnrc_tcp_tcb_init_cmd }, { "gnrc_tcp_open", "gnrc_tcp: open connection", gnrc_tcp_open_cmd }, { "gnrc_tcp_listen", "gnrc_tcp: listen for connection", gnrc_tcp_listen_cmd }, { "gnrc_tcp_accept", "gnrc_tcp: accept connection", gnrc_tcp_accept_cmd }, { "gnrc_tcp_send", "gnrc_tcp: send data to connected peer", gnrc_tcp_send_cmd }, { "gnrc_tcp_recv", "gnrc_tcp: recv data from connected peer", gnrc_tcp_recv_cmd }, { "gnrc_tcp_close", "gnrc_tcp: close connection gracefully", gnrc_tcp_close_cmd }, { "gnrc_tcp_abort", "gnrc_tcp: close connection forcefully", 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", buffer_get_max_size_cmd }, { "buffer_write", "write data into internal buffer", buffer_write_cmd }, { "buffer_read", "read data from internal buffer", buffer_read_cmd }, { NULL, NULL, NULL } }; int main(void) { /* we need a message queue for the thread running the shell in order to * receive potentially fast incoming networking packets */ msg_init_queue(main_msg_queue, MAIN_QUEUE_SIZE); printf("RIOT GNRC_TCP test application\n"); /* start shell */ char line_buf[SHELL_DEFAULT_BUFSIZE]; shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); /* should be never reached */ return 0; }