1#include "utils.h" 2#include <pico_socket.h> 3#include <pico_ipv4.h> 4/*** START TCP ECHO ***/ 5#define BSIZE (1024 * 10) 6static char recvbuf[BSIZE]; 7static int pos = 0, len = 0; 8static int flag = 0; 9 10int send_tcpecho(struct pico_socket *s) 11{ 12 int w, ww = 0; 13 if (len > pos) { 14 do { 15 w = pico_socket_write(s, recvbuf + pos, len - pos); 16 if (w > 0) { 17 pos += w; 18 ww += w; 19 if (pos >= len) { 20 pos = 0; 21 len = 0; 22 } 23 } 24 } while((w > 0) && (pos < len)); 25 } 26 27 return ww; 28} 29 30void cb_tcpecho(uint16_t ev, struct pico_socket *s) 31{ 32 int r = 0; 33 34 picoapp_dbg("tcpecho> wakeup ev=%u\n", ev); 35 36 if (ev & PICO_SOCK_EV_RD) { 37 if (flag & PICO_SOCK_EV_CLOSE) 38 printf("SOCKET> EV_RD, FIN RECEIVED\n"); 39 40 while (len < BSIZE) { 41 r = pico_socket_read(s, recvbuf + len, BSIZE - len); 42 if (r > 0) { 43 len += r; 44 flag &= ~(PICO_SOCK_EV_RD); 45 } else { 46 flag |= PICO_SOCK_EV_RD; 47 break; 48 } 49 } 50 if (flag & PICO_SOCK_EV_WR) { 51 flag &= ~PICO_SOCK_EV_WR; 52 send_tcpecho(s); 53 } 54 } 55 56 if (ev & PICO_SOCK_EV_CONN) { 57 uint32_t ka_val = 0; 58 struct pico_socket *sock_a = { 59 0 60 }; 61 struct pico_ip4 orig = { 62 0 63 }; 64 uint16_t port = 0; 65 char peer[30] = { 66 0 67 }; 68 int yes = 1; 69 70 sock_a = pico_socket_accept(s, &orig, &port); 71 pico_ipv4_to_string(peer, orig.addr); 72 printf("Connection established with %s:%d.\n", peer, short_be(port)); 73 pico_socket_setoption(sock_a, PICO_TCP_NODELAY, &yes); 74 /* Set keepalive options */ 75 ka_val = 5; 76 pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPCNT, &ka_val); 77 ka_val = 30000; 78 pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPIDLE, &ka_val); 79 ka_val = 5000; 80 pico_socket_setoption(sock_a, PICO_SOCKET_OPT_KEEPINTVL, &ka_val); 81 } 82 83 if (ev & PICO_SOCK_EV_FIN) { 84 printf("Socket closed. Exit normally. \n"); 85 if (!pico_timer_add(2000, deferred_exit, NULL)) { 86 printf("Failed to start exit timer, exiting now\n"); 87 exit(1); 88 } 89 } 90 91 if (ev & PICO_SOCK_EV_ERR) { 92 printf("Socket error received: %s. Bailing out.\n", strerror(pico_err)); 93 exit(1); 94 } 95 96 if (ev & PICO_SOCK_EV_CLOSE) { 97 printf("Socket received close from peer.\n"); 98 if (flag & PICO_SOCK_EV_RD) { 99 pico_socket_shutdown(s, PICO_SHUT_WR); 100 printf("SOCKET> Called shutdown write, ev = %d\n", ev); 101 } 102 } 103 104 if (ev & PICO_SOCK_EV_WR) { 105 r = send_tcpecho(s); 106 if (r == 0) 107 flag |= PICO_SOCK_EV_WR; 108 else 109 flag &= (~PICO_SOCK_EV_WR); 110 } 111} 112 113void app_tcpecho(char *arg) 114{ 115 char *nxt = arg; 116 char *lport = NULL; 117 uint16_t listen_port = 0; 118 int ret = 0, yes = 1; 119 struct pico_socket *s = NULL; 120 union { 121 struct pico_ip4 ip4; 122 struct pico_ip6 ip6; 123 } inaddr_any = { 124 .ip4 = {0}, .ip6 = {{0}} 125 }; 126 127 /* start of argument parsing */ 128 if (nxt) { 129 nxt = cpy_arg(&lport, nxt); 130 if (lport && atoi(lport)) { 131 listen_port = short_be(atoi(lport)); 132 } else { 133 goto out; 134 } 135 } else { 136 /* missing listen_port */ 137 goto out; 138 } 139 140 /* end of argument parsing */ 141 142 if (!IPV6_MODE) 143 s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcpecho); 144 else 145 s = pico_socket_open(PICO_PROTO_IPV6, PICO_PROTO_TCP, &cb_tcpecho); 146 147 if (!s) { 148 printf("%s: error opening socket: %s\n", __FUNCTION__, strerror(pico_err)); 149 exit(1); 150 } 151 152 pico_socket_setoption(s, PICO_TCP_NODELAY, &yes); 153 154 155 156 if (!IPV6_MODE) 157 ret = pico_socket_bind(s, &inaddr_any.ip4, &listen_port); 158 else 159 ret = pico_socket_bind(s, &inaddr_any.ip6, &listen_port); 160 161 if (ret < 0) { 162 printf("%s: error binding socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err)); 163 exit(1); 164 } 165 166 if (pico_socket_listen(s, 40) != 0) { 167 printf("%s: error listening on port %u\n", __FUNCTION__, short_be(listen_port)); 168 exit(1); 169 } 170 171 printf("Launching PicoTCP echo server\n"); 172 return; 173 174out: 175 fprintf(stderr, "tcpecho expects the following format: tcpecho:listen_port\n"); 176 exit(255); 177} 178/*** END TCP ECHO ***/ 179