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