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:
Fri May 17 12:09:59 2013 +0000
Revision:
1:cfe8984a32b4
Parent:
libraries/picotcp/stack/pico_socket.c@0:d7f2341ab245
Update for smaller SOCKETQ

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 0:d7f2341ab245 1 /*********************************************************************
daniele 0:d7f2341ab245 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 0:d7f2341ab245 3 See LICENSE and COPYING for usage.
daniele 0:d7f2341ab245 4
daniele 0:d7f2341ab245 5
daniele 0:d7f2341ab245 6 Authors: Daniele Lacamera
daniele 0:d7f2341ab245 7 *********************************************************************/
daniele 0:d7f2341ab245 8
daniele 0:d7f2341ab245 9
daniele 0:d7f2341ab245 10 #include "pico_config.h"
daniele 0:d7f2341ab245 11 #include "pico_queue.h"
daniele 0:d7f2341ab245 12 #include "pico_socket.h"
daniele 0:d7f2341ab245 13 #include "pico_ipv4.h"
daniele 0:d7f2341ab245 14 #include "pico_ipv6.h"
daniele 0:d7f2341ab245 15 #include "pico_udp.h"
daniele 0:d7f2341ab245 16 #include "pico_tcp.h"
daniele 0:d7f2341ab245 17 #include "pico_stack.h"
daniele 0:d7f2341ab245 18 #include "pico_icmp4.h"
daniele 0:d7f2341ab245 19 #include "pico_nat.h"
daniele 0:d7f2341ab245 20 #include "pico_tree.h"
daniele 0:d7f2341ab245 21 #include "pico_device.h"
daniele 0:d7f2341ab245 22
daniele 0:d7f2341ab245 23 #if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6)
daniele 0:d7f2341ab245 24 #if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP)
daniele 0:d7f2341ab245 25
daniele 0:d7f2341ab245 26
daniele 0:d7f2341ab245 27 #define PROTO(s) ((s)->proto->proto_number)
daniele 0:d7f2341ab245 28
daniele 0:d7f2341ab245 29 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 30 # define IS_NAGLE_ENABLED(s) (s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY))
daniele 0:d7f2341ab245 31 #endif
daniele 0:d7f2341ab245 32
daniele 0:d7f2341ab245 33 #define PICO_SOCKET_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */
daniele 0:d7f2341ab245 34
daniele 0:d7f2341ab245 35 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 36 # define IS_SOCK_IPV4(s) ((s->net == &pico_proto_ipv4))
daniele 0:d7f2341ab245 37 #else
daniele 0:d7f2341ab245 38 # define IS_SOCK_IPV4(s) (0)
daniele 0:d7f2341ab245 39 #endif
daniele 0:d7f2341ab245 40
daniele 0:d7f2341ab245 41 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 42 # define IS_SOCK_IPV6(s) ((s->net == &pico_proto_ipv6))
daniele 0:d7f2341ab245 43 #else
daniele 0:d7f2341ab245 44 # define IS_SOCK_IPV6(s) (0)
daniele 0:d7f2341ab245 45 #endif
daniele 0:d7f2341ab245 46
daniele 0:d7f2341ab245 47 #ifdef PICO_SUPPORT_IPFRAG
daniele 0:d7f2341ab245 48 # define frag_dbg(...) do{}while(0)
daniele 0:d7f2341ab245 49 #endif
daniele 0:d7f2341ab245 50
daniele 0:d7f2341ab245 51 static struct pico_sockport *sp_udp = NULL ,*sp_tcp = NULL;
daniele 0:d7f2341ab245 52
daniele 0:d7f2341ab245 53 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len);
daniele 0:d7f2341ab245 54
daniele 0:d7f2341ab245 55 static int socket_cmp(void * ka, void * kb)
daniele 0:d7f2341ab245 56 {
daniele 0:d7f2341ab245 57 struct pico_socket *a = ka, *b = kb;
daniele 0:d7f2341ab245 58 int a_is_ip6 = is_sock_ipv6(a);
daniele 0:d7f2341ab245 59 int b_is_ip6 = is_sock_ipv6(b);
daniele 0:d7f2341ab245 60
daniele 0:d7f2341ab245 61 int diff;
daniele 0:d7f2341ab245 62
daniele 0:d7f2341ab245 63 /* First, order by network ver */
daniele 0:d7f2341ab245 64 if (a_is_ip6 < b_is_ip6)
daniele 0:d7f2341ab245 65 return -1;
daniele 0:d7f2341ab245 66 if (a_is_ip6 > b_is_ip6)
daniele 0:d7f2341ab245 67 return 1;
daniele 0:d7f2341ab245 68
daniele 0:d7f2341ab245 69 /* If either socket is PICO_IPV4_INADDR_ANY mode, skip local address comparison */
daniele 0:d7f2341ab245 70
daniele 0:d7f2341ab245 71 /* At this point, sort by local host */
daniele 0:d7f2341ab245 72
daniele 0:d7f2341ab245 73 if (0) {
daniele 0:d7f2341ab245 74 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 75 } else if (a_is_ip6) {
daniele 0:d7f2341ab245 76 if ((memcmp(a->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6)==0) || memcmp((b->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0))
daniele 0:d7f2341ab245 77 diff = 0;
daniele 0:d7f2341ab245 78 else
daniele 0:d7f2341ab245 79 diff = memcmp(a->local_addr.ip6.addr, b->local_addr.ip6.addr, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 80 #endif
daniele 0:d7f2341ab245 81 } else {
daniele 0:d7f2341ab245 82 if ((a->local_addr.ip4.addr == PICO_IP4_ANY) || (b->local_addr.ip4.addr == PICO_IP4_ANY))
daniele 0:d7f2341ab245 83 diff = 0;
daniele 0:d7f2341ab245 84 else
daniele 0:d7f2341ab245 85 diff = a->local_addr.ip4.addr - b->local_addr.ip4.addr;
daniele 0:d7f2341ab245 86 }
daniele 0:d7f2341ab245 87
daniele 0:d7f2341ab245 88 if (diff)
daniele 0:d7f2341ab245 89 return diff;
daniele 0:d7f2341ab245 90
daniele 0:d7f2341ab245 91
daniele 0:d7f2341ab245 92 /* Sort by remote host */
daniele 0:d7f2341ab245 93 if (a_is_ip6)
daniele 0:d7f2341ab245 94 diff = memcmp(a->remote_addr.ip6.addr, b->remote_addr.ip6.addr, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 95 else
daniele 0:d7f2341ab245 96 diff = a->remote_addr.ip4.addr - b->remote_addr.ip4.addr;
daniele 0:d7f2341ab245 97
daniele 0:d7f2341ab245 98 if (diff)
daniele 0:d7f2341ab245 99 return diff;
daniele 0:d7f2341ab245 100
daniele 0:d7f2341ab245 101 /* And finally by remote port. The two sockets are coincident if the quad is the same. */
daniele 0:d7f2341ab245 102 return b->remote_port - a->remote_port;
daniele 0:d7f2341ab245 103 }
daniele 0:d7f2341ab245 104
daniele 0:d7f2341ab245 105 struct pico_sockport
daniele 0:d7f2341ab245 106 {
daniele 0:d7f2341ab245 107 struct pico_tree socks; // how you make the connection ?
daniele 0:d7f2341ab245 108 uint16_t number;
daniele 0:d7f2341ab245 109 uint16_t proto;
daniele 0:d7f2341ab245 110 };
daniele 0:d7f2341ab245 111
daniele 0:d7f2341ab245 112 #define INIT_SOCKPORT { {&LEAF , socket_cmp}, 0, 0 }
daniele 0:d7f2341ab245 113
daniele 0:d7f2341ab245 114 int sockport_cmp(void * ka, void * kb)
daniele 0:d7f2341ab245 115 {
daniele 0:d7f2341ab245 116 struct pico_sockport *a = ka, *b = kb;
daniele 0:d7f2341ab245 117 if (a->number < b->number)
daniele 0:d7f2341ab245 118 return -1;
daniele 0:d7f2341ab245 119 if (a->number > b->number)
daniele 0:d7f2341ab245 120 return 1;
daniele 0:d7f2341ab245 121 return 0;
daniele 0:d7f2341ab245 122 }
daniele 0:d7f2341ab245 123
daniele 0:d7f2341ab245 124 PICO_TREE_DECLARE(UDPTable,sockport_cmp);
daniele 0:d7f2341ab245 125 PICO_TREE_DECLARE(TCPTable,sockport_cmp);
daniele 0:d7f2341ab245 126
daniele 0:d7f2341ab245 127 static struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port)
daniele 0:d7f2341ab245 128 {
daniele 0:d7f2341ab245 129 struct pico_sockport test = INIT_SOCKPORT;
daniele 0:d7f2341ab245 130 test.number = port;
daniele 0:d7f2341ab245 131
daniele 0:d7f2341ab245 132 if (proto == PICO_PROTO_UDP)
daniele 0:d7f2341ab245 133 return pico_tree_findKey(&UDPTable,&test);
daniele 0:d7f2341ab245 134
daniele 0:d7f2341ab245 135 else if (proto == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 136 return pico_tree_findKey(&TCPTable,&test);
daniele 0:d7f2341ab245 137
daniele 0:d7f2341ab245 138 else return NULL;
daniele 0:d7f2341ab245 139 }
daniele 0:d7f2341ab245 140
daniele 0:d7f2341ab245 141 int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net)
daniele 0:d7f2341ab245 142 {
daniele 0:d7f2341ab245 143 struct pico_sockport *sp;
daniele 0:d7f2341ab245 144 struct pico_ip4 ip;
daniele 0:d7f2341ab245 145 sp = pico_get_sockport(proto, port);
daniele 0:d7f2341ab245 146
daniele 0:d7f2341ab245 147 if (!net)
daniele 0:d7f2341ab245 148 net = &pico_proto_ipv4;
daniele 0:d7f2341ab245 149
daniele 0:d7f2341ab245 150 /** IPv6 (wip) ***/
daniele 0:d7f2341ab245 151 if (net != &pico_proto_ipv4) {
daniele 0:d7f2341ab245 152 dbg("IPV6!!!!!\n");
daniele 0:d7f2341ab245 153 return (!sp);
daniele 0:d7f2341ab245 154 }
daniele 0:d7f2341ab245 155
daniele 0:d7f2341ab245 156 /* IPv4 */
daniele 0:d7f2341ab245 157 #ifdef PICO_SUPPORT_NAT
daniele 0:d7f2341ab245 158 if (pico_ipv4_nat_find(port,NULL, 0,proto) == 0) {
daniele 0:d7f2341ab245 159 dbg("In use by nat....\n");
daniele 0:d7f2341ab245 160 return 0;
daniele 0:d7f2341ab245 161 }
daniele 0:d7f2341ab245 162 #endif
daniele 0:d7f2341ab245 163 if (addr)
daniele 0:d7f2341ab245 164 ip.addr = ((struct pico_ip4 *)addr)->addr;
daniele 0:d7f2341ab245 165 else
daniele 0:d7f2341ab245 166 ip.addr = PICO_IPV4_INADDR_ANY;
daniele 0:d7f2341ab245 167
daniele 0:d7f2341ab245 168 if (ip.addr == PICO_IPV4_INADDR_ANY) {
daniele 0:d7f2341ab245 169 if (!sp) return 1;
daniele 0:d7f2341ab245 170 else {
daniele 0:d7f2341ab245 171 dbg("In use, and asked for ANY\n");
daniele 0:d7f2341ab245 172 return 0;
daniele 0:d7f2341ab245 173 }
daniele 0:d7f2341ab245 174 }
daniele 0:d7f2341ab245 175 if (sp) {
daniele 0:d7f2341ab245 176 struct pico_ip4 *s_local;
daniele 0:d7f2341ab245 177 struct pico_tree_node *idx;
daniele 0:d7f2341ab245 178 struct pico_socket *s;
daniele 0:d7f2341ab245 179 pico_tree_foreach(idx, &sp->socks) {
daniele 0:d7f2341ab245 180 s = idx->keyValue;
daniele 0:d7f2341ab245 181 if (s->net == &pico_proto_ipv4) {
daniele 0:d7f2341ab245 182 s_local = (struct pico_ip4*) &s->local_addr;
daniele 0:d7f2341ab245 183 if ((s_local->addr == PICO_IPV4_INADDR_ANY) || (s_local->addr == ip.addr))
daniele 0:d7f2341ab245 184 return 0;
daniele 0:d7f2341ab245 185 }
daniele 0:d7f2341ab245 186 }
daniele 0:d7f2341ab245 187 }
daniele 0:d7f2341ab245 188 return 1;
daniele 0:d7f2341ab245 189 }
daniele 0:d7f2341ab245 190
daniele 0:d7f2341ab245 191 static int pico_check_socket(struct pico_socket *s)
daniele 0:d7f2341ab245 192 {
daniele 0:d7f2341ab245 193 struct pico_sockport *test;
daniele 0:d7f2341ab245 194 struct pico_socket *found;
daniele 0:d7f2341ab245 195 struct pico_tree_node * index;
daniele 0:d7f2341ab245 196
daniele 0:d7f2341ab245 197 test = pico_get_sockport(PROTO(s), s->local_port);
daniele 0:d7f2341ab245 198
daniele 0:d7f2341ab245 199 if (!test) {
daniele 0:d7f2341ab245 200 return -1;
daniele 0:d7f2341ab245 201 }
daniele 0:d7f2341ab245 202
daniele 0:d7f2341ab245 203 pico_tree_foreach(index,&test->socks){
daniele 0:d7f2341ab245 204 found = index->keyValue;
daniele 0:d7f2341ab245 205 if (s == found) {
daniele 0:d7f2341ab245 206 return 0;
daniele 0:d7f2341ab245 207 }
daniele 0:d7f2341ab245 208 }
daniele 0:d7f2341ab245 209
daniele 0:d7f2341ab245 210 return -1;
daniele 0:d7f2341ab245 211 }
daniele 0:d7f2341ab245 212
daniele 0:d7f2341ab245 213
daniele 0:d7f2341ab245 214 int pico_socket_add(struct pico_socket *s)
daniele 0:d7f2341ab245 215 {
daniele 0:d7f2341ab245 216 struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
daniele 0:d7f2341ab245 217 if (!sp) {
daniele 0:d7f2341ab245 218 //dbg("Creating sockport..%04x\n", s->local_port); /* In comment due to spam during test */
daniele 0:d7f2341ab245 219 sp = pico_zalloc(sizeof(struct pico_sockport));
daniele 0:d7f2341ab245 220
daniele 0:d7f2341ab245 221 if (!sp) {
daniele 0:d7f2341ab245 222 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 223 return -1;
daniele 0:d7f2341ab245 224 }
daniele 0:d7f2341ab245 225 sp->proto = PROTO(s);
daniele 0:d7f2341ab245 226 sp->number = s->local_port;
daniele 0:d7f2341ab245 227 sp->socks.root = &LEAF;
daniele 0:d7f2341ab245 228 sp->socks.compare = socket_cmp;
daniele 0:d7f2341ab245 229
daniele 0:d7f2341ab245 230 if (PROTO(s) == PICO_PROTO_UDP)
daniele 0:d7f2341ab245 231 {
daniele 0:d7f2341ab245 232 pico_tree_insert(&UDPTable,sp);
daniele 0:d7f2341ab245 233 }
daniele 0:d7f2341ab245 234 else if (PROTO(s) == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 235 {
daniele 0:d7f2341ab245 236 pico_tree_insert(&TCPTable,sp);
daniele 0:d7f2341ab245 237 }
daniele 0:d7f2341ab245 238 }
daniele 0:d7f2341ab245 239
daniele 0:d7f2341ab245 240 pico_tree_insert(&sp->socks,s);
daniele 0:d7f2341ab245 241 s->state |= PICO_SOCKET_STATE_BOUND;
daniele 0:d7f2341ab245 242
daniele 0:d7f2341ab245 243 #if DEBUG_SOCKET_TREE
daniele 0:d7f2341ab245 244 {
daniele 0:d7f2341ab245 245 struct pico_tree_node * index;
daniele 0:d7f2341ab245 246 //RB_FOREACH(s, socket_tree, &sp->socks) {
daniele 0:d7f2341ab245 247 pico_tree_foreach(index,&sp->socks){
daniele 0:d7f2341ab245 248 s = index->keyValue;
daniele 0:d7f2341ab245 249 dbg(">>>> List Socket lc=%hu rm=%hu\n", short_be(s->local_port), short_be(s->remote_port));
daniele 0:d7f2341ab245 250 }
daniele 0:d7f2341ab245 251
daniele 0:d7f2341ab245 252 }
daniele 0:d7f2341ab245 253 #endif
daniele 0:d7f2341ab245 254 return 0;
daniele 0:d7f2341ab245 255 }
daniele 0:d7f2341ab245 256
daniele 0:d7f2341ab245 257 static void socket_garbage_collect(unsigned long now, void *arg)
daniele 0:d7f2341ab245 258 {
daniele 0:d7f2341ab245 259 struct pico_socket *s = (struct pico_socket *) arg;
daniele 0:d7f2341ab245 260 pico_free(s);
daniele 0:d7f2341ab245 261 }
daniele 0:d7f2341ab245 262
daniele 0:d7f2341ab245 263 int pico_socket_del(struct pico_socket *s)
daniele 0:d7f2341ab245 264 {
daniele 0:d7f2341ab245 265 struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
daniele 0:d7f2341ab245 266
daniele 0:d7f2341ab245 267 if (!sp) {
daniele 0:d7f2341ab245 268 pico_err = PICO_ERR_ENXIO;
daniele 0:d7f2341ab245 269 return -1;
daniele 0:d7f2341ab245 270 }
daniele 0:d7f2341ab245 271 pico_tree_delete(&sp->socks,s);
daniele 0:d7f2341ab245 272
daniele 0:d7f2341ab245 273 if(pico_tree_empty(&sp->socks)){
daniele 0:d7f2341ab245 274 if (PROTO(s) == PICO_PROTO_UDP)
daniele 0:d7f2341ab245 275 {
daniele 0:d7f2341ab245 276 pico_tree_delete(&UDPTable,sp);
daniele 0:d7f2341ab245 277 }
daniele 0:d7f2341ab245 278 else if (PROTO(s) == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 279 {
daniele 0:d7f2341ab245 280 pico_tree_delete(&TCPTable,sp);
daniele 0:d7f2341ab245 281 }
daniele 0:d7f2341ab245 282
daniele 0:d7f2341ab245 283 if(sp_tcp == sp) sp_tcp = NULL;
daniele 0:d7f2341ab245 284
daniele 0:d7f2341ab245 285 if(sp_udp == sp) sp_udp = NULL;
daniele 0:d7f2341ab245 286
daniele 0:d7f2341ab245 287 pico_free(sp);
daniele 0:d7f2341ab245 288
daniele 0:d7f2341ab245 289 }
daniele 0:d7f2341ab245 290
daniele 0:d7f2341ab245 291 s->state = PICO_SOCKET_STATE_CLOSED;
daniele 0:d7f2341ab245 292 pico_timer_add(3000, socket_garbage_collect, s);
daniele 0:d7f2341ab245 293
daniele 0:d7f2341ab245 294
daniele 0:d7f2341ab245 295 return 0;
daniele 0:d7f2341ab245 296 }
daniele 0:d7f2341ab245 297
daniele 0:d7f2341ab245 298 static int pico_socket_alter_state(struct pico_socket *s, uint16_t more_states, uint16_t less_states, uint16_t tcp_state)
daniele 0:d7f2341ab245 299 {
daniele 0:d7f2341ab245 300 struct pico_sockport *sp;
daniele 0:d7f2341ab245 301 if (more_states & PICO_SOCKET_STATE_BOUND)
daniele 0:d7f2341ab245 302 return pico_socket_add(s);
daniele 0:d7f2341ab245 303
daniele 0:d7f2341ab245 304 if (less_states & PICO_SOCKET_STATE_BOUND)
daniele 0:d7f2341ab245 305 return pico_socket_del(s);
daniele 0:d7f2341ab245 306
daniele 0:d7f2341ab245 307 sp = pico_get_sockport(PROTO(s), s->local_port);
daniele 0:d7f2341ab245 308 if (!sp) {
daniele 0:d7f2341ab245 309 pico_err = PICO_ERR_ENXIO;
daniele 0:d7f2341ab245 310 return -1;
daniele 0:d7f2341ab245 311 }
daniele 0:d7f2341ab245 312
daniele 0:d7f2341ab245 313 s->state |= more_states;
daniele 0:d7f2341ab245 314 s->state &= (~less_states);
daniele 0:d7f2341ab245 315 if (tcp_state) {
daniele 0:d7f2341ab245 316 s->state &= 0x00FF;
daniele 0:d7f2341ab245 317 s->state |= tcp_state;
daniele 0:d7f2341ab245 318 }
daniele 0:d7f2341ab245 319
daniele 0:d7f2341ab245 320 return 0;
daniele 0:d7f2341ab245 321 }
daniele 0:d7f2341ab245 322
daniele 0:d7f2341ab245 323 static int pico_socket_deliver(struct pico_protocol *p, struct pico_frame *f, uint16_t localport)
daniele 0:d7f2341ab245 324 {
daniele 0:d7f2341ab245 325 struct pico_frame *cpy = NULL;
daniele 0:d7f2341ab245 326 struct pico_sockport *sp = NULL;
daniele 0:d7f2341ab245 327 struct pico_socket *s = NULL, *found = NULL;
daniele 0:d7f2341ab245 328 struct pico_tree_node *index = NULL;
daniele 0:d7f2341ab245 329 struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
daniele 0:d7f2341ab245 330 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 331 struct pico_ipv4_hdr *ip4hdr;
daniele 0:d7f2341ab245 332 #endif
daniele 0:d7f2341ab245 333 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 334 struct pico_ipv6_hdr *ip6hdr;
daniele 0:d7f2341ab245 335 #endif
daniele 0:d7f2341ab245 336
daniele 0:d7f2341ab245 337 if (!tr)
daniele 0:d7f2341ab245 338 return -1;
daniele 0:d7f2341ab245 339
daniele 0:d7f2341ab245 340 sp = pico_get_sockport(p->proto_number, localport);
daniele 0:d7f2341ab245 341
daniele 0:d7f2341ab245 342 if (!sp) {
daniele 0:d7f2341ab245 343 dbg("No such port %d\n",short_be(localport));
daniele 0:d7f2341ab245 344 return -1;
daniele 0:d7f2341ab245 345 }
daniele 0:d7f2341ab245 346
daniele 0:d7f2341ab245 347 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 348 if (p->proto_number == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 349 pico_tree_foreach(index,&sp->socks){
daniele 0:d7f2341ab245 350 s = index->keyValue;
daniele 0:d7f2341ab245 351 /* 4-tuple identification of socket (port-IP) */
daniele 0:d7f2341ab245 352 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 353 if (IS_IPV4(f)) {
daniele 0:d7f2341ab245 354 struct pico_ip4 s_local, s_remote, p_src, p_dst;
daniele 0:d7f2341ab245 355 ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
daniele 0:d7f2341ab245 356 s_local.addr = s->local_addr.ip4.addr;
daniele 0:d7f2341ab245 357 s_remote.addr = s->remote_addr.ip4.addr;
daniele 0:d7f2341ab245 358 p_src.addr = ip4hdr->src.addr;
daniele 0:d7f2341ab245 359 p_dst.addr = ip4hdr->dst.addr;
daniele 0:d7f2341ab245 360 if ( (s->remote_port == tr->sport) && /* remote port check */
daniele 0:d7f2341ab245 361 (s_remote.addr == p_src.addr) && /* remote addr check */
daniele 0:d7f2341ab245 362 ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
daniele 0:d7f2341ab245 363 found = s;
daniele 0:d7f2341ab245 364 break;
daniele 0:d7f2341ab245 365 } else if ( (s->remote_port == 0) && /* not connected... listening */
daniele 0:d7f2341ab245 366 ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
daniele 0:d7f2341ab245 367 /* listen socket */
daniele 0:d7f2341ab245 368 found = s;
daniele 0:d7f2341ab245 369 }
daniele 0:d7f2341ab245 370 }
daniele 0:d7f2341ab245 371 #endif
daniele 0:d7f2341ab245 372 #ifdef PICO_SUPPORT_IPV6 /* XXX TODO make compare for ipv6 addresses */
daniele 0:d7f2341ab245 373 if (IS_IPV6(f)) {
daniele 0:d7f2341ab245 374 ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
daniele 0:d7f2341ab245 375 if ( (s->remote_port == localport) ) { // && (((struct pico_ip6) s->remote_addr.ip6).addr == ((struct pico_ip6)(ip6hdr->src)).addr) ) {
daniele 0:d7f2341ab245 376 found = s;
daniele 0:d7f2341ab245 377 break;
daniele 0:d7f2341ab245 378 } else if (s->remote_port == 0) {
daniele 0:d7f2341ab245 379 /* listen socket */
daniele 0:d7f2341ab245 380 found = s;
daniele 0:d7f2341ab245 381 }
daniele 0:d7f2341ab245 382 }
daniele 0:d7f2341ab245 383 #endif
daniele 0:d7f2341ab245 384 } /* FOREACH */
daniele 0:d7f2341ab245 385 if (found != NULL) {
daniele 0:d7f2341ab245 386 pico_tcp_input(found,f);
daniele 0:d7f2341ab245 387 if ((found->ev_pending) && found->wakeup) {
daniele 0:d7f2341ab245 388 found->wakeup(found->ev_pending, found);
daniele 0:d7f2341ab245 389 }
daniele 0:d7f2341ab245 390 return 0;
daniele 0:d7f2341ab245 391 } else {
daniele 0:d7f2341ab245 392 dbg("SOCKET> mmm something wrong (prob sockport)\n");
daniele 0:d7f2341ab245 393 return -1;
daniele 0:d7f2341ab245 394 }
daniele 0:d7f2341ab245 395 } /* TCP CASE */
daniele 0:d7f2341ab245 396 #endif
daniele 0:d7f2341ab245 397
daniele 0:d7f2341ab245 398 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 399 if (p->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 400 pico_tree_foreach(index, &sp->socks) {
daniele 0:d7f2341ab245 401 s = index->keyValue;
daniele 0:d7f2341ab245 402 if (IS_IPV4(f)) { /* IPV4 */
daniele 0:d7f2341ab245 403 struct pico_ip4 s_local, p_dst;
daniele 0:d7f2341ab245 404 ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
daniele 0:d7f2341ab245 405 s_local.addr = s->local_addr.ip4.addr;
daniele 0:d7f2341ab245 406 p_dst.addr = ip4hdr->dst.addr;
daniele 0:d7f2341ab245 407 if ((pico_ipv4_is_broadcast(p_dst.addr)) || !pico_ipv4_is_unicast(p_dst.addr)) {
daniele 0:d7f2341ab245 408 struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4);
daniele 0:d7f2341ab245 409 if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */
daniele 0:d7f2341ab245 410 (dev == f->dev) ) { /* the source of the bcast packet is a neighbor... */
daniele 0:d7f2341ab245 411 cpy = pico_frame_copy(f);
daniele 0:d7f2341ab245 412 if (!cpy)
daniele 0:d7f2341ab245 413 return -1;
daniele 0:d7f2341ab245 414 if (pico_enqueue(&s->q_in, cpy) > 0) {
daniele 0:d7f2341ab245 415 if (s->wakeup)
daniele 0:d7f2341ab245 416 s->wakeup(PICO_SOCK_EV_RD, s);
daniele 0:d7f2341ab245 417 }
daniele 0:d7f2341ab245 418 }
daniele 0:d7f2341ab245 419 } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))
daniele 0:d7f2341ab245 420 { /* Either local socket is ANY, or matches dst */
daniele 0:d7f2341ab245 421 cpy = pico_frame_copy(f);
daniele 0:d7f2341ab245 422 if (!cpy)
daniele 0:d7f2341ab245 423 return -1;
daniele 0:d7f2341ab245 424 if (pico_enqueue(&s->q_in, cpy) > 0) {
daniele 0:d7f2341ab245 425 if (s->wakeup)
daniele 0:d7f2341ab245 426 s->wakeup(PICO_SOCK_EV_RD, s);
daniele 0:d7f2341ab245 427 }
daniele 0:d7f2341ab245 428 }
daniele 0:d7f2341ab245 429 } else {
daniele 0:d7f2341ab245 430 /*... IPv6 */
daniele 0:d7f2341ab245 431 }
daniele 0:d7f2341ab245 432 } /* FOREACH */
daniele 0:d7f2341ab245 433 pico_frame_discard(f);
daniele 0:d7f2341ab245 434 if (s)
daniele 0:d7f2341ab245 435 return 0;
daniele 0:d7f2341ab245 436 else
daniele 0:d7f2341ab245 437 return -1;
daniele 0:d7f2341ab245 438 }
daniele 0:d7f2341ab245 439 #endif
daniele 0:d7f2341ab245 440 return -1;
daniele 0:d7f2341ab245 441 }
daniele 0:d7f2341ab245 442
daniele 0:d7f2341ab245 443 struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *))
daniele 0:d7f2341ab245 444 {
daniele 0:d7f2341ab245 445
daniele 0:d7f2341ab245 446 struct pico_socket *s = NULL;
daniele 0:d7f2341ab245 447
daniele 0:d7f2341ab245 448 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 449 if (proto == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 450 s = pico_udp_open();
daniele 0:d7f2341ab245 451 s->proto = &pico_proto_udp;
daniele 0:d7f2341ab245 452 }
daniele 0:d7f2341ab245 453 #endif
daniele 0:d7f2341ab245 454
daniele 0:d7f2341ab245 455 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 456 if (proto == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 457 s = pico_tcp_open();
daniele 0:d7f2341ab245 458 s->proto = &pico_proto_tcp;
daniele 0:d7f2341ab245 459 /*check if Nagle enabled */
daniele 0:d7f2341ab245 460 if (!IS_NAGLE_ENABLED(s))
daniele 0:d7f2341ab245 461 dbg("ERROR Nagle should be enabled here\n\n");
daniele 0:d7f2341ab245 462 }
daniele 0:d7f2341ab245 463 #endif
daniele 0:d7f2341ab245 464
daniele 0:d7f2341ab245 465 if (!s) {
daniele 0:d7f2341ab245 466 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 0:d7f2341ab245 467 return NULL;
daniele 0:d7f2341ab245 468 }
daniele 0:d7f2341ab245 469
daniele 0:d7f2341ab245 470 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 471 if (net == PICO_PROTO_IPV4)
daniele 0:d7f2341ab245 472 s->net = &pico_proto_ipv4;
daniele 0:d7f2341ab245 473 #endif
daniele 0:d7f2341ab245 474
daniele 0:d7f2341ab245 475 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 476 if (net == PICO_PROTO_IPV6)
daniele 0:d7f2341ab245 477 s->net = &pico_proto_ipv6;
daniele 0:d7f2341ab245 478 #endif
daniele 0:d7f2341ab245 479
daniele 0:d7f2341ab245 480 s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
daniele 0:d7f2341ab245 481 s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
daniele 0:d7f2341ab245 482 s->wakeup = wakeup;
daniele 0:d7f2341ab245 483
daniele 0:d7f2341ab245 484 if (!s->net) {
daniele 0:d7f2341ab245 485 pico_free(s);
daniele 0:d7f2341ab245 486 pico_err = PICO_ERR_ENETUNREACH;
daniele 0:d7f2341ab245 487 return NULL;
daniele 0:d7f2341ab245 488 }
daniele 0:d7f2341ab245 489 return s;
daniele 0:d7f2341ab245 490 }
daniele 0:d7f2341ab245 491
daniele 0:d7f2341ab245 492
daniele 0:d7f2341ab245 493 struct pico_socket *pico_socket_clone(struct pico_socket *facsimile)
daniele 0:d7f2341ab245 494 {
daniele 0:d7f2341ab245 495 struct pico_socket *s = NULL;
daniele 0:d7f2341ab245 496
daniele 0:d7f2341ab245 497 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 498 if (facsimile->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 499 s = pico_udp_open();
daniele 0:d7f2341ab245 500 s->proto = &pico_proto_udp;
daniele 0:d7f2341ab245 501 }
daniele 0:d7f2341ab245 502 #endif
daniele 0:d7f2341ab245 503
daniele 0:d7f2341ab245 504 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 505 if (facsimile->proto->proto_number == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 506 s = pico_tcp_open();
daniele 0:d7f2341ab245 507 s->proto = &pico_proto_tcp;
daniele 0:d7f2341ab245 508 }
daniele 0:d7f2341ab245 509 #endif
daniele 0:d7f2341ab245 510
daniele 0:d7f2341ab245 511 if (!s) {
daniele 0:d7f2341ab245 512 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 0:d7f2341ab245 513 return NULL;
daniele 0:d7f2341ab245 514 }
daniele 0:d7f2341ab245 515 s->local_port = facsimile->local_port;
daniele 0:d7f2341ab245 516 s->remote_port = facsimile->remote_port;
daniele 0:d7f2341ab245 517 s->state = facsimile->state;
daniele 0:d7f2341ab245 518
daniele 0:d7f2341ab245 519 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 520 if (facsimile->net == &pico_proto_ipv4) {
daniele 0:d7f2341ab245 521 s->net = &pico_proto_ipv4;
daniele 0:d7f2341ab245 522 memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip4));
daniele 0:d7f2341ab245 523 memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip4));
daniele 0:d7f2341ab245 524 }
daniele 0:d7f2341ab245 525 #endif
daniele 0:d7f2341ab245 526
daniele 0:d7f2341ab245 527 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 528 if (net == &pico_proto_ipv6) {
daniele 0:d7f2341ab245 529 s->net = &pico_proto_ipv6;
daniele 0:d7f2341ab245 530 memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip6));
daniele 0:d7f2341ab245 531 memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip6));
daniele 0:d7f2341ab245 532 }
daniele 0:d7f2341ab245 533 #endif
daniele 0:d7f2341ab245 534 s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
daniele 0:d7f2341ab245 535 s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
daniele 0:d7f2341ab245 536 s->wakeup = NULL;
daniele 0:d7f2341ab245 537 if (!s->net) {
daniele 0:d7f2341ab245 538 pico_free(s);
daniele 0:d7f2341ab245 539 pico_err = PICO_ERR_ENETUNREACH;
daniele 0:d7f2341ab245 540 return NULL;
daniele 0:d7f2341ab245 541 }
daniele 0:d7f2341ab245 542 return s;
daniele 0:d7f2341ab245 543 }
daniele 0:d7f2341ab245 544
daniele 0:d7f2341ab245 545 int pico_socket_read(struct pico_socket *s, void *buf, int len)
daniele 0:d7f2341ab245 546 {
daniele 0:d7f2341ab245 547 if (!s || buf == NULL) {
daniele 0:d7f2341ab245 548 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 549 return -1;
daniele 0:d7f2341ab245 550 } else {
daniele 0:d7f2341ab245 551 /* check if exists in tree */
daniele 0:d7f2341ab245 552 /* See task #178 */
daniele 0:d7f2341ab245 553 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 554 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 555 return -1;
daniele 0:d7f2341ab245 556 }
daniele 0:d7f2341ab245 557 }
daniele 0:d7f2341ab245 558
daniele 0:d7f2341ab245 559 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 560 pico_err = PICO_ERR_EIO;
daniele 0:d7f2341ab245 561 return -1;
daniele 0:d7f2341ab245 562 }
daniele 0:d7f2341ab245 563 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 564 if (PROTO(s) == PICO_PROTO_UDP)
daniele 0:d7f2341ab245 565 return pico_udp_recv(s, buf, len, NULL, NULL);
daniele 0:d7f2341ab245 566 #endif
daniele 0:d7f2341ab245 567
daniele 0:d7f2341ab245 568 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 569 if (PROTO(s) == PICO_PROTO_TCP){
daniele 0:d7f2341ab245 570 /* check if in shutdown state and if no more data in tcpq_in */
daniele 0:d7f2341ab245 571 if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s) ) {
daniele 0:d7f2341ab245 572 pico_err = PICO_ERR_ESHUTDOWN;
daniele 0:d7f2341ab245 573 return -1;
daniele 0:d7f2341ab245 574 } else {
daniele 0:d7f2341ab245 575 return pico_tcp_read(s, buf, len);
daniele 0:d7f2341ab245 576 }
daniele 0:d7f2341ab245 577 }
daniele 0:d7f2341ab245 578 #endif
daniele 0:d7f2341ab245 579 return 0;
daniele 0:d7f2341ab245 580 }
daniele 0:d7f2341ab245 581
daniele 0:d7f2341ab245 582 int pico_socket_write(struct pico_socket *s, void *buf, int len)
daniele 0:d7f2341ab245 583 {
daniele 0:d7f2341ab245 584 if (!s || buf == NULL) {
daniele 0:d7f2341ab245 585 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 586 return -1;
daniele 0:d7f2341ab245 587 } else {
daniele 0:d7f2341ab245 588 /* check if exists in tree */
daniele 0:d7f2341ab245 589 /* See task #178 */
daniele 0:d7f2341ab245 590 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 591 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 592 return -1;
daniele 0:d7f2341ab245 593 }
daniele 0:d7f2341ab245 594 }
daniele 0:d7f2341ab245 595
daniele 0:d7f2341ab245 596 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 597 pico_err = PICO_ERR_EIO;
daniele 0:d7f2341ab245 598 return -1;
daniele 0:d7f2341ab245 599 }
daniele 0:d7f2341ab245 600 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
daniele 0:d7f2341ab245 601 pico_err = PICO_ERR_ENOTCONN;
daniele 0:d7f2341ab245 602 return -1;
daniele 0:d7f2341ab245 603 } else if (s->state & PICO_SOCKET_STATE_SHUT_LOCAL) { /* check if in shutdown state */
daniele 0:d7f2341ab245 604 pico_err = PICO_ERR_ESHUTDOWN;
daniele 0:d7f2341ab245 605 return -1;
daniele 0:d7f2341ab245 606 } else {
daniele 0:d7f2341ab245 607 return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
daniele 0:d7f2341ab245 608 }
daniele 0:d7f2341ab245 609 }
daniele 0:d7f2341ab245 610
daniele 0:d7f2341ab245 611 uint16_t pico_socket_high_port(uint16_t proto)
daniele 0:d7f2341ab245 612 {
daniele 0:d7f2341ab245 613 uint16_t port;
daniele 0:d7f2341ab245 614 if (0 ||
daniele 0:d7f2341ab245 615 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 616 (proto == PICO_PROTO_TCP) ||
daniele 0:d7f2341ab245 617 #endif
daniele 0:d7f2341ab245 618 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 619 (proto == PICO_PROTO_UDP) ||
daniele 0:d7f2341ab245 620 #endif
daniele 0:d7f2341ab245 621 0) {
daniele 0:d7f2341ab245 622 do {
daniele 0:d7f2341ab245 623 uint32_t rand = pico_rand();
daniele 0:d7f2341ab245 624 port = (uint16_t) (rand & 0xFFFFU);
daniele 0:d7f2341ab245 625 port = (uint16_t)(port % (65535 - 1024)) + 1024U;
daniele 0:d7f2341ab245 626 if (pico_is_port_free(proto, port, NULL, NULL)) {
daniele 0:d7f2341ab245 627 return short_be(port);
daniele 0:d7f2341ab245 628 }
daniele 0:d7f2341ab245 629 } while(1);
daniele 0:d7f2341ab245 630 }
daniele 0:d7f2341ab245 631 else return 0U;
daniele 0:d7f2341ab245 632 }
daniele 0:d7f2341ab245 633
daniele 0:d7f2341ab245 634
daniele 0:d7f2341ab245 635 int pico_socket_sendto(struct pico_socket *s, void *buf, int len, void *dst, uint16_t remote_port)
daniele 0:d7f2341ab245 636 {
daniele 0:d7f2341ab245 637 struct pico_frame *f;
daniele 0:d7f2341ab245 638 struct pico_remote_duple *remote_duple = NULL;
daniele 0:d7f2341ab245 639 int header_offset = 0;
daniele 0:d7f2341ab245 640 int total_payload_written = 0;
daniele 0:d7f2341ab245 641 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 642 struct pico_ip4 *src4;
daniele 0:d7f2341ab245 643 #endif
daniele 0:d7f2341ab245 644
daniele 0:d7f2341ab245 645 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 646 struct pico_ip6 *src6;
daniele 0:d7f2341ab245 647 #endif
daniele 0:d7f2341ab245 648 if (len == 0) {
daniele 0:d7f2341ab245 649 return 0;
daniele 0:d7f2341ab245 650 } else if (len < 0) {
daniele 0:d7f2341ab245 651 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 652 return -1;
daniele 0:d7f2341ab245 653 }
daniele 0:d7f2341ab245 654
daniele 0:d7f2341ab245 655 if (buf == NULL || s == NULL) {
daniele 0:d7f2341ab245 656 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 657 return -1;
daniele 0:d7f2341ab245 658 }
daniele 0:d7f2341ab245 659
daniele 0:d7f2341ab245 660 if (!dst || !remote_port) {
daniele 0:d7f2341ab245 661 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 0:d7f2341ab245 662 return -1;
daniele 0:d7f2341ab245 663 }
daniele 0:d7f2341ab245 664
daniele 0:d7f2341ab245 665 if ((s->state & PICO_SOCKET_STATE_CONNECTED) != 0) {
daniele 0:d7f2341ab245 666 if (remote_port != s->remote_port) {
daniele 0:d7f2341ab245 667 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 668 return -1;
daniele 0:d7f2341ab245 669 }
daniele 0:d7f2341ab245 670 }
daniele 0:d7f2341ab245 671
daniele 0:d7f2341ab245 672 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 673 if (IS_SOCK_IPV4(s)) {
daniele 0:d7f2341ab245 674 if ((s->state & PICO_SOCKET_STATE_CONNECTED)) {
daniele 0:d7f2341ab245 675 if (s->remote_addr.ip4.addr != ((struct pico_ip4 *)dst)->addr ) {
daniele 0:d7f2341ab245 676 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 0:d7f2341ab245 677 return -1;
daniele 0:d7f2341ab245 678 }
daniele 0:d7f2341ab245 679 } else {
daniele 0:d7f2341ab245 680 src4 = pico_ipv4_source_find(dst);
daniele 0:d7f2341ab245 681 if (!src4) {
daniele 0:d7f2341ab245 682 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 0:d7f2341ab245 683 return -1;
daniele 0:d7f2341ab245 684 }
daniele 0:d7f2341ab245 685 if (src4->addr != PICO_IPV4_INADDR_ANY)
daniele 0:d7f2341ab245 686 s->local_addr.ip4.addr = src4->addr;
daniele 0:d7f2341ab245 687 # ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 688 /* socket remote info could change in a consecutive call, make persistent */
daniele 0:d7f2341ab245 689 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 690 remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
daniele 0:d7f2341ab245 691 remote_duple->remote_addr.ip4.addr = ((struct pico_ip4 *)dst)->addr;
daniele 0:d7f2341ab245 692 remote_duple->remote_port = remote_port;
daniele 0:d7f2341ab245 693 }
daniele 0:d7f2341ab245 694 # endif
daniele 0:d7f2341ab245 695 }
daniele 0:d7f2341ab245 696 }
daniele 0:d7f2341ab245 697 #endif
daniele 0:d7f2341ab245 698
daniele 0:d7f2341ab245 699 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 700 if (IS_SOCK_IPV6(s)) {
daniele 0:d7f2341ab245 701 if (s->state & PICO_SOCKET_STATE_CONNECTED) {
daniele 0:d7f2341ab245 702 if (memcmp(&s->remote_addr, dst, PICO_SIZE_IP6))
daniele 0:d7f2341ab245 703 return -1;
daniele 0:d7f2341ab245 704 } else {
daniele 0:d7f2341ab245 705 src6 = pico_ipv6_source_find(dst);
daniele 0:d7f2341ab245 706 if (!src6) {
daniele 0:d7f2341ab245 707 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 0:d7f2341ab245 708 return -1;
daniele 0:d7f2341ab245 709 }
daniele 0:d7f2341ab245 710 memcpy(&s->local_addr, src6, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 711 memcpy(&s->remote_addr, dst, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 712 # ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 713 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 714 remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
daniele 0:d7f2341ab245 715 remote_duple->remote_addr.ip6.addr = ((struct pico_ip6 *)dst)->addr;
daniele 0:d7f2341ab245 716 remote_duple->remote_port = remote_port;
daniele 0:d7f2341ab245 717 }
daniele 0:d7f2341ab245 718 # endif
daniele 0:d7f2341ab245 719 }
daniele 0:d7f2341ab245 720 }
daniele 0:d7f2341ab245 721 #endif
daniele 0:d7f2341ab245 722
daniele 0:d7f2341ab245 723 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 724 s->local_port = pico_socket_high_port(s->proto->proto_number);
daniele 0:d7f2341ab245 725 if (s->local_port == 0) {
daniele 0:d7f2341ab245 726 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 727 return -1;
daniele 0:d7f2341ab245 728 }
daniele 0:d7f2341ab245 729 }
daniele 0:d7f2341ab245 730 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
daniele 0:d7f2341ab245 731 s->remote_port = remote_port;
daniele 0:d7f2341ab245 732 }
daniele 0:d7f2341ab245 733
daniele 0:d7f2341ab245 734 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 735 if (PROTO(s) == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 736 header_offset = pico_tcp_overhead(s);
daniele 0:d7f2341ab245 737 #endif
daniele 0:d7f2341ab245 738
daniele 0:d7f2341ab245 739 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 740 if (PROTO(s) == PICO_PROTO_UDP)
daniele 0:d7f2341ab245 741 header_offset = sizeof(struct pico_udp_hdr);
daniele 0:d7f2341ab245 742 #endif
daniele 0:d7f2341ab245 743
daniele 0:d7f2341ab245 744 while (total_payload_written < len) {
daniele 0:d7f2341ab245 745 int transport_len = (len - total_payload_written) + header_offset;
daniele 0:d7f2341ab245 746 if (transport_len > PICO_SOCKET_MTU)
daniele 0:d7f2341ab245 747 transport_len = PICO_SOCKET_MTU;
daniele 0:d7f2341ab245 748 #ifdef PICO_SUPPORT_IPFRAG
daniele 0:d7f2341ab245 749 else {
daniele 0:d7f2341ab245 750 if (total_payload_written)
daniele 0:d7f2341ab245 751 transport_len -= header_offset; /* last fragment, do not allocate memory for transport header */
daniele 0:d7f2341ab245 752 }
daniele 0:d7f2341ab245 753 #endif /* PICO_SUPPORT_IPFRAG */
daniele 0:d7f2341ab245 754
daniele 0:d7f2341ab245 755 f = pico_socket_frame_alloc(s, transport_len);
daniele 0:d7f2341ab245 756 if (!f) {
daniele 0:d7f2341ab245 757 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 758 return -1;
daniele 0:d7f2341ab245 759 }
daniele 0:d7f2341ab245 760 f->payload += header_offset;
daniele 0:d7f2341ab245 761 f->payload_len -= header_offset;
daniele 0:d7f2341ab245 762 f->sock = s;
daniele 0:d7f2341ab245 763 if (remote_duple) {
daniele 0:d7f2341ab245 764 f->info = pico_zalloc(sizeof(struct pico_remote_duple));
daniele 0:d7f2341ab245 765 memcpy(f->info, remote_duple, sizeof(struct pico_remote_duple));
daniele 0:d7f2341ab245 766 }
daniele 0:d7f2341ab245 767
daniele 0:d7f2341ab245 768 #ifdef PICO_SUPPORT_IPFRAG
daniele 0:d7f2341ab245 769 # ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 770 if (PROTO(s) == PICO_PROTO_UDP && ((len + header_offset) > PICO_SOCKET_MTU)) {
daniele 0:d7f2341ab245 771 /* hacking way to identify fragmentation frames: payload != transport_hdr -> first frame */
daniele 0:d7f2341ab245 772 if (!total_payload_written) {
daniele 0:d7f2341ab245 773 frag_dbg("FRAG: first fragmented frame %p | len = %u offset = 0\n", f, f->payload_len);
daniele 0:d7f2341ab245 774 /* transport header length field contains total length + header length */
daniele 0:d7f2341ab245 775 f->transport_len = len + header_offset;
daniele 0:d7f2341ab245 776 f->frag = short_be(PICO_IPV4_MOREFRAG);
daniele 0:d7f2341ab245 777 } else {
daniele 0:d7f2341ab245 778 /* no transport header in fragmented IP */
daniele 0:d7f2341ab245 779 f->payload = f->transport_hdr;
daniele 0:d7f2341ab245 780 f->payload_len += header_offset;
daniele 0:d7f2341ab245 781 /* set offset in octets */
daniele 0:d7f2341ab245 782 f->frag = short_be((total_payload_written + header_offset) / 8);
daniele 0:d7f2341ab245 783 if (total_payload_written + f->payload_len < len) {
daniele 0:d7f2341ab245 784 frag_dbg("FRAG: intermediate fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
daniele 0:d7f2341ab245 785 f->frag |= short_be(PICO_IPV4_MOREFRAG);
daniele 0:d7f2341ab245 786 } else {
daniele 0:d7f2341ab245 787 frag_dbg("FRAG: last fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
daniele 0:d7f2341ab245 788 f->frag &= short_be(PICO_IPV4_FRAG_MASK);
daniele 0:d7f2341ab245 789 }
daniele 0:d7f2341ab245 790 }
daniele 0:d7f2341ab245 791 } else {
daniele 0:d7f2341ab245 792 f->frag = short_be(PICO_IPV4_DONTFRAG);
daniele 0:d7f2341ab245 793 }
daniele 0:d7f2341ab245 794 # endif /* PICO_SUPPORT_UDP */
daniele 0:d7f2341ab245 795 #endif /* PICO_SUPPORT_IPFRAG */
daniele 0:d7f2341ab245 796
daniele 0:d7f2341ab245 797 if (f->payload_len <= 0) {
daniele 0:d7f2341ab245 798 pico_frame_discard(f);
daniele 0:d7f2341ab245 799 pico_free(remote_duple);
daniele 0:d7f2341ab245 800 return total_payload_written;
daniele 0:d7f2341ab245 801 }
daniele 0:d7f2341ab245 802
daniele 0:d7f2341ab245 803 memcpy(f->payload, buf + total_payload_written, f->payload_len);
daniele 0:d7f2341ab245 804 //dbg("Pushing segment, hdr len: %d, payload_len: %d\n", header_offset, f->payload_len);
daniele 0:d7f2341ab245 805
daniele 0:d7f2341ab245 806 if (s->proto->push(s->proto, f) > 0) {
daniele 0:d7f2341ab245 807 total_payload_written += f->payload_len;
daniele 0:d7f2341ab245 808 } else {
daniele 0:d7f2341ab245 809 pico_frame_discard(f);
daniele 0:d7f2341ab245 810 pico_err = PICO_ERR_EAGAIN;
daniele 0:d7f2341ab245 811 break;
daniele 0:d7f2341ab245 812 }
daniele 0:d7f2341ab245 813 }
daniele 0:d7f2341ab245 814 pico_free(remote_duple);
daniele 0:d7f2341ab245 815 return total_payload_written;
daniele 0:d7f2341ab245 816 }
daniele 0:d7f2341ab245 817
daniele 0:d7f2341ab245 818 int pico_socket_send(struct pico_socket *s, void *buf, int len)
daniele 0:d7f2341ab245 819 {
daniele 0:d7f2341ab245 820 if (!s || buf == NULL) {
daniele 0:d7f2341ab245 821 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 822 return -1;
daniele 0:d7f2341ab245 823 } else {
daniele 0:d7f2341ab245 824 /* check if exists in tree */
daniele 0:d7f2341ab245 825 /* See task #178 */
daniele 0:d7f2341ab245 826 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 827 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 828 return -1;
daniele 0:d7f2341ab245 829 }
daniele 0:d7f2341ab245 830 }
daniele 0:d7f2341ab245 831
daniele 0:d7f2341ab245 832 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
daniele 0:d7f2341ab245 833 pico_err = PICO_ERR_ENOTCONN;
daniele 0:d7f2341ab245 834 return -1;
daniele 0:d7f2341ab245 835 }
daniele 0:d7f2341ab245 836 return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
daniele 0:d7f2341ab245 837 }
daniele 0:d7f2341ab245 838
daniele 0:d7f2341ab245 839 int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port)
daniele 0:d7f2341ab245 840 {
daniele 0:d7f2341ab245 841 if (!s || buf == NULL) { /// || orig == NULL || remote_port == NULL) {
daniele 0:d7f2341ab245 842 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 843 return -1;
daniele 0:d7f2341ab245 844 } else {
daniele 0:d7f2341ab245 845 /* check if exists in tree */
daniele 0:d7f2341ab245 846 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 847 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 848 /* See task #178 */
daniele 0:d7f2341ab245 849 return -1;
daniele 0:d7f2341ab245 850 }
daniele 0:d7f2341ab245 851 }
daniele 0:d7f2341ab245 852
daniele 0:d7f2341ab245 853 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 854 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 0:d7f2341ab245 855 return -1;
daniele 0:d7f2341ab245 856 }
daniele 0:d7f2341ab245 857 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 858 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 859 return pico_udp_recv(s, buf, len, orig, remote_port);
daniele 0:d7f2341ab245 860 }
daniele 0:d7f2341ab245 861 #endif
daniele 0:d7f2341ab245 862 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 863 if (PROTO(s) == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 864 /* check if in shutdown state and if tcpq_in empty */
daniele 0:d7f2341ab245 865 if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) {
daniele 0:d7f2341ab245 866 pico_err = PICO_ERR_ESHUTDOWN;
daniele 0:d7f2341ab245 867 return -1;
daniele 0:d7f2341ab245 868 } else {
daniele 0:d7f2341ab245 869 //dbg("socket tcp recv\n");
daniele 0:d7f2341ab245 870 return pico_tcp_read(s, buf, len);
daniele 0:d7f2341ab245 871 }
daniele 0:d7f2341ab245 872 }
daniele 0:d7f2341ab245 873 #endif
daniele 0:d7f2341ab245 874 //dbg("socket return 0\n");
daniele 0:d7f2341ab245 875 return 0;
daniele 0:d7f2341ab245 876 }
daniele 0:d7f2341ab245 877
daniele 0:d7f2341ab245 878 int pico_socket_recv(struct pico_socket *s, void *buf, int len)
daniele 0:d7f2341ab245 879 {
daniele 0:d7f2341ab245 880 return pico_socket_recvfrom(s, buf, len, NULL, NULL);
daniele 0:d7f2341ab245 881 }
daniele 0:d7f2341ab245 882
daniele 0:d7f2341ab245 883
daniele 0:d7f2341ab245 884 int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port)
daniele 0:d7f2341ab245 885 {
daniele 0:d7f2341ab245 886 if (!s || !local_addr || !port) {
daniele 0:d7f2341ab245 887 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 888 return -1;
daniele 0:d7f2341ab245 889 }
daniele 0:d7f2341ab245 890
daniele 0:d7f2341ab245 891 if (!is_sock_ipv6(s)) {
daniele 0:d7f2341ab245 892 struct pico_ip4 *ip = (struct pico_ip4 *)local_addr;
daniele 0:d7f2341ab245 893 if (ip->addr != PICO_IPV4_INADDR_ANY) {
daniele 0:d7f2341ab245 894 if (!pico_ipv4_link_find(local_addr)) {
daniele 0:d7f2341ab245 895 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 896 return -1;
daniele 0:d7f2341ab245 897 }
daniele 0:d7f2341ab245 898 }
daniele 0:d7f2341ab245 899 } else {
daniele 0:d7f2341ab245 900 /*... IPv6 */
daniele 0:d7f2341ab245 901 }
daniele 0:d7f2341ab245 902
daniele 0:d7f2341ab245 903
daniele 0:d7f2341ab245 904 /* When given port = 0, get a random high port to bind to. */
daniele 0:d7f2341ab245 905 if (*port == 0) {
daniele 0:d7f2341ab245 906 *port = pico_socket_high_port(PROTO(s));
daniele 0:d7f2341ab245 907 if (*port == 0) {
daniele 0:d7f2341ab245 908 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 909 return -1;
daniele 0:d7f2341ab245 910 }
daniele 0:d7f2341ab245 911 }
daniele 0:d7f2341ab245 912
daniele 0:d7f2341ab245 913 if (pico_is_port_free(PROTO(s), *port, local_addr, s->net) == 0) {
daniele 0:d7f2341ab245 914 pico_err = PICO_ERR_EADDRINUSE;
daniele 0:d7f2341ab245 915 return -1;
daniele 0:d7f2341ab245 916 }
daniele 0:d7f2341ab245 917 s->local_port = *port;
daniele 0:d7f2341ab245 918
daniele 0:d7f2341ab245 919 if (is_sock_ipv6(s)) {
daniele 0:d7f2341ab245 920 struct pico_ip6 *ip = (struct pico_ip6 *) local_addr;
daniele 0:d7f2341ab245 921 memcpy(s->local_addr.ip6.addr, ip, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 922 /* XXX: port ipv4 functionality to ipv6 */
daniele 0:d7f2341ab245 923 /* Check for port already in use */
daniele 0:d7f2341ab245 924 if (pico_is_port_free(PROTO(s), *port, &local_addr, s->net)) {
daniele 0:d7f2341ab245 925 pico_err = PICO_ERR_EADDRINUSE;
daniele 0:d7f2341ab245 926 return -1;
daniele 0:d7f2341ab245 927 }
daniele 0:d7f2341ab245 928 } else if (is_sock_ipv4(s)) {
daniele 0:d7f2341ab245 929 struct pico_ip4 *ip = (struct pico_ip4 *) local_addr;
daniele 0:d7f2341ab245 930 s->local_addr.ip4.addr = ip->addr;
daniele 0:d7f2341ab245 931 }
daniele 0:d7f2341ab245 932 return pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
daniele 0:d7f2341ab245 933 }
daniele 0:d7f2341ab245 934
daniele 0:d7f2341ab245 935 int pico_socket_connect(struct pico_socket *s, void *remote_addr, uint16_t remote_port)
daniele 0:d7f2341ab245 936 {
daniele 0:d7f2341ab245 937 int ret = -1;
daniele 0:d7f2341ab245 938 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 0:d7f2341ab245 939 if (!s || remote_addr == NULL || remote_port == 0) {
daniele 0:d7f2341ab245 940 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 941 return -1;
daniele 0:d7f2341ab245 942 }
daniele 0:d7f2341ab245 943
daniele 0:d7f2341ab245 944 s->remote_port = remote_port;
daniele 0:d7f2341ab245 945
daniele 0:d7f2341ab245 946 if (s->local_port == 0) {
daniele 0:d7f2341ab245 947 s->local_port = pico_socket_high_port(PROTO(s));
daniele 0:d7f2341ab245 948 if (!s->local_port) {
daniele 0:d7f2341ab245 949 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 950 return -1;
daniele 0:d7f2341ab245 951 }
daniele 0:d7f2341ab245 952 }
daniele 0:d7f2341ab245 953
daniele 0:d7f2341ab245 954 if (is_sock_ipv6(s)) {
daniele 0:d7f2341ab245 955 struct pico_ip6 *ip = (struct pico_ip6 *) remote_addr;
daniele 0:d7f2341ab245 956 memcpy(s->remote_addr.ip6.addr, ip, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 957 } else if (is_sock_ipv4(s)) {
daniele 0:d7f2341ab245 958 struct pico_ip4 *local, *ip = (struct pico_ip4 *) remote_addr;
daniele 0:d7f2341ab245 959 s->remote_addr.ip4.addr = ip->addr;
daniele 0:d7f2341ab245 960 local = pico_ipv4_source_find(ip);
daniele 0:d7f2341ab245 961 if (local) {
daniele 0:d7f2341ab245 962 s->local_addr.ip4.addr = local->addr;
daniele 0:d7f2341ab245 963 } else {
daniele 0:d7f2341ab245 964 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 0:d7f2341ab245 965 return -1;
daniele 0:d7f2341ab245 966 }
daniele 0:d7f2341ab245 967 }
daniele 0:d7f2341ab245 968
daniele 0:d7f2341ab245 969 pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
daniele 0:d7f2341ab245 970
daniele 0:d7f2341ab245 971 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 972 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 973 pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED, 0, 0);
daniele 0:d7f2341ab245 974 pico_err = PICO_ERR_NOERR;
daniele 0:d7f2341ab245 975 ret = 0;
daniele 0:d7f2341ab245 976 }
daniele 0:d7f2341ab245 977 #endif
daniele 0:d7f2341ab245 978
daniele 0:d7f2341ab245 979 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 980 if (PROTO(s) == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 981 if (pico_tcp_initconn(s) == 0) {
daniele 0:d7f2341ab245 982 pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, 0, 0);
daniele 0:d7f2341ab245 983 pico_err = PICO_ERR_NOERR;
daniele 0:d7f2341ab245 984 ret = 0;
daniele 0:d7f2341ab245 985 } else {
daniele 0:d7f2341ab245 986 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 0:d7f2341ab245 987 }
daniele 0:d7f2341ab245 988 }
daniele 0:d7f2341ab245 989 #endif
daniele 0:d7f2341ab245 990
daniele 0:d7f2341ab245 991 return ret;
daniele 0:d7f2341ab245 992 }
daniele 0:d7f2341ab245 993
daniele 0:d7f2341ab245 994 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 995
daniele 0:d7f2341ab245 996 int pico_socket_listen(struct pico_socket *s, int backlog)
daniele 0:d7f2341ab245 997 {
daniele 0:d7f2341ab245 998 if (!s || backlog < 1) {
daniele 0:d7f2341ab245 999 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1000 return -1;
daniele 0:d7f2341ab245 1001 } else {
daniele 0:d7f2341ab245 1002 /* check if exists in tree */
daniele 0:d7f2341ab245 1003 /* See task #178 */
daniele 0:d7f2341ab245 1004 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 1005 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1006 return -1;
daniele 0:d7f2341ab245 1007 }
daniele 0:d7f2341ab245 1008 }
daniele 0:d7f2341ab245 1009
daniele 0:d7f2341ab245 1010 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1011 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1012 return -1;
daniele 0:d7f2341ab245 1013 }
daniele 0:d7f2341ab245 1014
daniele 0:d7f2341ab245 1015 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 1016 pico_err = PICO_ERR_EISCONN;
daniele 0:d7f2341ab245 1017 return -1;
daniele 0:d7f2341ab245 1018 }
daniele 0:d7f2341ab245 1019
daniele 0:d7f2341ab245 1020 if (backlog < 1) {
daniele 0:d7f2341ab245 1021 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1022 return -1;
daniele 0:d7f2341ab245 1023 }
daniele 0:d7f2341ab245 1024
daniele 0:d7f2341ab245 1025 if (PROTO(s) == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 1026 pico_socket_alter_state(s, PICO_SOCKET_STATE_TCP_SYN_SENT, 0, PICO_SOCKET_STATE_TCP_LISTEN);
daniele 0:d7f2341ab245 1027 s->max_backlog = backlog;
daniele 0:d7f2341ab245 1028
daniele 0:d7f2341ab245 1029 return 0;
daniele 0:d7f2341ab245 1030 }
daniele 0:d7f2341ab245 1031
daniele 0:d7f2341ab245 1032 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port)
daniele 0:d7f2341ab245 1033 {
daniele 0:d7f2341ab245 1034 if (!s || !orig || !port) {
daniele 0:d7f2341ab245 1035 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1036 return NULL;
daniele 0:d7f2341ab245 1037 }
daniele 0:d7f2341ab245 1038
daniele 0:d7f2341ab245 1039 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1040
daniele 0:d7f2341ab245 1041 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 1042 return NULL;
daniele 0:d7f2341ab245 1043 }
daniele 0:d7f2341ab245 1044
daniele 0:d7f2341ab245 1045 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1046 return NULL;
daniele 0:d7f2341ab245 1047 }
daniele 0:d7f2341ab245 1048
daniele 0:d7f2341ab245 1049 if (TCPSTATE(s) == PICO_SOCKET_STATE_TCP_LISTEN) {
daniele 0:d7f2341ab245 1050 struct pico_sockport *sp = pico_get_sockport(PICO_PROTO_TCP, s->local_port);
daniele 0:d7f2341ab245 1051 struct pico_socket *found;
daniele 0:d7f2341ab245 1052 /* If at this point no incoming connection socket is found,
daniele 0:d7f2341ab245 1053 * the accept call is valid, but no connection is established yet.
daniele 0:d7f2341ab245 1054 */
daniele 0:d7f2341ab245 1055 pico_err = PICO_ERR_EAGAIN;
daniele 0:d7f2341ab245 1056 if (sp) {
daniele 0:d7f2341ab245 1057 struct pico_tree_node * index;
daniele 0:d7f2341ab245 1058 //RB_FOREACH(found, socket_tree, &sp->socks) {
daniele 0:d7f2341ab245 1059 pico_tree_foreach(index,&sp->socks){
daniele 0:d7f2341ab245 1060 found = index->keyValue;
daniele 0:d7f2341ab245 1061 if (s == found->parent) {
daniele 0:d7f2341ab245 1062 found->parent = NULL;
daniele 0:d7f2341ab245 1063 pico_err = PICO_ERR_NOERR;
daniele 0:d7f2341ab245 1064 memcpy(orig, &found->remote_addr, sizeof(struct pico_ip4));
daniele 0:d7f2341ab245 1065 *port = found->remote_port;
daniele 0:d7f2341ab245 1066 return found;
daniele 0:d7f2341ab245 1067 }
daniele 0:d7f2341ab245 1068 }
daniele 0:d7f2341ab245 1069 }
daniele 0:d7f2341ab245 1070 }
daniele 0:d7f2341ab245 1071 return NULL;
daniele 0:d7f2341ab245 1072 }
daniele 0:d7f2341ab245 1073
daniele 0:d7f2341ab245 1074 #else
daniele 0:d7f2341ab245 1075
daniele 0:d7f2341ab245 1076 int pico_socket_listen(struct pico_socket *s, int backlog)
daniele 0:d7f2341ab245 1077 {
daniele 0:d7f2341ab245 1078 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1079 return -1;
daniele 0:d7f2341ab245 1080 }
daniele 0:d7f2341ab245 1081
daniele 0:d7f2341ab245 1082 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *local_port)
daniele 0:d7f2341ab245 1083 {
daniele 0:d7f2341ab245 1084 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1085 return NULL;
daniele 0:d7f2341ab245 1086 }
daniele 0:d7f2341ab245 1087
daniele 0:d7f2341ab245 1088 #endif
daniele 0:d7f2341ab245 1089
daniele 0:d7f2341ab245 1090 #define PICO_SOCKET_SETOPT_EN(socket,index) (socket->opt_flags |= (1 << index))
daniele 0:d7f2341ab245 1091 #define PICO_SOCKET_SETOPT_DIS(socket,index) (socket->opt_flags &= ~(1 << index))
daniele 0:d7f2341ab245 1092
daniele 0:d7f2341ab245 1093 int pico_socket_setoption(struct pico_socket *s, int option, void *value) // XXX no check against proto (vs setsockopt) or implicit by socket?
daniele 0:d7f2341ab245 1094 {
daniele 0:d7f2341ab245 1095 if (s == NULL) {
daniele 0:d7f2341ab245 1096 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1097 return -1;
daniele 0:d7f2341ab245 1098 }
daniele 0:d7f2341ab245 1099
daniele 0:d7f2341ab245 1100 pico_err = PICO_ERR_NOERR;
daniele 0:d7f2341ab245 1101
daniele 0:d7f2341ab245 1102 switch (option)
daniele 0:d7f2341ab245 1103 {
daniele 0:d7f2341ab245 1104 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1105 case PICO_TCP_NODELAY:
daniele 0:d7f2341ab245 1106 if (s->proto->proto_number == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 1107 /* disable Nagle's algorithm */
daniele 0:d7f2341ab245 1108 PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_TCPNODELAY);
daniele 0:d7f2341ab245 1109 } else {
daniele 0:d7f2341ab245 1110 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1111 }
daniele 0:d7f2341ab245 1112 break;
daniele 0:d7f2341ab245 1113 #endif
daniele 0:d7f2341ab245 1114
daniele 0:d7f2341ab245 1115
daniele 0:d7f2341ab245 1116 #ifdef PICO_SUPPORT_MCAST
daniele 0:d7f2341ab245 1117 case PICO_IP_MULTICAST_IF:
daniele 0:d7f2341ab245 1118 pico_err = PICO_ERR_EOPNOTSUPP;
daniele 0:d7f2341ab245 1119 return -1;
daniele 0:d7f2341ab245 1120 break;
daniele 0:d7f2341ab245 1121
daniele 0:d7f2341ab245 1122 case PICO_IP_MULTICAST_TTL:
daniele 0:d7f2341ab245 1123 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1124 return pico_udp_set_mc_ttl(s, *((uint8_t *) value));
daniele 0:d7f2341ab245 1125 }
daniele 0:d7f2341ab245 1126 break;
daniele 0:d7f2341ab245 1127
daniele 0:d7f2341ab245 1128 case PICO_IP_MULTICAST_LOOP:
daniele 0:d7f2341ab245 1129 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1130 switch (*(uint8_t *) value)
daniele 0:d7f2341ab245 1131 {
daniele 0:d7f2341ab245 1132 case 0:
daniele 0:d7f2341ab245 1133 /* do not loop back multicast datagram */
daniele 0:d7f2341ab245 1134 PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
daniele 0:d7f2341ab245 1135 break;
daniele 0:d7f2341ab245 1136
daniele 0:d7f2341ab245 1137 case 1:
daniele 0:d7f2341ab245 1138 /* do loop back multicast datagram */
daniele 0:d7f2341ab245 1139 PICO_SOCKET_SETOPT_EN(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
daniele 0:d7f2341ab245 1140 break;
daniele 0:d7f2341ab245 1141
daniele 0:d7f2341ab245 1142 default:
daniele 0:d7f2341ab245 1143 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1144 return -1;
daniele 0:d7f2341ab245 1145 }
daniele 0:d7f2341ab245 1146 }
daniele 0:d7f2341ab245 1147 break;
daniele 0:d7f2341ab245 1148
daniele 0:d7f2341ab245 1149 case PICO_IP_ADD_MEMBERSHIP:
daniele 0:d7f2341ab245 1150 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1151 struct pico_ip_mreq *mreq = (struct pico_ip_mreq *) value;
daniele 0:d7f2341ab245 1152 struct pico_ipv4_link *mcast_link;
daniele 0:d7f2341ab245 1153 if (!mreq->mcast_link_addr.addr) {
daniele 0:d7f2341ab245 1154 mcast_link = NULL; /* use default multicast link */
daniele 0:d7f2341ab245 1155 } else {
daniele 0:d7f2341ab245 1156 mcast_link = pico_ipv4_link_get(&mreq->mcast_link_addr);
daniele 0:d7f2341ab245 1157 if (!mcast_link) {
daniele 0:d7f2341ab245 1158 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1159 return -1;
daniele 0:d7f2341ab245 1160 }
daniele 0:d7f2341ab245 1161 }
daniele 0:d7f2341ab245 1162 return pico_ipv4_mcast_join_group(&mreq->mcast_group_addr, mcast_link);
daniele 0:d7f2341ab245 1163 }
daniele 0:d7f2341ab245 1164 break;
daniele 0:d7f2341ab245 1165
daniele 0:d7f2341ab245 1166 case PICO_IP_DROP_MEMBERSHIP:
daniele 0:d7f2341ab245 1167 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1168 struct pico_ip_mreq *mreq = (struct pico_ip_mreq *) value;
daniele 0:d7f2341ab245 1169 struct pico_ipv4_link *mcast_link;
daniele 0:d7f2341ab245 1170 if (!mreq->mcast_link_addr.addr) {
daniele 0:d7f2341ab245 1171 mcast_link = NULL; /* use default multicast link */
daniele 0:d7f2341ab245 1172 } else {
daniele 0:d7f2341ab245 1173 mcast_link = pico_ipv4_link_get(&mreq->mcast_link_addr);
daniele 0:d7f2341ab245 1174 if (!mcast_link) {
daniele 0:d7f2341ab245 1175 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1176 return -1;
daniele 0:d7f2341ab245 1177 }
daniele 0:d7f2341ab245 1178 }
daniele 0:d7f2341ab245 1179 return pico_ipv4_mcast_leave_group(&mreq->mcast_group_addr, mcast_link);
daniele 0:d7f2341ab245 1180 }
daniele 0:d7f2341ab245 1181 break;
daniele 0:d7f2341ab245 1182 #endif /* PICO_SUPPORT_MCAST */
daniele 0:d7f2341ab245 1183
daniele 0:d7f2341ab245 1184 default:
daniele 0:d7f2341ab245 1185 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1186 return -1;
daniele 0:d7f2341ab245 1187 }
daniele 0:d7f2341ab245 1188
daniele 0:d7f2341ab245 1189 if (pico_err != PICO_ERR_NOERR)
daniele 0:d7f2341ab245 1190 return -1;
daniele 0:d7f2341ab245 1191 else
daniele 0:d7f2341ab245 1192 return 0;
daniele 0:d7f2341ab245 1193 }
daniele 0:d7f2341ab245 1194
daniele 0:d7f2341ab245 1195 #define PICO_SOCKET_GETOPT(socket,index) ((socket->opt_flags & (1 << index)) != 0)
daniele 0:d7f2341ab245 1196
daniele 0:d7f2341ab245 1197 int pico_socket_getoption(struct pico_socket *s, int option, void *value)
daniele 0:d7f2341ab245 1198 {
daniele 0:d7f2341ab245 1199 if (!s || !value) {
daniele 0:d7f2341ab245 1200 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1201 return -1;
daniele 0:d7f2341ab245 1202 }
daniele 0:d7f2341ab245 1203
daniele 0:d7f2341ab245 1204 switch (option)
daniele 0:d7f2341ab245 1205 {
daniele 0:d7f2341ab245 1206 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1207 case PICO_TCP_NODELAY:
daniele 0:d7f2341ab245 1208 if (s->proto->proto_number == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 1209 /* state Nagle's algorithm */
daniele 0:d7f2341ab245 1210 *(int *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_TCPNODELAY);
daniele 0:d7f2341ab245 1211 else
daniele 0:d7f2341ab245 1212 *(int *)value = 0;
daniele 0:d7f2341ab245 1213 break;
daniele 0:d7f2341ab245 1214 #endif
daniele 0:d7f2341ab245 1215
daniele 0:d7f2341ab245 1216 #ifdef PICO_SUPPORT_MCAST
daniele 0:d7f2341ab245 1217 case PICO_IP_MULTICAST_IF:
daniele 0:d7f2341ab245 1218 pico_err = PICO_ERR_EOPNOTSUPP;
daniele 0:d7f2341ab245 1219 return -1;
daniele 0:d7f2341ab245 1220 break;
daniele 0:d7f2341ab245 1221
daniele 0:d7f2341ab245 1222 case PICO_IP_MULTICAST_TTL:
daniele 0:d7f2341ab245 1223 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1224 pico_udp_get_mc_ttl(s, (uint8_t *) value);
daniele 0:d7f2341ab245 1225 } else {
daniele 0:d7f2341ab245 1226 *(uint8_t *)value = 0;
daniele 0:d7f2341ab245 1227 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1228 return -1;
daniele 0:d7f2341ab245 1229 }
daniele 0:d7f2341ab245 1230 break;
daniele 0:d7f2341ab245 1231
daniele 0:d7f2341ab245 1232 case PICO_IP_MULTICAST_LOOP:
daniele 0:d7f2341ab245 1233 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1234 *(uint8_t *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
daniele 0:d7f2341ab245 1235 } else {
daniele 0:d7f2341ab245 1236 *(uint8_t *)value = 0;
daniele 0:d7f2341ab245 1237 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1238 return -1;
daniele 0:d7f2341ab245 1239 }
daniele 0:d7f2341ab245 1240 break;
daniele 0:d7f2341ab245 1241 #endif /* PICO_SUPPORT_MCAST */
daniele 0:d7f2341ab245 1242
daniele 0:d7f2341ab245 1243 default:
daniele 0:d7f2341ab245 1244 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1245 return -1;
daniele 0:d7f2341ab245 1246 }
daniele 0:d7f2341ab245 1247
daniele 0:d7f2341ab245 1248 return 0;
daniele 0:d7f2341ab245 1249 }
daniele 0:d7f2341ab245 1250
daniele 0:d7f2341ab245 1251
daniele 0:d7f2341ab245 1252 int pico_socket_shutdown(struct pico_socket *s, int mode)
daniele 0:d7f2341ab245 1253 {
daniele 0:d7f2341ab245 1254 if (!s) {
daniele 0:d7f2341ab245 1255 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1256 return -1;
daniele 0:d7f2341ab245 1257 } else {
daniele 0:d7f2341ab245 1258 /* check if exists in tree */
daniele 0:d7f2341ab245 1259 /* See task #178 */
daniele 0:d7f2341ab245 1260 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 1261 pico_free(s); /* close socket after bind or connect failed */
daniele 0:d7f2341ab245 1262 return 0;
daniele 0:d7f2341ab245 1263 }
daniele 0:d7f2341ab245 1264 }
daniele 0:d7f2341ab245 1265
daniele 0:d7f2341ab245 1266 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 1267 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1268 if (mode & PICO_SHUT_RDWR)
daniele 0:d7f2341ab245 1269 pico_socket_alter_state(s, PICO_SOCKET_STATE_CLOSED, PICO_SOCKET_STATE_CLOSING |PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED, 0);
daniele 0:d7f2341ab245 1270 else if (mode & PICO_SHUT_RD)
daniele 0:d7f2341ab245 1271 pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
daniele 0:d7f2341ab245 1272 }
daniele 0:d7f2341ab245 1273 #endif
daniele 0:d7f2341ab245 1274 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1275 if (PROTO(s) == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 1276 if (mode & PICO_SHUT_WR)
daniele 0:d7f2341ab245 1277 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL, 0, 0);
daniele 0:d7f2341ab245 1278 else if (mode & PICO_SHUT_RD)
daniele 0:d7f2341ab245 1279 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
daniele 0:d7f2341ab245 1280 else if (mode & PICO_SHUT_RDWR)
daniele 0:d7f2341ab245 1281 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL | PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
daniele 0:d7f2341ab245 1282 }
daniele 0:d7f2341ab245 1283 #endif
daniele 0:d7f2341ab245 1284 return 0;
daniele 0:d7f2341ab245 1285 }
daniele 0:d7f2341ab245 1286
daniele 0:d7f2341ab245 1287 int pico_socket_close(struct pico_socket *s)
daniele 0:d7f2341ab245 1288 {
daniele 0:d7f2341ab245 1289 return pico_socket_shutdown(s, PICO_SHUT_RDWR);
daniele 0:d7f2341ab245 1290 }
daniele 0:d7f2341ab245 1291
daniele 0:d7f2341ab245 1292 #ifdef PICO_SUPPORT_CRC
daniele 0:d7f2341ab245 1293 static inline int pico_transport_crc_check(struct pico_frame *f)
daniele 0:d7f2341ab245 1294 {
daniele 0:d7f2341ab245 1295 struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr;
daniele 0:d7f2341ab245 1296 struct pico_udp_hdr *udp_hdr = NULL;
daniele 0:d7f2341ab245 1297 uint16_t checksum_invalid = 1;
daniele 0:d7f2341ab245 1298
daniele 0:d7f2341ab245 1299 switch (net_hdr->proto)
daniele 0:d7f2341ab245 1300 {
daniele 0:d7f2341ab245 1301 case PICO_PROTO_TCP:
daniele 0:d7f2341ab245 1302 checksum_invalid = short_be(pico_tcp_checksum_ipv4(f));
daniele 0:d7f2341ab245 1303 //dbg("TCP CRC validation == %u\n", checksum_invalid);
daniele 0:d7f2341ab245 1304 if (checksum_invalid) {
daniele 0:d7f2341ab245 1305 //dbg("TCP CRC: validation failed!\n");
daniele 0:d7f2341ab245 1306 pico_frame_discard(f);
daniele 0:d7f2341ab245 1307 return 0;
daniele 0:d7f2341ab245 1308 }
daniele 0:d7f2341ab245 1309 break;
daniele 0:d7f2341ab245 1310
daniele 0:d7f2341ab245 1311 case PICO_PROTO_UDP:
daniele 0:d7f2341ab245 1312 udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
daniele 0:d7f2341ab245 1313 if (short_be(udp_hdr->crc)) {
daniele 0:d7f2341ab245 1314 checksum_invalid = short_be(pico_udp_checksum_ipv4(f));
daniele 0:d7f2341ab245 1315 //dbg("UDP CRC validation == %u\n", checksum_invalid);
daniele 0:d7f2341ab245 1316 if (checksum_invalid) {
daniele 0:d7f2341ab245 1317 //dbg("UDP CRC: validation failed!\n");
daniele 0:d7f2341ab245 1318 pico_frame_discard(f);
daniele 0:d7f2341ab245 1319 return 0;
daniele 0:d7f2341ab245 1320 }
daniele 0:d7f2341ab245 1321 }
daniele 0:d7f2341ab245 1322 break;
daniele 0:d7f2341ab245 1323
daniele 0:d7f2341ab245 1324 default:
daniele 0:d7f2341ab245 1325 // Do nothing
daniele 0:d7f2341ab245 1326 break;
daniele 0:d7f2341ab245 1327 }
daniele 0:d7f2341ab245 1328 return 1;
daniele 0:d7f2341ab245 1329 }
daniele 0:d7f2341ab245 1330 #else
daniele 0:d7f2341ab245 1331 static inline int pico_transport_crc_check(struct pico_frame *f)
daniele 0:d7f2341ab245 1332 {
daniele 0:d7f2341ab245 1333 return 1;
daniele 0:d7f2341ab245 1334 }
daniele 0:d7f2341ab245 1335 #endif /* PICO_SUPPORT_CRC */
daniele 0:d7f2341ab245 1336
daniele 0:d7f2341ab245 1337 int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f)
daniele 0:d7f2341ab245 1338 {
daniele 0:d7f2341ab245 1339 struct pico_trans *hdr = (struct pico_trans *) f->transport_hdr;
daniele 0:d7f2341ab245 1340 int ret = 0;
daniele 0:d7f2341ab245 1341
daniele 0:d7f2341ab245 1342 if (!hdr) {
daniele 0:d7f2341ab245 1343 pico_err = PICO_ERR_EFAULT;
daniele 0:d7f2341ab245 1344 return -1;
daniele 0:d7f2341ab245 1345 }
daniele 0:d7f2341ab245 1346
daniele 0:d7f2341ab245 1347 ret = pico_transport_crc_check(f);
daniele 0:d7f2341ab245 1348 if (ret < 1)
daniele 0:d7f2341ab245 1349 return ret;
daniele 0:d7f2341ab245 1350 else
daniele 0:d7f2341ab245 1351 ret = 0;
daniele 0:d7f2341ab245 1352
daniele 0:d7f2341ab245 1353 if ((hdr) && (pico_socket_deliver(self, f, hdr->dport) == 0))
daniele 0:d7f2341ab245 1354 return ret;
daniele 0:d7f2341ab245 1355
daniele 0:d7f2341ab245 1356 if (!IS_BCAST(f)) {
daniele 0:d7f2341ab245 1357 dbg("Socket not found... \n");
daniele 0:d7f2341ab245 1358 pico_notify_socket_unreachable(f);
daniele 0:d7f2341ab245 1359 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1360 /* if tcp protocol send RST segment */
daniele 0:d7f2341ab245 1361 //if (self->proto_number == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 1362 // pico_tcp_reply_rst(f);
daniele 0:d7f2341ab245 1363 #endif
daniele 0:d7f2341ab245 1364 ret = -1;
daniele 0:d7f2341ab245 1365 pico_err = PICO_ERR_ENOENT;
daniele 0:d7f2341ab245 1366 }
daniele 0:d7f2341ab245 1367 pico_frame_discard(f);
daniele 0:d7f2341ab245 1368 return ret;
daniele 0:d7f2341ab245 1369 }
daniele 0:d7f2341ab245 1370
daniele 0:d7f2341ab245 1371 #define SL_LOOP_MIN 1
daniele 0:d7f2341ab245 1372
daniele 0:d7f2341ab245 1373
daniele 0:d7f2341ab245 1374 int pico_sockets_loop(int loop_score)
daniele 0:d7f2341ab245 1375 {
daniele 0:d7f2341ab245 1376 static struct pico_tree_node *index_udp, * index_tcp;
daniele 0:d7f2341ab245 1377
daniele 0:d7f2341ab245 1378 struct pico_sockport *start;
daniele 0:d7f2341ab245 1379 struct pico_socket *s;
daniele 0:d7f2341ab245 1380
daniele 0:d7f2341ab245 1381 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 1382 struct pico_frame *f;
daniele 0:d7f2341ab245 1383
daniele 0:d7f2341ab245 1384 if (sp_udp == NULL)
daniele 0:d7f2341ab245 1385 {
daniele 0:d7f2341ab245 1386 index_udp = pico_tree_firstNode(UDPTable.root);
daniele 0:d7f2341ab245 1387 sp_udp = index_udp->keyValue;
daniele 0:d7f2341ab245 1388 }
daniele 0:d7f2341ab245 1389
daniele 0:d7f2341ab245 1390 /* init start node */
daniele 0:d7f2341ab245 1391 start = sp_udp;
daniele 0:d7f2341ab245 1392
daniele 0:d7f2341ab245 1393 /* round-robin all transport protocols, break if traversed all protocols */
daniele 0:d7f2341ab245 1394 while (loop_score > SL_LOOP_MIN && sp_udp != NULL) {
daniele 0:d7f2341ab245 1395 struct pico_tree_node * index;
daniele 0:d7f2341ab245 1396
daniele 0:d7f2341ab245 1397 pico_tree_foreach(index,&sp_udp->socks){
daniele 0:d7f2341ab245 1398 s = index->keyValue;
daniele 0:d7f2341ab245 1399 f = pico_dequeue(&s->q_out);
daniele 0:d7f2341ab245 1400 while (f && (loop_score > 0)) {
daniele 0:d7f2341ab245 1401 pico_proto_udp.push(&pico_proto_udp, f);
daniele 0:d7f2341ab245 1402 loop_score -= 1;
daniele 0:d7f2341ab245 1403 f = pico_dequeue(&s->q_out);
daniele 0:d7f2341ab245 1404 }
daniele 0:d7f2341ab245 1405 }
daniele 0:d7f2341ab245 1406
daniele 0:d7f2341ab245 1407 index_udp = pico_tree_next(index_udp);
daniele 0:d7f2341ab245 1408 sp_udp = index_udp->keyValue;
daniele 0:d7f2341ab245 1409
daniele 0:d7f2341ab245 1410 if (sp_udp == NULL)
daniele 0:d7f2341ab245 1411 {
daniele 0:d7f2341ab245 1412 index_udp = pico_tree_firstNode(UDPTable.root);
daniele 0:d7f2341ab245 1413 sp_udp = index_udp->keyValue;
daniele 0:d7f2341ab245 1414 }
daniele 0:d7f2341ab245 1415 if (sp_udp == start)
daniele 0:d7f2341ab245 1416 break;
daniele 0:d7f2341ab245 1417 }
daniele 0:d7f2341ab245 1418 #endif
daniele 0:d7f2341ab245 1419
daniele 0:d7f2341ab245 1420 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1421 if (sp_tcp == NULL)
daniele 0:d7f2341ab245 1422 {
daniele 0:d7f2341ab245 1423 index_tcp = pico_tree_firstNode(TCPTable.root);
daniele 0:d7f2341ab245 1424 sp_tcp = index_tcp->keyValue;
daniele 0:d7f2341ab245 1425 }
daniele 0:d7f2341ab245 1426
daniele 0:d7f2341ab245 1427 /* init start node */
daniele 0:d7f2341ab245 1428 start = sp_tcp;
daniele 0:d7f2341ab245 1429
daniele 0:d7f2341ab245 1430 while (loop_score > SL_LOOP_MIN && sp_tcp != NULL) {
daniele 0:d7f2341ab245 1431 struct pico_tree_node * index;
daniele 0:d7f2341ab245 1432 pico_tree_foreach(index, &sp_tcp->socks){
daniele 0:d7f2341ab245 1433 s = index->keyValue;
daniele 0:d7f2341ab245 1434 loop_score = pico_tcp_output(s, loop_score);
daniele 0:d7f2341ab245 1435 if ((s->ev_pending) && s->wakeup) {
daniele 0:d7f2341ab245 1436 s->wakeup(s->ev_pending, s);
daniele 0:d7f2341ab245 1437 }
daniele 0:d7f2341ab245 1438 if (loop_score <= 0) {
daniele 0:d7f2341ab245 1439 loop_score = 0;
daniele 0:d7f2341ab245 1440 break;
daniele 0:d7f2341ab245 1441 }
daniele 0:d7f2341ab245 1442 }
daniele 0:d7f2341ab245 1443
daniele 0:d7f2341ab245 1444 /* check if RB_FOREACH ended, if not, break to keep the cur sp_tcp */
daniele 0:d7f2341ab245 1445 if (s != NULL)
daniele 0:d7f2341ab245 1446 break;
daniele 0:d7f2341ab245 1447
daniele 0:d7f2341ab245 1448 index_tcp = pico_tree_next(index_tcp);
daniele 0:d7f2341ab245 1449 sp_tcp = index_tcp->keyValue;
daniele 0:d7f2341ab245 1450
daniele 0:d7f2341ab245 1451 if (sp_tcp == NULL)
daniele 0:d7f2341ab245 1452 {
daniele 0:d7f2341ab245 1453 index_tcp = pico_tree_firstNode(TCPTable.root);
daniele 0:d7f2341ab245 1454 sp_tcp = index_tcp->keyValue;
daniele 0:d7f2341ab245 1455 }
daniele 0:d7f2341ab245 1456 if (sp_tcp == start)
daniele 0:d7f2341ab245 1457 break;
daniele 0:d7f2341ab245 1458 }
daniele 0:d7f2341ab245 1459 #endif
daniele 0:d7f2341ab245 1460
daniele 0:d7f2341ab245 1461 return loop_score;
daniele 0:d7f2341ab245 1462 }
daniele 0:d7f2341ab245 1463
daniele 0:d7f2341ab245 1464
daniele 0:d7f2341ab245 1465 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len)
daniele 0:d7f2341ab245 1466 {
daniele 0:d7f2341ab245 1467 struct pico_frame *f = NULL;
daniele 0:d7f2341ab245 1468
daniele 0:d7f2341ab245 1469 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 1470 if (IS_SOCK_IPV6(s))
daniele 0:d7f2341ab245 1471 f = pico_proto_ipv6.alloc(&pico_proto_ipv6, len);
daniele 0:d7f2341ab245 1472 #endif
daniele 0:d7f2341ab245 1473
daniele 0:d7f2341ab245 1474 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 1475 if (IS_SOCK_IPV4(s))
daniele 0:d7f2341ab245 1476 f = pico_proto_ipv4.alloc(&pico_proto_ipv4, len);
daniele 0:d7f2341ab245 1477 #endif
daniele 0:d7f2341ab245 1478 if (!f) {
daniele 0:d7f2341ab245 1479 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 1480 return f;
daniele 0:d7f2341ab245 1481 }
daniele 0:d7f2341ab245 1482 f->payload = f->transport_hdr;
daniele 0:d7f2341ab245 1483 f->payload_len = len;
daniele 0:d7f2341ab245 1484 f->sock = s;
daniele 0:d7f2341ab245 1485 return f;
daniele 0:d7f2341ab245 1486 }
daniele 0:d7f2341ab245 1487
daniele 0:d7f2341ab245 1488 int pico_transport_error(struct pico_frame *f, uint8_t proto, int code)
daniele 0:d7f2341ab245 1489 {
daniele 0:d7f2341ab245 1490 int ret = -1;
daniele 0:d7f2341ab245 1491 struct pico_trans *trans = (struct pico_trans*) f->transport_hdr;
daniele 0:d7f2341ab245 1492 struct pico_sockport *port = NULL;
daniele 0:d7f2341ab245 1493 struct pico_socket *s = NULL;
daniele 0:d7f2341ab245 1494 switch (proto) {
daniele 0:d7f2341ab245 1495
daniele 0:d7f2341ab245 1496
daniele 0:d7f2341ab245 1497 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 1498 case PICO_PROTO_UDP:
daniele 0:d7f2341ab245 1499 port = pico_get_sockport(proto, trans->sport);
daniele 0:d7f2341ab245 1500 break;
daniele 0:d7f2341ab245 1501 #endif
daniele 0:d7f2341ab245 1502
daniele 0:d7f2341ab245 1503 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1504 case PICO_PROTO_TCP:
daniele 0:d7f2341ab245 1505 port = pico_get_sockport(proto, trans->sport);
daniele 0:d7f2341ab245 1506 break;
daniele 0:d7f2341ab245 1507 #endif
daniele 0:d7f2341ab245 1508
daniele 0:d7f2341ab245 1509 default:
daniele 0:d7f2341ab245 1510 /* Protocol not available */
daniele 0:d7f2341ab245 1511 ret = -1;
daniele 0:d7f2341ab245 1512 }
daniele 0:d7f2341ab245 1513 if (port) {
daniele 0:d7f2341ab245 1514 struct pico_tree_node * index;
daniele 0:d7f2341ab245 1515 ret = 0;
daniele 0:d7f2341ab245 1516
daniele 0:d7f2341ab245 1517 pico_tree_foreach(index,&port->socks) {
daniele 0:d7f2341ab245 1518 s = index->keyValue;
daniele 0:d7f2341ab245 1519 if (trans->dport == s->remote_port) {
daniele 0:d7f2341ab245 1520 if (s->wakeup) {
daniele 0:d7f2341ab245 1521 //dbg("SOCKET ERROR FROM ICMP NOTIFICATION. (icmp code= %d)\n\n", code);
daniele 0:d7f2341ab245 1522 switch(code) {
daniele 0:d7f2341ab245 1523 case PICO_ICMP_UNREACH_PROTOCOL:
daniele 0:d7f2341ab245 1524 pico_err = PICO_ERR_EPROTO;
daniele 0:d7f2341ab245 1525 break;
daniele 0:d7f2341ab245 1526
daniele 0:d7f2341ab245 1527 case PICO_ICMP_UNREACH_PORT:
daniele 0:d7f2341ab245 1528 pico_err = PICO_ERR_ECONNREFUSED;
daniele 0:d7f2341ab245 1529 break;
daniele 0:d7f2341ab245 1530
daniele 0:d7f2341ab245 1531 case PICO_ICMP_UNREACH_NET:
daniele 0:d7f2341ab245 1532 case PICO_ICMP_UNREACH_NET_PROHIB:
daniele 0:d7f2341ab245 1533 case PICO_ICMP_UNREACH_NET_UNKNOWN:
daniele 0:d7f2341ab245 1534 pico_err = PICO_ERR_ENETUNREACH;
daniele 0:d7f2341ab245 1535 break;
daniele 0:d7f2341ab245 1536
daniele 0:d7f2341ab245 1537 default:
daniele 0:d7f2341ab245 1538 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 0:d7f2341ab245 1539 }
daniele 0:d7f2341ab245 1540 s->wakeup(PICO_SOCK_EV_ERR, s);
daniele 0:d7f2341ab245 1541 }
daniele 0:d7f2341ab245 1542 break;
daniele 0:d7f2341ab245 1543 }
daniele 0:d7f2341ab245 1544 }
daniele 0:d7f2341ab245 1545 }
daniele 0:d7f2341ab245 1546 pico_frame_discard(f);
daniele 0:d7f2341ab245 1547 return ret;
daniele 0:d7f2341ab245 1548 }
daniele 0:d7f2341ab245 1549 #endif
daniele 0:d7f2341ab245 1550 #endif