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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pico_socket_tcp.c Source File

pico_socket_tcp.c

00001 #include "pico_config.h"
00002 #include "pico_socket.h"
00003 #include "pico_ipv4.h"
00004 #include "pico_ipv6.h"
00005 #include "pico_tcp.h"
00006 #include "pico_socket_tcp.h"
00007 
00008 
00009 static int sockopt_validate_args(struct pico_socket *s,  void *value)
00010 {
00011     if (!value) {
00012         pico_err = PICO_ERR_EINVAL;
00013         return -1;
00014     }
00015 
00016     if (s->proto->proto_number != PICO_PROTO_TCP) {
00017         pico_err = PICO_ERR_EPROTONOSUPPORT;
00018         return -1;
00019     }
00020 
00021     return 0;
00022 }
00023 
00024 int pico_getsockopt_tcp(struct pico_socket *s, int option, void *value)
00025 {
00026     if (sockopt_validate_args(s, value) < 0)
00027         return -1;
00028 
00029 #ifdef PICO_SUPPORT_TCP
00030     if (option == PICO_TCP_NODELAY) {
00031         /* state of the NODELAY option */
00032         *(int *)value = PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_TCPNODELAY);
00033         return 0;
00034     }
00035     else if (option == PICO_SOCKET_OPT_RCVBUF) {
00036         return pico_tcp_get_bufsize_in(s, (uint32_t *)value);
00037     }
00038 
00039     else if (option == PICO_SOCKET_OPT_SNDBUF) {
00040         return pico_tcp_get_bufsize_out(s, (uint32_t *)value);
00041     }
00042 
00043 #endif
00044     return -1;
00045 }
00046 
00047 static void tcp_set_nagle_option(struct pico_socket *s, void *value)
00048 {
00049     int *val = (int*)value;
00050     if (*val > 0) {
00051         dbg("setsockopt: Nagle algorithm disabled.\n");
00052         PICO_SOCKET_SETOPT_EN(s, PICO_SOCKET_OPT_TCPNODELAY);
00053     } else {
00054         dbg("setsockopt: Nagle algorithm enabled.\n");
00055         PICO_SOCKET_SETOPT_DIS(s, PICO_SOCKET_OPT_TCPNODELAY);
00056     }
00057 }
00058 
00059 int pico_setsockopt_tcp(struct pico_socket *s, int option, void *value)
00060 {
00061     if (sockopt_validate_args(s, value) < 0)
00062         return -1;
00063 
00064 #ifdef PICO_SUPPORT_TCP
00065     if (option ==  PICO_TCP_NODELAY) {
00066         tcp_set_nagle_option(s, value);
00067         return 0;
00068     }
00069     else if (option == PICO_SOCKET_OPT_RCVBUF) {
00070         uint32_t *val = (uint32_t*)value;
00071         pico_tcp_set_bufsize_in(s, *val);
00072         return 0;
00073     }
00074     else if (option == PICO_SOCKET_OPT_SNDBUF) {
00075         uint32_t *val = (uint32_t*)value;
00076         pico_tcp_set_bufsize_out(s, *val);
00077         return 0;
00078     }
00079     else if (option == PICO_SOCKET_OPT_KEEPCNT) {
00080         uint32_t *val = (uint32_t*)value;
00081         pico_tcp_set_keepalive_probes(s, *val);
00082         return 0;
00083     }
00084     else if (option == PICO_SOCKET_OPT_KEEPIDLE) {
00085         uint32_t *val = (uint32_t*)value;
00086         pico_tcp_set_keepalive_time(s, *val);
00087         return 0;
00088     }
00089     else if (option == PICO_SOCKET_OPT_KEEPINTVL) {
00090         uint32_t *val = (uint32_t*)value;
00091         pico_tcp_set_keepalive_intvl(s, *val);
00092         return 0;
00093     }
00094     else if (option == PICO_SOCKET_OPT_LINGER) {
00095         uint32_t *val = (uint32_t*)value;
00096         pico_tcp_set_linger(s, *val);
00097         return 0;
00098     }
00099 
00100 #endif
00101     pico_err = PICO_ERR_EINVAL;
00102     return -1;
00103 }
00104 
00105 void pico_socket_tcp_cleanup(struct pico_socket *sock)
00106 {
00107 #ifdef PICO_SUPPORT_TCP
00108     /* for tcp sockets go further and clean the sockets inside queue */
00109     if(is_sock_tcp(sock))
00110         pico_tcp_cleanup_queues(sock);
00111 
00112 #endif
00113 }
00114 
00115 
00116 void pico_socket_tcp_delete(struct pico_socket *s)
00117 {
00118 #ifdef PICO_SUPPORT_TCP
00119     if(s->parent)
00120         s->parent->number_of_pending_conn--;
00121 
00122 #endif
00123 }
00124 
00125 static struct pico_socket *socket_tcp_deliver_ipv4(struct pico_socket *s, struct pico_frame *f)
00126 {
00127     struct pico_socket *found = NULL;
00128     #ifdef PICO_SUPPORT_IPV4
00129     struct pico_ip4 s_local, s_remote, p_src, p_dst;
00130     struct pico_ipv4_hdr *ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
00131     struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
00132     s_local.addr = s->local_addr.ip4.addr;
00133     s_remote.addr = s->remote_addr.ip4.addr;
00134     p_src.addr = ip4hdr->src.addr;
00135     p_dst.addr = ip4hdr->dst.addr;
00136     if ((s->remote_port == tr->sport) && /* remote port check */
00137         (s_remote.addr == p_src.addr) && /* remote addr check */
00138         ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
00139         found = s;
00140         return found;
00141     } else if ((s->remote_port == 0)  && /* not connected... listening */
00142                ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
00143         /* listen socket */
00144         found = s;
00145     }
00146 
00147     #endif
00148     return found;
00149 }
00150 
00151 static struct pico_socket *socket_tcp_deliver_ipv6(struct pico_socket *s, struct pico_frame *f)
00152 {
00153     struct pico_socket *found = NULL;
00154     #ifdef PICO_SUPPORT_IPV6
00155     struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
00156     struct pico_ip6 s_local = {{0}}, s_remote = {{0}}, p_src = {{0}}, p_dst = {{0}};
00157     struct pico_ipv6_hdr *ip6hdr = (struct pico_ipv6_hdr *)(f->net_hdr);
00158     s_local = s->local_addr.ip6;
00159     s_remote = s->remote_addr.ip6;
00160     p_src = ip6hdr->src;
00161     p_dst = ip6hdr->dst;
00162     if ((s->remote_port == tr->sport) &&
00163         (!memcmp(s_remote.addr, p_src.addr, PICO_SIZE_IP6)) &&
00164         ((!memcmp(s_local.addr, PICO_IP6_ANY, PICO_SIZE_IP6)) || (!memcmp(s_local.addr, p_dst.addr, PICO_SIZE_IP6)))) {
00165         found = s;
00166         return found;
00167     } else if ((s->remote_port == 0)  && /* not connected... listening */
00168                ((!memcmp(s_local.addr, PICO_IP6_ANY, PICO_SIZE_IP6)) || (!memcmp(s_local.addr, p_dst.addr, PICO_SIZE_IP6)))) {
00169         /* listen socket */
00170         found = s;
00171     }
00172 
00173     #else
00174     (void) s;
00175     (void) f;
00176     #endif
00177     return found;
00178 }
00179 
00180 static int socket_tcp_do_deliver(struct pico_socket *s, struct pico_frame *f)
00181 {
00182     if (s != NULL) {
00183         pico_tcp_input(s, f);
00184         if ((s->ev_pending) && s->wakeup) {
00185             s->wakeup(s->ev_pending, s);
00186             if(!s->parent)
00187                 s->ev_pending = 0;
00188         }
00189 
00190         return 0;
00191     }
00192 
00193     dbg("TCP SOCKET> Not s.\n");
00194     return -1;
00195 }
00196 
00197 int pico_socket_tcp_deliver(struct pico_sockport *sp, struct pico_frame *f)
00198 {
00199     struct pico_socket *found = NULL;
00200     struct pico_tree_node *index = NULL;
00201     struct pico_tree_node *_tmp;
00202     struct pico_socket *s = NULL;
00203 
00204 
00205     pico_tree_foreach_safe(index, &sp->socks, _tmp){
00206         s = index->keyValue;
00207         /* 4-tuple identification of socket (port-IP) */
00208         if (IS_IPV4(f)) {
00209             found = socket_tcp_deliver_ipv4(s, f);
00210         }
00211 
00212         if (IS_IPV6(f)) {
00213             found = socket_tcp_deliver_ipv6(s, f);
00214         }
00215 
00216         if (found)
00217             break;
00218     } /* FOREACH */
00219 
00220     return socket_tcp_do_deliver(found, f);
00221 }
00222 
00223 struct pico_socket *pico_socket_tcp_open(uint16_t family)
00224 {
00225     struct pico_socket *s = NULL;
00226     (void) family;
00227 #ifdef PICO_SUPPORT_TCP
00228     s = pico_tcp_open(family);
00229     if (!s) {
00230         pico_err = PICO_ERR_ENOMEM;
00231         return NULL;
00232     }
00233 
00234     s->proto = &pico_proto_tcp;
00235     /*check if Nagle enabled */
00236     /*
00237        if (!IS_NAGLE_ENABLED(s))
00238            dbg("ERROR Nagle should be enabled here\n\n");
00239      */
00240 #endif
00241     return s;
00242 }
00243 
00244 int pico_socket_tcp_read(struct pico_socket *s, void *buf, uint32_t len)
00245 {
00246 #ifdef PICO_SUPPORT_TCP
00247     /* check if in shutdown state and if no more data in tcpq_in */
00248     if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) {
00249         pico_err = PICO_ERR_ESHUTDOWN;
00250         return -1;
00251     } else {
00252         return (int)(pico_tcp_read(s, buf, (uint32_t)len));
00253     }
00254 
00255 #else
00256     return 0;
00257 #endif
00258 }
00259 
00260 void transport_flags_update(struct pico_frame *f, struct pico_socket *s)
00261 {
00262 #ifdef PICO_SUPPORT_TCP
00263     if(is_sock_tcp(s))
00264         pico_tcp_flags_update(f, s);
00265 
00266 #endif
00267 }