Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
tass
Date:
Thu Jan 28 15:12:00 2016 +0100
Revision:
155:a70f34550c34
Parent:
152:a3d286bf94e5
Adding TCP flag for FIN.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tass 152:a3d286bf94e5 1 #include "pico_config.h"
tass picotcp@tass.be 149:5f4cb161cec3 2 #include "pico_socket.h"
tass picotcp@tass.be 149:5f4cb161cec3 3 #include "pico_ipv4.h"
tass picotcp@tass.be 149:5f4cb161cec3 4 #include "pico_ipv6.h"
tass picotcp@tass.be 149:5f4cb161cec3 5 #include "pico_tcp.h"
tass 152:a3d286bf94e5 6 #include "pico_socket_tcp.h"
tass picotcp@tass.be 149:5f4cb161cec3 7
tass 152:a3d286bf94e5 8
tass 152:a3d286bf94e5 9 static int sockopt_validate_args(struct pico_socket *s, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 10 {
tass picotcp@tass.be 149:5f4cb161cec3 11 if (!value) {
tass picotcp@tass.be 149:5f4cb161cec3 12 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 13 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 14 }
tass picotcp@tass.be 149:5f4cb161cec3 15
tass picotcp@tass.be 149:5f4cb161cec3 16 if (s->proto->proto_number != PICO_PROTO_TCP) {
tass picotcp@tass.be 149:5f4cb161cec3 17 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass picotcp@tass.be 149:5f4cb161cec3 18 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 19 }
tass picotcp@tass.be 149:5f4cb161cec3 20
tass 152:a3d286bf94e5 21 return 0;
tass 152:a3d286bf94e5 22 }
tass 152:a3d286bf94e5 23
tass 152:a3d286bf94e5 24 int pico_getsockopt_tcp(struct pico_socket *s, int option, void *value)
tass 152:a3d286bf94e5 25 {
tass 152:a3d286bf94e5 26 if (sockopt_validate_args(s, value) < 0)
tass 152:a3d286bf94e5 27 return -1;
tass 152:a3d286bf94e5 28
tass picotcp@tass.be 149:5f4cb161cec3 29 #ifdef PICO_SUPPORT_TCP
tass picotcp@tass.be 149:5f4cb161cec3 30 if (option == PICO_TCP_NODELAY) {
tass picotcp@tass.be 149:5f4cb161cec3 31 /* state of the NODELAY option */
tass picotcp@tass.be 149:5f4cb161cec3 32 *(int *)value = PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_TCPNODELAY);
tass picotcp@tass.be 149:5f4cb161cec3 33 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 34 }
tass picotcp@tass.be 149:5f4cb161cec3 35 else if (option == PICO_SOCKET_OPT_RCVBUF) {
tass picotcp@tass.be 149:5f4cb161cec3 36 return pico_tcp_get_bufsize_in(s, (uint32_t *)value);
tass picotcp@tass.be 149:5f4cb161cec3 37 }
tass picotcp@tass.be 149:5f4cb161cec3 38
tass 152:a3d286bf94e5 39 else if (option == PICO_SOCKET_OPT_SNDBUF) {
tass picotcp@tass.be 149:5f4cb161cec3 40 return pico_tcp_get_bufsize_out(s, (uint32_t *)value);
tass picotcp@tass.be 149:5f4cb161cec3 41 }
tass picotcp@tass.be 149:5f4cb161cec3 42
tass picotcp@tass.be 149:5f4cb161cec3 43 #endif
tass picotcp@tass.be 149:5f4cb161cec3 44 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 45 }
tass picotcp@tass.be 149:5f4cb161cec3 46
tass 152:a3d286bf94e5 47 static void tcp_set_nagle_option(struct pico_socket *s, void *value)
tass 152:a3d286bf94e5 48 {
tass 152:a3d286bf94e5 49 int *val = (int*)value;
tass 152:a3d286bf94e5 50 if (*val > 0) {
tass 152:a3d286bf94e5 51 dbg("setsockopt: Nagle algorithm disabled.\n");
tass 152:a3d286bf94e5 52 PICO_SOCKET_SETOPT_EN(s, PICO_SOCKET_OPT_TCPNODELAY);
tass 152:a3d286bf94e5 53 } else {
tass 152:a3d286bf94e5 54 dbg("setsockopt: Nagle algorithm enabled.\n");
tass 152:a3d286bf94e5 55 PICO_SOCKET_SETOPT_DIS(s, PICO_SOCKET_OPT_TCPNODELAY);
tass 152:a3d286bf94e5 56 }
tass 152:a3d286bf94e5 57 }
tass 152:a3d286bf94e5 58
tass picotcp@tass.be 149:5f4cb161cec3 59 int pico_setsockopt_tcp(struct pico_socket *s, int option, void *value)
tass picotcp@tass.be 149:5f4cb161cec3 60 {
tass 152:a3d286bf94e5 61 if (sockopt_validate_args(s, value) < 0)
tass picotcp@tass.be 149:5f4cb161cec3 62 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 63
tass picotcp@tass.be 149:5f4cb161cec3 64 #ifdef PICO_SUPPORT_TCP
tass picotcp@tass.be 149:5f4cb161cec3 65 if (option == PICO_TCP_NODELAY) {
tass 152:a3d286bf94e5 66 tcp_set_nagle_option(s, value);
tass picotcp@tass.be 149:5f4cb161cec3 67 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 68 }
tass 152:a3d286bf94e5 69 else if (option == PICO_SOCKET_OPT_RCVBUF) {
tass picotcp@tass.be 149:5f4cb161cec3 70 uint32_t *val = (uint32_t*)value;
tass picotcp@tass.be 149:5f4cb161cec3 71 pico_tcp_set_bufsize_in(s, *val);
tass picotcp@tass.be 149:5f4cb161cec3 72 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 73 }
tass 152:a3d286bf94e5 74 else if (option == PICO_SOCKET_OPT_SNDBUF) {
tass picotcp@tass.be 149:5f4cb161cec3 75 uint32_t *val = (uint32_t*)value;
tass picotcp@tass.be 149:5f4cb161cec3 76 pico_tcp_set_bufsize_out(s, *val);
tass picotcp@tass.be 149:5f4cb161cec3 77 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 78 }
tass 152:a3d286bf94e5 79 else if (option == PICO_SOCKET_OPT_KEEPCNT) {
tass 152:a3d286bf94e5 80 uint32_t *val = (uint32_t*)value;
tass 152:a3d286bf94e5 81 pico_tcp_set_keepalive_probes(s, *val);
tass 152:a3d286bf94e5 82 return 0;
tass 152:a3d286bf94e5 83 }
tass 152:a3d286bf94e5 84 else if (option == PICO_SOCKET_OPT_KEEPIDLE) {
tass 152:a3d286bf94e5 85 uint32_t *val = (uint32_t*)value;
tass 152:a3d286bf94e5 86 pico_tcp_set_keepalive_time(s, *val);
tass 152:a3d286bf94e5 87 return 0;
tass 152:a3d286bf94e5 88 }
tass 152:a3d286bf94e5 89 else if (option == PICO_SOCKET_OPT_KEEPINTVL) {
tass 152:a3d286bf94e5 90 uint32_t *val = (uint32_t*)value;
tass 152:a3d286bf94e5 91 pico_tcp_set_keepalive_intvl(s, *val);
tass 152:a3d286bf94e5 92 return 0;
tass 152:a3d286bf94e5 93 }
tass 152:a3d286bf94e5 94 else if (option == PICO_SOCKET_OPT_LINGER) {
tass 152:a3d286bf94e5 95 uint32_t *val = (uint32_t*)value;
tass 152:a3d286bf94e5 96 pico_tcp_set_linger(s, *val);
tass 152:a3d286bf94e5 97 return 0;
tass 152:a3d286bf94e5 98 }
tass picotcp@tass.be 149:5f4cb161cec3 99
tass picotcp@tass.be 149:5f4cb161cec3 100 #endif
tass picotcp@tass.be 149:5f4cb161cec3 101 pico_err = PICO_ERR_EINVAL;
tass picotcp@tass.be 149:5f4cb161cec3 102 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 103 }
tass picotcp@tass.be 149:5f4cb161cec3 104
tass picotcp@tass.be 149:5f4cb161cec3 105 void pico_socket_tcp_cleanup(struct pico_socket *sock)
tass picotcp@tass.be 149:5f4cb161cec3 106 {
tass picotcp@tass.be 149:5f4cb161cec3 107 #ifdef PICO_SUPPORT_TCP
tass picotcp@tass.be 149:5f4cb161cec3 108 /* for tcp sockets go further and clean the sockets inside queue */
tass 152:a3d286bf94e5 109 if(is_sock_tcp(sock))
tass picotcp@tass.be 149:5f4cb161cec3 110 pico_tcp_cleanup_queues(sock);
tass picotcp@tass.be 149:5f4cb161cec3 111
tass picotcp@tass.be 149:5f4cb161cec3 112 #endif
tass picotcp@tass.be 149:5f4cb161cec3 113 }
tass picotcp@tass.be 149:5f4cb161cec3 114
tass picotcp@tass.be 149:5f4cb161cec3 115
tass picotcp@tass.be 149:5f4cb161cec3 116 void pico_socket_tcp_delete(struct pico_socket *s)
tass picotcp@tass.be 149:5f4cb161cec3 117 {
tass picotcp@tass.be 149:5f4cb161cec3 118 #ifdef PICO_SUPPORT_TCP
tass picotcp@tass.be 149:5f4cb161cec3 119 if(s->parent)
tass picotcp@tass.be 149:5f4cb161cec3 120 s->parent->number_of_pending_conn--;
tass picotcp@tass.be 149:5f4cb161cec3 121
tass picotcp@tass.be 149:5f4cb161cec3 122 #endif
tass picotcp@tass.be 149:5f4cb161cec3 123 }
tass picotcp@tass.be 149:5f4cb161cec3 124
tass 152:a3d286bf94e5 125 static struct pico_socket *socket_tcp_deliver_ipv4(struct pico_socket *s, struct pico_frame *f)
tass 152:a3d286bf94e5 126 {
tass 152:a3d286bf94e5 127 struct pico_socket *found = NULL;
tass 152:a3d286bf94e5 128 #ifdef PICO_SUPPORT_IPV4
tass 152:a3d286bf94e5 129 struct pico_ip4 s_local, s_remote, p_src, p_dst;
tass 152:a3d286bf94e5 130 struct pico_ipv4_hdr *ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
tass 152:a3d286bf94e5 131 struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
tass 152:a3d286bf94e5 132 s_local.addr = s->local_addr.ip4.addr;
tass 152:a3d286bf94e5 133 s_remote.addr = s->remote_addr.ip4.addr;
tass 152:a3d286bf94e5 134 p_src.addr = ip4hdr->src.addr;
tass 152:a3d286bf94e5 135 p_dst.addr = ip4hdr->dst.addr;
tass 152:a3d286bf94e5 136 if ((s->remote_port == tr->sport) && /* remote port check */
tass 152:a3d286bf94e5 137 (s_remote.addr == p_src.addr) && /* remote addr check */
tass 152:a3d286bf94e5 138 ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
tass 152:a3d286bf94e5 139 found = s;
tass 152:a3d286bf94e5 140 return found;
tass 152:a3d286bf94e5 141 } else if ((s->remote_port == 0) && /* not connected... listening */
tass 152:a3d286bf94e5 142 ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
tass 152:a3d286bf94e5 143 /* listen socket */
tass 152:a3d286bf94e5 144 found = s;
tass 152:a3d286bf94e5 145 }
tass 152:a3d286bf94e5 146
tass 152:a3d286bf94e5 147 #endif
tass 152:a3d286bf94e5 148 return found;
tass 152:a3d286bf94e5 149 }
tass 152:a3d286bf94e5 150
tass 152:a3d286bf94e5 151 static struct pico_socket *socket_tcp_deliver_ipv6(struct pico_socket *s, struct pico_frame *f)
tass 152:a3d286bf94e5 152 {
tass 152:a3d286bf94e5 153 struct pico_socket *found = NULL;
tass 152:a3d286bf94e5 154 #ifdef PICO_SUPPORT_IPV6
tass 152:a3d286bf94e5 155 struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
tass 152:a3d286bf94e5 156 struct pico_ip6 s_local = {{0}}, s_remote = {{0}}, p_src = {{0}}, p_dst = {{0}};
tass 152:a3d286bf94e5 157 struct pico_ipv6_hdr *ip6hdr = (struct pico_ipv6_hdr *)(f->net_hdr);
tass 152:a3d286bf94e5 158 s_local = s->local_addr.ip6;
tass 152:a3d286bf94e5 159 s_remote = s->remote_addr.ip6;
tass 152:a3d286bf94e5 160 p_src = ip6hdr->src;
tass 152:a3d286bf94e5 161 p_dst = ip6hdr->dst;
tass 152:a3d286bf94e5 162 if ((s->remote_port == tr->sport) &&
tass 152:a3d286bf94e5 163 (!memcmp(s_remote.addr, p_src.addr, PICO_SIZE_IP6)) &&
tass 152:a3d286bf94e5 164 ((!memcmp(s_local.addr, PICO_IP6_ANY, PICO_SIZE_IP6)) || (!memcmp(s_local.addr, p_dst.addr, PICO_SIZE_IP6)))) {
tass 152:a3d286bf94e5 165 found = s;
tass 152:a3d286bf94e5 166 return found;
tass 152:a3d286bf94e5 167 } else if ((s->remote_port == 0) && /* not connected... listening */
tass 152:a3d286bf94e5 168 ((!memcmp(s_local.addr, PICO_IP6_ANY, PICO_SIZE_IP6)) || (!memcmp(s_local.addr, p_dst.addr, PICO_SIZE_IP6)))) {
tass 152:a3d286bf94e5 169 /* listen socket */
tass 152:a3d286bf94e5 170 found = s;
tass 152:a3d286bf94e5 171 }
tass 152:a3d286bf94e5 172
tass 152:a3d286bf94e5 173 #else
tass 152:a3d286bf94e5 174 (void) s;
tass 152:a3d286bf94e5 175 (void) f;
tass 152:a3d286bf94e5 176 #endif
tass 152:a3d286bf94e5 177 return found;
tass 152:a3d286bf94e5 178 }
tass 152:a3d286bf94e5 179
tass 152:a3d286bf94e5 180 static int socket_tcp_do_deliver(struct pico_socket *s, struct pico_frame *f)
tass 152:a3d286bf94e5 181 {
tass 152:a3d286bf94e5 182 if (s != NULL) {
tass 152:a3d286bf94e5 183 pico_tcp_input(s, f);
tass 152:a3d286bf94e5 184 if ((s->ev_pending) && s->wakeup) {
tass 152:a3d286bf94e5 185 s->wakeup(s->ev_pending, s);
tass 152:a3d286bf94e5 186 if(!s->parent)
tass 152:a3d286bf94e5 187 s->ev_pending = 0;
tass 152:a3d286bf94e5 188 }
tass 152:a3d286bf94e5 189
tass 152:a3d286bf94e5 190 return 0;
tass 152:a3d286bf94e5 191 }
tass 152:a3d286bf94e5 192
tass 152:a3d286bf94e5 193 dbg("TCP SOCKET> Not s.\n");
tass 152:a3d286bf94e5 194 return -1;
tass 152:a3d286bf94e5 195 }
tass 152:a3d286bf94e5 196
tass picotcp@tass.be 149:5f4cb161cec3 197 int pico_socket_tcp_deliver(struct pico_sockport *sp, struct pico_frame *f)
tass picotcp@tass.be 149:5f4cb161cec3 198 {
tass picotcp@tass.be 149:5f4cb161cec3 199 struct pico_socket *found = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 200 struct pico_tree_node *index = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 201 struct pico_tree_node *_tmp;
tass picotcp@tass.be 149:5f4cb161cec3 202 struct pico_socket *s = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 203
tass picotcp@tass.be 149:5f4cb161cec3 204
tass picotcp@tass.be 149:5f4cb161cec3 205 pico_tree_foreach_safe(index, &sp->socks, _tmp){
tass picotcp@tass.be 149:5f4cb161cec3 206 s = index->keyValue;
tass picotcp@tass.be 149:5f4cb161cec3 207 /* 4-tuple identification of socket (port-IP) */
tass picotcp@tass.be 149:5f4cb161cec3 208 if (IS_IPV4(f)) {
tass 152:a3d286bf94e5 209 found = socket_tcp_deliver_ipv4(s, f);
tass picotcp@tass.be 149:5f4cb161cec3 210 }
tass picotcp@tass.be 149:5f4cb161cec3 211
tass picotcp@tass.be 149:5f4cb161cec3 212 if (IS_IPV6(f)) {
tass 152:a3d286bf94e5 213 found = socket_tcp_deliver_ipv6(s, f);
tass picotcp@tass.be 149:5f4cb161cec3 214 }
tass picotcp@tass.be 149:5f4cb161cec3 215
tass 152:a3d286bf94e5 216 if (found)
tass 152:a3d286bf94e5 217 break;
tass picotcp@tass.be 149:5f4cb161cec3 218 } /* FOREACH */
tass picotcp@tass.be 149:5f4cb161cec3 219
tass 152:a3d286bf94e5 220 return socket_tcp_do_deliver(found, f);
tass picotcp@tass.be 149:5f4cb161cec3 221 }
tass picotcp@tass.be 149:5f4cb161cec3 222
tass picotcp@tass.be 149:5f4cb161cec3 223 struct pico_socket *pico_socket_tcp_open(uint16_t family)
tass picotcp@tass.be 149:5f4cb161cec3 224 {
tass picotcp@tass.be 149:5f4cb161cec3 225 struct pico_socket *s = NULL;
tass picotcp@tass.be 149:5f4cb161cec3 226 (void) family;
tass picotcp@tass.be 149:5f4cb161cec3 227 #ifdef PICO_SUPPORT_TCP
tass picotcp@tass.be 149:5f4cb161cec3 228 s = pico_tcp_open(family);
tass picotcp@tass.be 149:5f4cb161cec3 229 if (!s) {
tass picotcp@tass.be 149:5f4cb161cec3 230 pico_err = PICO_ERR_ENOMEM;
tass picotcp@tass.be 149:5f4cb161cec3 231 return NULL;
tass picotcp@tass.be 149:5f4cb161cec3 232 }
tass picotcp@tass.be 149:5f4cb161cec3 233
tass picotcp@tass.be 149:5f4cb161cec3 234 s->proto = &pico_proto_tcp;
tass picotcp@tass.be 149:5f4cb161cec3 235 /*check if Nagle enabled */
tass picotcp@tass.be 149:5f4cb161cec3 236 /*
tass picotcp@tass.be 149:5f4cb161cec3 237 if (!IS_NAGLE_ENABLED(s))
tass picotcp@tass.be 149:5f4cb161cec3 238 dbg("ERROR Nagle should be enabled here\n\n");
tass picotcp@tass.be 149:5f4cb161cec3 239 */
tass picotcp@tass.be 149:5f4cb161cec3 240 #endif
tass picotcp@tass.be 149:5f4cb161cec3 241 return s;
tass picotcp@tass.be 149:5f4cb161cec3 242 }
tass picotcp@tass.be 149:5f4cb161cec3 243
tass picotcp@tass.be 149:5f4cb161cec3 244 int pico_socket_tcp_read(struct pico_socket *s, void *buf, uint32_t len)
tass picotcp@tass.be 149:5f4cb161cec3 245 {
tass picotcp@tass.be 149:5f4cb161cec3 246 #ifdef PICO_SUPPORT_TCP
tass picotcp@tass.be 149:5f4cb161cec3 247 /* check if in shutdown state and if no more data in tcpq_in */
tass picotcp@tass.be 149:5f4cb161cec3 248 if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) {
tass picotcp@tass.be 149:5f4cb161cec3 249 pico_err = PICO_ERR_ESHUTDOWN;
tass picotcp@tass.be 149:5f4cb161cec3 250 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 251 } else {
tass picotcp@tass.be 149:5f4cb161cec3 252 return (int)(pico_tcp_read(s, buf, (uint32_t)len));
tass picotcp@tass.be 149:5f4cb161cec3 253 }
tass picotcp@tass.be 149:5f4cb161cec3 254
tass picotcp@tass.be 150:551effcf6a39 255 #else
tass picotcp@tass.be 150:551effcf6a39 256 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 257 #endif
tass picotcp@tass.be 149:5f4cb161cec3 258 }
tass picotcp@tass.be 149:5f4cb161cec3 259
tass picotcp@tass.be 149:5f4cb161cec3 260 void transport_flags_update(struct pico_frame *f, struct pico_socket *s)
tass picotcp@tass.be 149:5f4cb161cec3 261 {
tass picotcp@tass.be 149:5f4cb161cec3 262 #ifdef PICO_SUPPORT_TCP
tass 152:a3d286bf94e5 263 if(is_sock_tcp(s))
tass 152:a3d286bf94e5 264 pico_tcp_flags_update(f, s);
tass 152:a3d286bf94e5 265
tass picotcp@tass.be 149:5f4cb161cec3 266 #endif
tass picotcp@tass.be 149:5f4cb161cec3 267 }