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:
Tue Sep 17 07:25:24 2013 +0000
Revision:
64:0225b609335e
Parent:
51:ab4529a384a6
Child:
66:71a2ef45a035
Issue #27. No more memory leaks from dns and udp.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 29:1a47b7151851 1 /*********************************************************************
daniele 29:1a47b7151851 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 29:1a47b7151851 3 See LICENSE and COPYING for usage.
daniele 29:1a47b7151851 4
daniele 29:1a47b7151851 5
daniele 29:1a47b7151851 6 Authors: Daniele Lacamera
daniele 29:1a47b7151851 7 *********************************************************************/
daniele 29:1a47b7151851 8
daniele 29:1a47b7151851 9
daniele 29:1a47b7151851 10 #include "pico_config.h"
daniele 29:1a47b7151851 11 #include "pico_queue.h"
daniele 29:1a47b7151851 12 #include "pico_socket.h"
daniele 29:1a47b7151851 13 #include "pico_ipv4.h"
daniele 29:1a47b7151851 14 #include "pico_ipv6.h"
daniele 29:1a47b7151851 15 #include "pico_udp.h"
daniele 29:1a47b7151851 16 #include "pico_tcp.h"
daniele 29:1a47b7151851 17 #include "pico_stack.h"
daniele 29:1a47b7151851 18 #include "pico_icmp4.h"
daniele 29:1a47b7151851 19 #include "pico_nat.h"
daniele 29:1a47b7151851 20 #include "pico_tree.h"
daniele 29:1a47b7151851 21 #include "pico_device.h"
daniele 29:1a47b7151851 22
daniele 29:1a47b7151851 23 #if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6)
daniele 29:1a47b7151851 24 #if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP)
daniele 29:1a47b7151851 25
daniele 29:1a47b7151851 26
tass 48:40fc4462265c 27 #define PROTO(s) ((s)->proto->proto_number)
tass 48:40fc4462265c 28 #define PICO_SOCKET4_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */
tass 48:40fc4462265c 29 #define PICO_SOCKET6_MTU 1460 /* Ethernet MTU(1500) - IP header size(40) */
tass 48:40fc4462265c 30
daniele 29:1a47b7151851 31 #ifdef PICO_SUPPORT_MUTEX
daniele 29:1a47b7151851 32 static void * Mutex = NULL;
daniele 29:1a47b7151851 33 #define LOCK(x) {\
daniele 29:1a47b7151851 34 if (x == NULL) \
daniele 29:1a47b7151851 35 x = pico_mutex_init(); \
daniele 29:1a47b7151851 36 pico_mutex_lock(x); \
daniele 29:1a47b7151851 37 }
daniele 29:1a47b7151851 38 #define UNLOCK(x) pico_mutex_unlock(x);
daniele 29:1a47b7151851 39
daniele 29:1a47b7151851 40 #else
daniele 29:1a47b7151851 41 #define LOCK(x) do{}while(0)
daniele 29:1a47b7151851 42 #define UNLOCK(x) do{}while(0)
daniele 29:1a47b7151851 43 #endif
daniele 29:1a47b7151851 44
daniele 29:1a47b7151851 45
daniele 29:1a47b7151851 46 #define PROTO(s) ((s)->proto->proto_number)
daniele 29:1a47b7151851 47
daniele 29:1a47b7151851 48 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 49 # define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY)))))
daniele 29:1a47b7151851 50 #endif
daniele 29:1a47b7151851 51
daniele 29:1a47b7151851 52 #define PICO_SOCKET_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */
daniele 29:1a47b7151851 53
daniele 29:1a47b7151851 54 #ifdef PICO_SUPPORT_IPV4
daniele 29:1a47b7151851 55 # define IS_SOCK_IPV4(s) ((s->net == &pico_proto_ipv4))
daniele 29:1a47b7151851 56 #else
daniele 29:1a47b7151851 57 # define IS_SOCK_IPV4(s) (0)
daniele 29:1a47b7151851 58 #endif
daniele 29:1a47b7151851 59
daniele 29:1a47b7151851 60 #ifdef PICO_SUPPORT_IPV6
daniele 29:1a47b7151851 61 # define IS_SOCK_IPV6(s) ((s->net == &pico_proto_ipv6))
daniele 29:1a47b7151851 62 #else
daniele 29:1a47b7151851 63 # define IS_SOCK_IPV6(s) (0)
daniele 29:1a47b7151851 64 #endif
daniele 29:1a47b7151851 65
daniele 29:1a47b7151851 66 #ifdef PICO_SUPPORT_IPFRAG
daniele 29:1a47b7151851 67 # define frag_dbg(...) do{}while(0)
daniele 29:1a47b7151851 68 #endif
daniele 29:1a47b7151851 69
daniele 29:1a47b7151851 70 #ifdef PICO_SUPPORT_MCAST
daniele 29:1a47b7151851 71 # define so_mcast_dbg(...) do{}while(0) /* ip_mcast_dbg in pico_ipv4.c */
daniele 29:1a47b7151851 72 #endif
daniele 29:1a47b7151851 73
daniele 29:1a47b7151851 74 static struct pico_sockport *sp_udp = NULL ,*sp_tcp = NULL;
daniele 29:1a47b7151851 75
daniele 29:1a47b7151851 76 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len);
daniele 29:1a47b7151851 77
daniele 29:1a47b7151851 78 static int socket_cmp(void * ka, void * kb)
daniele 29:1a47b7151851 79 {
daniele 29:1a47b7151851 80 struct pico_socket *a = ka, *b = kb;
daniele 29:1a47b7151851 81 int a_is_ip6 = is_sock_ipv6(a);
daniele 29:1a47b7151851 82 int b_is_ip6 = is_sock_ipv6(b);
daniele 29:1a47b7151851 83
daniele 29:1a47b7151851 84 int diff;
daniele 29:1a47b7151851 85
daniele 29:1a47b7151851 86 /* First, order by network ver */
daniele 29:1a47b7151851 87 if (a_is_ip6 < b_is_ip6)
daniele 29:1a47b7151851 88 return -1;
daniele 29:1a47b7151851 89 if (a_is_ip6 > b_is_ip6)
daniele 29:1a47b7151851 90 return 1;
daniele 29:1a47b7151851 91
daniele 29:1a47b7151851 92 /* If either socket is PICO_IPV4_INADDR_ANY mode, skip local address comparison */
daniele 29:1a47b7151851 93
daniele 29:1a47b7151851 94 /* At this point, sort by local host */
daniele 29:1a47b7151851 95
daniele 29:1a47b7151851 96 if (0) {
daniele 29:1a47b7151851 97 #ifdef PICO_SUPPORT_IPV6
daniele 29:1a47b7151851 98 } else if (a_is_ip6) {
daniele 29:1a47b7151851 99 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 29:1a47b7151851 100 diff = 0;
daniele 29:1a47b7151851 101 else
daniele 29:1a47b7151851 102 diff = memcmp(a->local_addr.ip6.addr, b->local_addr.ip6.addr, PICO_SIZE_IP6);
daniele 29:1a47b7151851 103 #endif
daniele 29:1a47b7151851 104 } else {
daniele 29:1a47b7151851 105 if ((a->local_addr.ip4.addr == PICO_IP4_ANY) || (b->local_addr.ip4.addr == PICO_IP4_ANY))
daniele 29:1a47b7151851 106 diff = 0;
daniele 29:1a47b7151851 107 else
daniele 29:1a47b7151851 108 diff = a->local_addr.ip4.addr - b->local_addr.ip4.addr;
daniele 29:1a47b7151851 109 }
daniele 29:1a47b7151851 110
daniele 29:1a47b7151851 111 if (diff)
daniele 29:1a47b7151851 112 return diff;
daniele 29:1a47b7151851 113
daniele 29:1a47b7151851 114
daniele 29:1a47b7151851 115 /* Sort by remote host */
daniele 29:1a47b7151851 116 if (a_is_ip6)
daniele 29:1a47b7151851 117 diff = memcmp(a->remote_addr.ip6.addr, b->remote_addr.ip6.addr, PICO_SIZE_IP6);
daniele 29:1a47b7151851 118 else
daniele 29:1a47b7151851 119 diff = a->remote_addr.ip4.addr - b->remote_addr.ip4.addr;
daniele 29:1a47b7151851 120
daniele 29:1a47b7151851 121 if (diff)
daniele 29:1a47b7151851 122 return diff;
daniele 29:1a47b7151851 123
daniele 29:1a47b7151851 124 /* And finally by remote port. The two sockets are coincident if the quad is the same. */
daniele 29:1a47b7151851 125 return b->remote_port - a->remote_port;
daniele 29:1a47b7151851 126 }
daniele 29:1a47b7151851 127
daniele 29:1a47b7151851 128 struct pico_sockport
daniele 29:1a47b7151851 129 {
daniele 29:1a47b7151851 130 struct pico_tree socks; // how you make the connection ?
daniele 29:1a47b7151851 131 uint16_t number;
daniele 29:1a47b7151851 132 uint16_t proto;
daniele 29:1a47b7151851 133 };
daniele 29:1a47b7151851 134
daniele 29:1a47b7151851 135 #define INIT_SOCKPORT { {&LEAF , socket_cmp}, 0, 0 }
daniele 29:1a47b7151851 136
daniele 29:1a47b7151851 137 int sockport_cmp(void * ka, void * kb)
daniele 29:1a47b7151851 138 {
daniele 29:1a47b7151851 139 struct pico_sockport *a = ka, *b = kb;
daniele 29:1a47b7151851 140 if (a->number < b->number)
daniele 29:1a47b7151851 141 return -1;
daniele 29:1a47b7151851 142 if (a->number > b->number)
daniele 29:1a47b7151851 143 return 1;
daniele 29:1a47b7151851 144 return 0;
daniele 29:1a47b7151851 145 }
daniele 29:1a47b7151851 146
daniele 29:1a47b7151851 147 PICO_TREE_DECLARE(UDPTable,sockport_cmp);
daniele 29:1a47b7151851 148 PICO_TREE_DECLARE(TCPTable,sockport_cmp);
daniele 29:1a47b7151851 149
daniele 29:1a47b7151851 150 #ifdef PICO_SUPPORT_MCAST
daniele 29:1a47b7151851 151 /* socket
daniele 29:1a47b7151851 152 * |
daniele 29:1a47b7151851 153 * MCASTListen
daniele 29:1a47b7151851 154 * | | |
daniele 29:1a47b7151851 155 * ------------ | ------------
daniele 29:1a47b7151851 156 * | | |
daniele 29:1a47b7151851 157 * MCASTSources MCASTSources MCASTSources
daniele 29:1a47b7151851 158 * | | | | | | | | | | | |
daniele 29:1a47b7151851 159 * S S S S S S S S S S S S
daniele 29:1a47b7151851 160 *
daniele 29:1a47b7151851 161 * MCASTListen: RBTree(mcast_link, mcast_group)
daniele 29:1a47b7151851 162 * MCASTSources: RBTree(source)
daniele 29:1a47b7151851 163 */
daniele 29:1a47b7151851 164 struct pico_mcast_listen
daniele 29:1a47b7151851 165 {
daniele 29:1a47b7151851 166 uint8_t filter_mode;
daniele 29:1a47b7151851 167 struct pico_ip4 mcast_link;
daniele 29:1a47b7151851 168 struct pico_ip4 mcast_group;
daniele 29:1a47b7151851 169 struct pico_tree MCASTSources;
daniele 29:1a47b7151851 170 };
daniele 29:1a47b7151851 171
daniele 29:1a47b7151851 172 static int mcast_listen_cmp(void *ka, void *kb)
daniele 29:1a47b7151851 173 {
daniele 29:1a47b7151851 174 struct pico_mcast_listen *a = ka, *b = kb;
daniele 29:1a47b7151851 175 if (a->mcast_group.addr < b->mcast_group.addr)
daniele 29:1a47b7151851 176 return -1;
daniele 29:1a47b7151851 177 if (a->mcast_group.addr > b->mcast_group.addr)
daniele 29:1a47b7151851 178 return 1;
daniele 29:1a47b7151851 179
daniele 29:1a47b7151851 180 if (a->mcast_link.addr < b->mcast_link.addr)
daniele 29:1a47b7151851 181 return -1;
daniele 29:1a47b7151851 182 if (a->mcast_link.addr > b->mcast_link.addr)
daniele 29:1a47b7151851 183 return 1;
daniele 29:1a47b7151851 184
daniele 29:1a47b7151851 185 return 0;
daniele 29:1a47b7151851 186 }
daniele 29:1a47b7151851 187
daniele 29:1a47b7151851 188 static int mcast_sources_cmp(void *ka, void *kb)
daniele 29:1a47b7151851 189 {
daniele 29:1a47b7151851 190 struct pico_ip4 *a = ka, *b = kb;
daniele 29:1a47b7151851 191 if (a->addr < b->addr)
daniele 29:1a47b7151851 192 return -1;
daniele 29:1a47b7151851 193 if (a->addr > b->addr)
daniele 29:1a47b7151851 194 return 1;
daniele 29:1a47b7151851 195 return 0;
daniele 29:1a47b7151851 196 }
daniele 29:1a47b7151851 197
daniele 29:1a47b7151851 198 static int mcast_socket_cmp(void *ka, void *kb)
daniele 29:1a47b7151851 199 {
daniele 29:1a47b7151851 200 struct pico_socket *a = ka, *b = kb;
daniele 29:1a47b7151851 201 if (a < b)
daniele 29:1a47b7151851 202 return -1;
daniele 29:1a47b7151851 203 if (a > b)
daniele 29:1a47b7151851 204 return 1;
daniele 29:1a47b7151851 205 return 0;
daniele 29:1a47b7151851 206 }
daniele 29:1a47b7151851 207 /* gather all multicast sockets to hasten filter aggregation */
daniele 29:1a47b7151851 208 PICO_TREE_DECLARE(MCASTSockets, mcast_socket_cmp);
daniele 29:1a47b7151851 209
daniele 29:1a47b7151851 210 static int mcast_filter_cmp(void *ka, void *kb)
daniele 29:1a47b7151851 211 {
daniele 29:1a47b7151851 212 struct pico_ip4 *a = ka, *b = kb;
daniele 29:1a47b7151851 213 if (a->addr < b->addr)
daniele 29:1a47b7151851 214 return -1;
daniele 29:1a47b7151851 215 if (a->addr > b->addr)
daniele 29:1a47b7151851 216 return 1;
daniele 29:1a47b7151851 217 return 0;
daniele 29:1a47b7151851 218 }
daniele 29:1a47b7151851 219 /* gather sources to be filtered */
daniele 29:1a47b7151851 220 PICO_TREE_DECLARE(MCASTFilter, mcast_filter_cmp);
daniele 29:1a47b7151851 221
daniele 29:1a47b7151851 222 /* MCASTFilter will be empty if no socket is listening on mcast_group on mcast_link anymore */
daniele 29:1a47b7151851 223 static int pico_socket_aggregate_mcastfilters(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group)
daniele 29:1a47b7151851 224 {
daniele 29:1a47b7151851 225 uint8_t filter_mode = PICO_IP_MULTICAST_INCLUDE;
daniele 29:1a47b7151851 226 struct pico_mcast_listen *listen = NULL, ltest = {0};
daniele 29:1a47b7151851 227 struct pico_ip4 *source = NULL;
daniele 29:1a47b7151851 228 struct pico_socket *mcast_sock = NULL;
daniele 29:1a47b7151851 229 struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
daniele 29:1a47b7151851 230
daniele 29:1a47b7151851 231 ltest.mcast_link = *mcast_link;
daniele 29:1a47b7151851 232 ltest.mcast_group = *mcast_group;
daniele 29:1a47b7151851 233
daniele 29:1a47b7151851 234 /* cleanup old filter */
daniele 29:1a47b7151851 235 pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
daniele 29:1a47b7151851 236 {
daniele 29:1a47b7151851 237 pico_tree_delete(&MCASTFilter, index->keyValue);
daniele 29:1a47b7151851 238 }
daniele 29:1a47b7151851 239
daniele 29:1a47b7151851 240 /* construct new filter */
daniele 29:1a47b7151851 241 pico_tree_foreach(index, &MCASTSockets)
daniele 29:1a47b7151851 242 {
daniele 29:1a47b7151851 243 mcast_sock = index->keyValue;
daniele 29:1a47b7151851 244 listen = pico_tree_findKey(mcast_sock->MCASTListen, &ltest);
daniele 29:1a47b7151851 245 if (listen) {
daniele 29:1a47b7151851 246 /* aggregate filter */
daniele 29:1a47b7151851 247 switch(filter_mode)
daniele 29:1a47b7151851 248 {
daniele 29:1a47b7151851 249 case PICO_IP_MULTICAST_INCLUDE:
daniele 29:1a47b7151851 250 switch (listen->filter_mode)
daniele 29:1a47b7151851 251 {
daniele 29:1a47b7151851 252 case PICO_IP_MULTICAST_INCLUDE:
daniele 29:1a47b7151851 253 /* filter = summation of INCLUDEs */
daniele 29:1a47b7151851 254 /* mode stays INCLUDE, add all sources to filter */
daniele 29:1a47b7151851 255 pico_tree_foreach(index2, &listen->MCASTSources)
daniele 29:1a47b7151851 256 {
daniele 29:1a47b7151851 257 source = index2->keyValue;
daniele 29:1a47b7151851 258 pico_tree_insert(&MCASTFilter, source);
daniele 29:1a47b7151851 259 }
daniele 29:1a47b7151851 260 break;
daniele 29:1a47b7151851 261
daniele 29:1a47b7151851 262 case PICO_IP_MULTICAST_EXCLUDE:
daniele 29:1a47b7151851 263 /* filter = EXCLUDE - INCLUDE */
daniele 29:1a47b7151851 264 /* delete from the interface INCLUDE filter any source NOT in the socket EXCLUDE filter */
daniele 29:1a47b7151851 265 pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2)
daniele 29:1a47b7151851 266 {
daniele 29:1a47b7151851 267 source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue);
daniele 29:1a47b7151851 268 if (!source)
daniele 29:1a47b7151851 269 pico_tree_delete(&MCASTFilter, index2->keyValue);
daniele 29:1a47b7151851 270 }
daniele 29:1a47b7151851 271 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
daniele 29:1a47b7151851 272 filter_mode = PICO_IP_MULTICAST_EXCLUDE;
daniele 29:1a47b7151851 273 /* add to the interface EXCLUDE filter any socket source NOT in the former interface INCLUDE filter */
daniele 29:1a47b7151851 274 pico_tree_foreach(index2, &listen->MCASTSources)
daniele 29:1a47b7151851 275 {
daniele 29:1a47b7151851 276 source = pico_tree_insert(&MCASTFilter, index2->keyValue);
daniele 29:1a47b7151851 277 if (source)
daniele 29:1a47b7151851 278 pico_tree_delete(&MCASTFilter, source);
daniele 29:1a47b7151851 279 }
daniele 29:1a47b7151851 280 break;
daniele 29:1a47b7151851 281
daniele 29:1a47b7151851 282 default:
daniele 29:1a47b7151851 283 return -1;
daniele 29:1a47b7151851 284 }
daniele 29:1a47b7151851 285 break;
daniele 29:1a47b7151851 286
daniele 29:1a47b7151851 287 case PICO_IP_MULTICAST_EXCLUDE:
daniele 29:1a47b7151851 288 switch (listen->filter_mode)
daniele 29:1a47b7151851 289 {
daniele 29:1a47b7151851 290 case PICO_IP_MULTICAST_INCLUDE:
daniele 29:1a47b7151851 291 /* filter = EXCLUDE - INCLUDE */
daniele 29:1a47b7151851 292 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
daniele 29:1a47b7151851 293 /* remove from the interface EXCLUDE filter any source in the socket INCLUDE filter */
daniele 29:1a47b7151851 294 pico_tree_foreach(index2, &listen->MCASTSources)
daniele 29:1a47b7151851 295 {
daniele 29:1a47b7151851 296 source = pico_tree_findKey(&MCASTFilter, index2->keyValue);
daniele 29:1a47b7151851 297 if (source)
daniele 29:1a47b7151851 298 pico_tree_delete(&MCASTFilter, source);
daniele 29:1a47b7151851 299 }
daniele 29:1a47b7151851 300 break;
daniele 29:1a47b7151851 301
daniele 29:1a47b7151851 302 case PICO_IP_MULTICAST_EXCLUDE:
daniele 29:1a47b7151851 303 /* filter = intersection of EXCLUDEs */
daniele 29:1a47b7151851 304 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
daniele 29:1a47b7151851 305 /* remove from the interface EXCLUDE filter any source not in the socket EXCLUDE filter */
daniele 29:1a47b7151851 306 pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2)
daniele 29:1a47b7151851 307 {
daniele 29:1a47b7151851 308 source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue);
daniele 29:1a47b7151851 309 if (!source)
daniele 29:1a47b7151851 310 pico_tree_delete(&MCASTFilter, index2->keyValue);
daniele 29:1a47b7151851 311 }
daniele 29:1a47b7151851 312 break;
daniele 29:1a47b7151851 313
daniele 29:1a47b7151851 314 default:
daniele 29:1a47b7151851 315 return -1;
daniele 29:1a47b7151851 316 }
daniele 29:1a47b7151851 317 break;
daniele 29:1a47b7151851 318
daniele 29:1a47b7151851 319 default:
daniele 29:1a47b7151851 320 return -1;
daniele 29:1a47b7151851 321 }
daniele 29:1a47b7151851 322 }
daniele 29:1a47b7151851 323 }
daniele 29:1a47b7151851 324 return filter_mode;
daniele 29:1a47b7151851 325 }
daniele 29:1a47b7151851 326
daniele 29:1a47b7151851 327 static int pico_socket_mcast_filter(struct pico_socket *s, struct pico_ip4 *mcast_group, struct pico_ip4 *src)
daniele 29:1a47b7151851 328 {
daniele 29:1a47b7151851 329 struct pico_ipv4_link *mcast_link = NULL;
daniele 29:1a47b7151851 330 struct pico_mcast_listen *listen = NULL, ltest = {0};
daniele 29:1a47b7151851 331 struct pico_tree_node *index = NULL;
daniele 29:1a47b7151851 332
daniele 29:1a47b7151851 333 /* no multicast enabled on socket */
daniele 29:1a47b7151851 334 if (!s->MCASTListen)
daniele 29:1a47b7151851 335 return 0;
daniele 29:1a47b7151851 336
daniele 29:1a47b7151851 337 mcast_link = pico_ipv4_link_get(&s->local_addr.ip4);
daniele 29:1a47b7151851 338 if (!mcast_link)
daniele 29:1a47b7151851 339 return -1;
daniele 29:1a47b7151851 340
daniele 29:1a47b7151851 341 ltest.mcast_link.addr = mcast_link->address.addr;
daniele 29:1a47b7151851 342 ltest.mcast_group = *mcast_group;
daniele 29:1a47b7151851 343 listen = pico_tree_findKey(s->MCASTListen, &ltest);
daniele 29:1a47b7151851 344 if (!listen)
daniele 29:1a47b7151851 345 return -1;
daniele 29:1a47b7151851 346
daniele 29:1a47b7151851 347 /* perform source filtering */
daniele 29:1a47b7151851 348 switch (listen->filter_mode)
daniele 29:1a47b7151851 349 {
daniele 29:1a47b7151851 350 case PICO_IP_MULTICAST_INCLUDE:
daniele 29:1a47b7151851 351 pico_tree_foreach(index, &listen->MCASTSources)
daniele 29:1a47b7151851 352 {
daniele 29:1a47b7151851 353 if (src->addr == ((struct pico_ip4 *)index->keyValue)->addr) {
daniele 29:1a47b7151851 354 so_mcast_dbg("MCAST: IP %08X in included socket source list\n", src->addr);
daniele 29:1a47b7151851 355 return 0;
daniele 29:1a47b7151851 356 }
daniele 29:1a47b7151851 357 }
daniele 29:1a47b7151851 358 so_mcast_dbg("MCAST: IP %08X NOT in included socket source list\n", src->addr);
daniele 29:1a47b7151851 359 return -1;
daniele 29:1a47b7151851 360 break;
daniele 29:1a47b7151851 361
daniele 29:1a47b7151851 362 case PICO_IP_MULTICAST_EXCLUDE:
daniele 29:1a47b7151851 363 pico_tree_foreach(index, &listen->MCASTSources)
daniele 29:1a47b7151851 364 {
daniele 29:1a47b7151851 365 if (src->addr == ((struct pico_ip4 *)index->keyValue)->addr) {
daniele 29:1a47b7151851 366 so_mcast_dbg("MCAST: IP %08X in excluded socket source list\n", src->addr);
daniele 29:1a47b7151851 367 return -1;
daniele 29:1a47b7151851 368 }
daniele 29:1a47b7151851 369 }
daniele 29:1a47b7151851 370 so_mcast_dbg("MCAST: IP %08X NOT in excluded socket source list\n", src->addr);
daniele 29:1a47b7151851 371 return 0;
daniele 29:1a47b7151851 372 break;
daniele 29:1a47b7151851 373
daniele 29:1a47b7151851 374 default:
daniele 29:1a47b7151851 375 return -1;
daniele 29:1a47b7151851 376 break;
daniele 29:1a47b7151851 377 }
daniele 29:1a47b7151851 378 return -1;
daniele 29:1a47b7151851 379 }
daniele 29:1a47b7151851 380
daniele 29:1a47b7151851 381 static inline struct pico_ipv4_link *pico_socket_setoption_mcastargs_validation(struct pico_ip_mreq *mreq, struct pico_ip_mreq_source *mreq_source)
daniele 29:1a47b7151851 382 {
daniele 29:1a47b7151851 383 struct pico_ipv4_link *mcast_link = NULL;
daniele 29:1a47b7151851 384
daniele 29:1a47b7151851 385 if (!mreq && !mreq_source)
daniele 29:1a47b7151851 386 return NULL;
daniele 29:1a47b7151851 387
daniele 29:1a47b7151851 388 if (mreq) {
daniele 29:1a47b7151851 389 if (!mreq->mcast_group_addr.addr)
daniele 29:1a47b7151851 390 return NULL;
daniele 29:1a47b7151851 391 if (pico_ipv4_is_unicast(mreq->mcast_group_addr.addr))
daniele 29:1a47b7151851 392 return NULL;
daniele 29:1a47b7151851 393
daniele 29:1a47b7151851 394 if (!mreq->mcast_link_addr.addr) {
daniele 29:1a47b7151851 395 mcast_link = pico_ipv4_get_default_mcastlink();
daniele 29:1a47b7151851 396 if (!mcast_link)
daniele 29:1a47b7151851 397 return NULL;
daniele 29:1a47b7151851 398 } else {
daniele 29:1a47b7151851 399 mcast_link = pico_ipv4_link_get(&mreq->mcast_link_addr);
daniele 29:1a47b7151851 400 if (!mcast_link)
daniele 29:1a47b7151851 401 return NULL;
daniele 29:1a47b7151851 402 }
daniele 29:1a47b7151851 403 }
daniele 29:1a47b7151851 404 if (mreq_source) {
daniele 29:1a47b7151851 405 if (!mreq_source->mcast_group_addr.addr)
daniele 29:1a47b7151851 406 return NULL;
daniele 29:1a47b7151851 407 if (pico_ipv4_is_unicast(mreq_source->mcast_group_addr.addr))
daniele 29:1a47b7151851 408 return NULL;
daniele 29:1a47b7151851 409
daniele 29:1a47b7151851 410 if (!mreq_source->mcast_source_addr.addr)
daniele 29:1a47b7151851 411 return NULL;
daniele 29:1a47b7151851 412 if (!pico_ipv4_is_unicast(mreq_source->mcast_source_addr.addr))
daniele 29:1a47b7151851 413 return NULL;
daniele 29:1a47b7151851 414
daniele 29:1a47b7151851 415 if (!mreq_source->mcast_link_addr.addr) {
daniele 29:1a47b7151851 416 mcast_link = pico_ipv4_get_default_mcastlink();
daniele 29:1a47b7151851 417 if (!mcast_link)
daniele 29:1a47b7151851 418 return NULL;
daniele 29:1a47b7151851 419 } else {
daniele 29:1a47b7151851 420 mcast_link = pico_ipv4_link_get(&mreq_source->mcast_link_addr);
daniele 29:1a47b7151851 421 if (!mcast_link)
daniele 29:1a47b7151851 422 return NULL;
daniele 29:1a47b7151851 423 }
daniele 29:1a47b7151851 424 }
daniele 29:1a47b7151851 425 return mcast_link;
daniele 29:1a47b7151851 426 }
daniele 29:1a47b7151851 427 #else
daniele 29:1a47b7151851 428 static int pico_socket_mcast_filter(struct pico_socket *s, struct pico_ip4 *mcast_group, struct pico_ip4 *src) {
daniele 29:1a47b7151851 429 return 0;
daniele 29:1a47b7151851 430 }
daniele 29:1a47b7151851 431 #endif /* PICO_SUPPORT_MCAST */
daniele 29:1a47b7151851 432
daniele 29:1a47b7151851 433 static struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port)
daniele 29:1a47b7151851 434 {
daniele 29:1a47b7151851 435 struct pico_sockport test = INIT_SOCKPORT;
daniele 29:1a47b7151851 436 test.number = port;
daniele 29:1a47b7151851 437
daniele 29:1a47b7151851 438 if (proto == PICO_PROTO_UDP)
daniele 29:1a47b7151851 439 return pico_tree_findKey(&UDPTable,&test);
daniele 29:1a47b7151851 440
daniele 29:1a47b7151851 441 else if (proto == PICO_PROTO_TCP)
daniele 29:1a47b7151851 442 return pico_tree_findKey(&TCPTable,&test);
daniele 29:1a47b7151851 443
daniele 29:1a47b7151851 444 else return NULL;
daniele 29:1a47b7151851 445 }
daniele 29:1a47b7151851 446
daniele 29:1a47b7151851 447 int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net)
daniele 29:1a47b7151851 448 {
daniele 29:1a47b7151851 449 struct pico_sockport *sp;
daniele 29:1a47b7151851 450 struct pico_ip4 ip;
daniele 29:1a47b7151851 451 sp = pico_get_sockport(proto, port);
daniele 29:1a47b7151851 452
daniele 29:1a47b7151851 453 if (!net)
daniele 29:1a47b7151851 454 net = &pico_proto_ipv4;
daniele 29:1a47b7151851 455
daniele 29:1a47b7151851 456 /** IPv6 (wip) ***/
daniele 29:1a47b7151851 457 if (net != &pico_proto_ipv4) {
daniele 29:1a47b7151851 458 dbg("IPV6!!!!!\n");
daniele 29:1a47b7151851 459 return (!sp);
daniele 29:1a47b7151851 460 }
daniele 29:1a47b7151851 461
daniele 29:1a47b7151851 462 /* IPv4 */
daniele 29:1a47b7151851 463 #ifdef PICO_SUPPORT_NAT
tass 51:ab4529a384a6 464 if (pico_ipv4_nat_find(port, NULL, 0, proto)) {
daniele 29:1a47b7151851 465 dbg("In use by nat....\n");
daniele 29:1a47b7151851 466 return 0;
daniele 29:1a47b7151851 467 }
daniele 29:1a47b7151851 468 #endif
daniele 29:1a47b7151851 469 if (addr)
daniele 29:1a47b7151851 470 ip.addr = ((struct pico_ip4 *)addr)->addr;
daniele 29:1a47b7151851 471 else
daniele 29:1a47b7151851 472 ip.addr = PICO_IPV4_INADDR_ANY;
daniele 29:1a47b7151851 473
daniele 29:1a47b7151851 474 if (ip.addr == PICO_IPV4_INADDR_ANY) {
daniele 29:1a47b7151851 475 if (!sp) return 1;
daniele 29:1a47b7151851 476 else {
daniele 29:1a47b7151851 477 dbg("In use, and asked for ANY\n");
daniele 29:1a47b7151851 478 return 0;
daniele 29:1a47b7151851 479 }
daniele 29:1a47b7151851 480 }
daniele 29:1a47b7151851 481 if (sp) {
daniele 29:1a47b7151851 482 struct pico_ip4 *s_local;
daniele 29:1a47b7151851 483 struct pico_tree_node *idx;
daniele 29:1a47b7151851 484 struct pico_socket *s;
daniele 29:1a47b7151851 485 pico_tree_foreach(idx, &sp->socks) {
daniele 29:1a47b7151851 486 s = idx->keyValue;
daniele 29:1a47b7151851 487 if (s->net == &pico_proto_ipv4) {
daniele 29:1a47b7151851 488 s_local = (struct pico_ip4*) &s->local_addr;
daniele 29:1a47b7151851 489 if ((s_local->addr == PICO_IPV4_INADDR_ANY) || (s_local->addr == ip.addr))
daniele 29:1a47b7151851 490 return 0;
daniele 29:1a47b7151851 491 }
daniele 29:1a47b7151851 492 }
daniele 29:1a47b7151851 493 }
daniele 29:1a47b7151851 494 return 1;
daniele 29:1a47b7151851 495 }
daniele 29:1a47b7151851 496
daniele 29:1a47b7151851 497 static int pico_check_socket(struct pico_socket *s)
daniele 29:1a47b7151851 498 {
daniele 29:1a47b7151851 499 struct pico_sockport *test;
daniele 29:1a47b7151851 500 struct pico_socket *found;
daniele 29:1a47b7151851 501 struct pico_tree_node * index;
daniele 29:1a47b7151851 502
daniele 29:1a47b7151851 503 test = pico_get_sockport(PROTO(s), s->local_port);
daniele 29:1a47b7151851 504
daniele 29:1a47b7151851 505 if (!test) {
daniele 29:1a47b7151851 506 return -1;
daniele 29:1a47b7151851 507 }
daniele 29:1a47b7151851 508
daniele 29:1a47b7151851 509 pico_tree_foreach(index,&test->socks){
daniele 29:1a47b7151851 510 found = index->keyValue;
daniele 29:1a47b7151851 511 if (s == found) {
daniele 29:1a47b7151851 512 return 0;
daniele 29:1a47b7151851 513 }
daniele 29:1a47b7151851 514 }
daniele 29:1a47b7151851 515
daniele 29:1a47b7151851 516 return -1;
daniele 29:1a47b7151851 517 }
daniele 29:1a47b7151851 518
tass 49:4b404dd2c97a 519 struct pico_socket* pico_sockets_find(uint16_t local,uint16_t remote)
tass 49:4b404dd2c97a 520 {
tass 51:ab4529a384a6 521 struct pico_socket * sock = NULL;
tass 51:ab4529a384a6 522 struct pico_tree_node *index = NULL;
tass 51:ab4529a384a6 523 struct pico_sockport *sp = NULL;
tass 49:4b404dd2c97a 524
tass 51:ab4529a384a6 525 sp = pico_get_sockport(PICO_PROTO_TCP,local);
tass 51:ab4529a384a6 526 if(sp)
tass 51:ab4529a384a6 527 {
tass 51:ab4529a384a6 528 pico_tree_foreach(index,&sp->socks)
tass 51:ab4529a384a6 529 {
tass 51:ab4529a384a6 530 if( ((struct pico_socket *)index->keyValue)->remote_port == remote)
tass 51:ab4529a384a6 531 {
tass 51:ab4529a384a6 532 sock = (struct pico_socket *)index->keyValue;
tass 51:ab4529a384a6 533 break;
tass 51:ab4529a384a6 534 }
tass 51:ab4529a384a6 535 }
tass 51:ab4529a384a6 536 }
tass 49:4b404dd2c97a 537
tass 51:ab4529a384a6 538 return sock;
tass 49:4b404dd2c97a 539 }
tass 49:4b404dd2c97a 540
daniele 29:1a47b7151851 541
daniele 29:1a47b7151851 542 int pico_socket_add(struct pico_socket *s)
daniele 29:1a47b7151851 543 {
daniele 29:1a47b7151851 544 struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
daniele 29:1a47b7151851 545 LOCK(Mutex);
daniele 29:1a47b7151851 546 if (!sp) {
daniele 29:1a47b7151851 547 //dbg("Creating sockport..%04x\n", s->local_port); /* In comment due to spam during test */
daniele 29:1a47b7151851 548 sp = pico_zalloc(sizeof(struct pico_sockport));
daniele 29:1a47b7151851 549
daniele 29:1a47b7151851 550 if (!sp) {
daniele 29:1a47b7151851 551 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 552 UNLOCK(Mutex);
daniele 29:1a47b7151851 553 return -1;
daniele 29:1a47b7151851 554 }
daniele 29:1a47b7151851 555 sp->proto = PROTO(s);
daniele 29:1a47b7151851 556 sp->number = s->local_port;
daniele 29:1a47b7151851 557 sp->socks.root = &LEAF;
daniele 29:1a47b7151851 558 sp->socks.compare = socket_cmp;
daniele 29:1a47b7151851 559
daniele 29:1a47b7151851 560 if (PROTO(s) == PICO_PROTO_UDP)
daniele 29:1a47b7151851 561 {
daniele 29:1a47b7151851 562 pico_tree_insert(&UDPTable,sp);
daniele 29:1a47b7151851 563 }
daniele 29:1a47b7151851 564 else if (PROTO(s) == PICO_PROTO_TCP)
daniele 29:1a47b7151851 565 {
daniele 29:1a47b7151851 566 pico_tree_insert(&TCPTable,sp);
daniele 29:1a47b7151851 567 }
daniele 29:1a47b7151851 568 }
daniele 29:1a47b7151851 569
daniele 29:1a47b7151851 570 pico_tree_insert(&sp->socks,s);
daniele 29:1a47b7151851 571 s->state |= PICO_SOCKET_STATE_BOUND;
tass 51:ab4529a384a6 572 UNLOCK(Mutex);
daniele 29:1a47b7151851 573 #if DEBUG_SOCKET_TREE
daniele 29:1a47b7151851 574 {
daniele 29:1a47b7151851 575 struct pico_tree_node * index;
daniele 29:1a47b7151851 576 //RB_FOREACH(s, socket_tree, &sp->socks) {
daniele 29:1a47b7151851 577 pico_tree_foreach(index,&sp->socks){
daniele 29:1a47b7151851 578 s = index->keyValue;
daniele 29:1a47b7151851 579 dbg(">>>> List Socket lc=%hu rm=%hu\n", short_be(s->local_port), short_be(s->remote_port));
daniele 29:1a47b7151851 580 }
daniele 29:1a47b7151851 581
daniele 29:1a47b7151851 582 }
daniele 29:1a47b7151851 583 #endif
daniele 29:1a47b7151851 584 return 0;
daniele 29:1a47b7151851 585 }
daniele 29:1a47b7151851 586
tass 64:0225b609335e 587 static void socket_clean_queues(struct pico_socket *sock)
tass 64:0225b609335e 588 {
tass 64:0225b609335e 589 struct pico_frame * f_in = pico_dequeue(&sock->q_in);
tass 64:0225b609335e 590 struct pico_frame * f_out = pico_dequeue(&sock->q_out);
tass 64:0225b609335e 591 while(f_in || f_out)
tass 64:0225b609335e 592 {
tass 64:0225b609335e 593 if(f_in)
tass 64:0225b609335e 594 {
tass 64:0225b609335e 595 pico_frame_discard(f_in);
tass 64:0225b609335e 596 f_in = pico_dequeue(&sock->q_in);
tass 64:0225b609335e 597 }
tass 64:0225b609335e 598
tass 64:0225b609335e 599 if(f_out)
tass 64:0225b609335e 600 {
tass 64:0225b609335e 601 pico_frame_discard(f_out);
tass 64:0225b609335e 602 f_out = pico_dequeue(&sock->q_out);
tass 64:0225b609335e 603 }
tass 64:0225b609335e 604
tass 64:0225b609335e 605 }
tass 64:0225b609335e 606 }
tass 64:0225b609335e 607
daniele 29:1a47b7151851 608 static void socket_garbage_collect(unsigned long now, void *arg)
daniele 29:1a47b7151851 609 {
daniele 29:1a47b7151851 610 struct pico_socket *s = (struct pico_socket *) arg;
tass 51:ab4529a384a6 611 IGNORE_PARAMETER(now);
tass 64:0225b609335e 612 socket_clean_queues(s);
daniele 29:1a47b7151851 613 pico_free(s);
daniele 29:1a47b7151851 614 }
daniele 29:1a47b7151851 615
daniele 29:1a47b7151851 616 int pico_socket_del(struct pico_socket *s)
daniele 29:1a47b7151851 617 {
daniele 29:1a47b7151851 618 struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
daniele 29:1a47b7151851 619
daniele 29:1a47b7151851 620 if (!sp) {
daniele 29:1a47b7151851 621 pico_err = PICO_ERR_ENXIO;
daniele 29:1a47b7151851 622 return -1;
daniele 29:1a47b7151851 623 }
daniele 29:1a47b7151851 624
daniele 29:1a47b7151851 625 LOCK(Mutex);
daniele 29:1a47b7151851 626 pico_tree_delete(&sp->socks,s);
daniele 29:1a47b7151851 627 s->net = NULL;
daniele 29:1a47b7151851 628 if(pico_tree_empty(&sp->socks)){
daniele 29:1a47b7151851 629 if (PROTO(s) == PICO_PROTO_UDP)
daniele 29:1a47b7151851 630 {
daniele 29:1a47b7151851 631 pico_tree_delete(&UDPTable,sp);
daniele 29:1a47b7151851 632 }
daniele 29:1a47b7151851 633 else if (PROTO(s) == PICO_PROTO_TCP)
daniele 29:1a47b7151851 634 {
daniele 29:1a47b7151851 635 pico_tree_delete(&TCPTable,sp);
daniele 29:1a47b7151851 636 }
daniele 29:1a47b7151851 637
daniele 29:1a47b7151851 638 if(sp_tcp == sp) sp_tcp = NULL;
daniele 29:1a47b7151851 639
daniele 29:1a47b7151851 640 if(sp_udp == sp) sp_udp = NULL;
daniele 29:1a47b7151851 641
daniele 29:1a47b7151851 642 pico_free(sp);
daniele 29:1a47b7151851 643
daniele 29:1a47b7151851 644 }
daniele 29:1a47b7151851 645
daniele 29:1a47b7151851 646 #ifdef PICO_SUPPORT_MCAST
daniele 29:1a47b7151851 647 do {
tass 48:40fc4462265c 648 int filter_mode;
daniele 29:1a47b7151851 649 struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
daniele 29:1a47b7151851 650 struct pico_mcast_listen *listen = NULL;
daniele 29:1a47b7151851 651 struct pico_ip4 *source = NULL;
daniele 29:1a47b7151851 652 if (s->MCASTListen) {
daniele 29:1a47b7151851 653 pico_tree_delete(&MCASTSockets, s);
daniele 29:1a47b7151851 654 pico_tree_foreach_safe(index, s->MCASTListen, _tmp)
daniele 29:1a47b7151851 655 {
daniele 29:1a47b7151851 656 listen = index->keyValue;
daniele 29:1a47b7151851 657 pico_tree_foreach_safe(index2, &listen->MCASTSources, _tmp2)
daniele 29:1a47b7151851 658 {
daniele 29:1a47b7151851 659 source = index->keyValue;
daniele 29:1a47b7151851 660 pico_tree_delete(&listen->MCASTSources, source);
daniele 29:1a47b7151851 661 pico_free(source);
daniele 29:1a47b7151851 662 }
daniele 29:1a47b7151851 663 filter_mode = pico_socket_aggregate_mcastfilters(&listen->mcast_link, &listen->mcast_group);
tass 48:40fc4462265c 664 if (filter_mode >= 0)
tass 48:40fc4462265c 665 pico_ipv4_mcast_leave(&listen->mcast_link, &listen->mcast_group, 1, filter_mode, &MCASTFilter);
daniele 29:1a47b7151851 666 pico_tree_delete(s->MCASTListen, listen);
daniele 29:1a47b7151851 667 pico_free(listen);
daniele 29:1a47b7151851 668 }
daniele 29:1a47b7151851 669 pico_free(s->MCASTListen);
daniele 29:1a47b7151851 670 }
daniele 29:1a47b7151851 671 } while (0);
daniele 29:1a47b7151851 672 #endif
daniele 29:1a47b7151851 673
daniele 29:1a47b7151851 674 s->state = PICO_SOCKET_STATE_CLOSED;
daniele 29:1a47b7151851 675 pico_timer_add(3000, socket_garbage_collect, s);
tass 51:ab4529a384a6 676 UNLOCK(Mutex);
daniele 29:1a47b7151851 677 return 0;
daniele 29:1a47b7151851 678 }
daniele 29:1a47b7151851 679
daniele 29:1a47b7151851 680 static int pico_socket_alter_state(struct pico_socket *s, uint16_t more_states, uint16_t less_states, uint16_t tcp_state)
daniele 29:1a47b7151851 681 {
daniele 29:1a47b7151851 682 struct pico_sockport *sp;
daniele 29:1a47b7151851 683 if (more_states & PICO_SOCKET_STATE_BOUND)
daniele 29:1a47b7151851 684 return pico_socket_add(s);
daniele 29:1a47b7151851 685
daniele 29:1a47b7151851 686 if (less_states & PICO_SOCKET_STATE_BOUND)
daniele 29:1a47b7151851 687 return pico_socket_del(s);
daniele 29:1a47b7151851 688
daniele 29:1a47b7151851 689 sp = pico_get_sockport(PROTO(s), s->local_port);
daniele 29:1a47b7151851 690 if (!sp) {
daniele 29:1a47b7151851 691 pico_err = PICO_ERR_ENXIO;
daniele 29:1a47b7151851 692 return -1;
daniele 29:1a47b7151851 693 }
daniele 29:1a47b7151851 694
daniele 29:1a47b7151851 695 s->state |= more_states;
daniele 29:1a47b7151851 696 s->state &= (~less_states);
daniele 29:1a47b7151851 697 if (tcp_state) {
daniele 29:1a47b7151851 698 s->state &= 0x00FF;
daniele 29:1a47b7151851 699 s->state |= tcp_state;
daniele 29:1a47b7151851 700 }
daniele 29:1a47b7151851 701
daniele 29:1a47b7151851 702 return 0;
daniele 29:1a47b7151851 703 }
daniele 29:1a47b7151851 704
daniele 29:1a47b7151851 705 static int pico_socket_deliver(struct pico_protocol *p, struct pico_frame *f, uint16_t localport)
daniele 29:1a47b7151851 706 {
daniele 29:1a47b7151851 707 struct pico_frame *cpy = NULL;
daniele 29:1a47b7151851 708 struct pico_sockport *sp = NULL;
daniele 29:1a47b7151851 709 struct pico_socket *s = NULL, *found = NULL;
daniele 29:1a47b7151851 710 struct pico_tree_node *index = NULL;
daniele 29:1a47b7151851 711 struct pico_tree_node *_tmp;
daniele 29:1a47b7151851 712 struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
daniele 29:1a47b7151851 713 #ifdef PICO_SUPPORT_IPV4
daniele 29:1a47b7151851 714 struct pico_ipv4_hdr *ip4hdr;
daniele 29:1a47b7151851 715 #endif
daniele 29:1a47b7151851 716 #ifdef PICO_SUPPORT_IPV6
daniele 29:1a47b7151851 717 struct pico_ipv6_hdr *ip6hdr;
daniele 29:1a47b7151851 718 #endif
daniele 29:1a47b7151851 719
daniele 29:1a47b7151851 720 if (!tr)
daniele 29:1a47b7151851 721 return -1;
daniele 29:1a47b7151851 722
daniele 29:1a47b7151851 723 sp = pico_get_sockport(p->proto_number, localport);
daniele 29:1a47b7151851 724
daniele 29:1a47b7151851 725 if (!sp) {
daniele 29:1a47b7151851 726 dbg("No such port %d\n",short_be(localport));
daniele 29:1a47b7151851 727 return -1;
daniele 29:1a47b7151851 728 }
daniele 29:1a47b7151851 729
daniele 29:1a47b7151851 730 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 731 if (p->proto_number == PICO_PROTO_TCP) {
daniele 29:1a47b7151851 732 pico_tree_foreach_safe(index,&sp->socks, _tmp){
daniele 29:1a47b7151851 733 s = index->keyValue;
daniele 29:1a47b7151851 734 /* 4-tuple identification of socket (port-IP) */
daniele 29:1a47b7151851 735 #ifdef PICO_SUPPORT_IPV4
daniele 29:1a47b7151851 736 if (IS_IPV4(f)) {
daniele 29:1a47b7151851 737 struct pico_ip4 s_local, s_remote, p_src, p_dst;
daniele 29:1a47b7151851 738 ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
daniele 29:1a47b7151851 739 s_local.addr = s->local_addr.ip4.addr;
daniele 29:1a47b7151851 740 s_remote.addr = s->remote_addr.ip4.addr;
daniele 29:1a47b7151851 741 p_src.addr = ip4hdr->src.addr;
daniele 29:1a47b7151851 742 p_dst.addr = ip4hdr->dst.addr;
daniele 29:1a47b7151851 743 if ( (s->remote_port == tr->sport) && /* remote port check */
daniele 29:1a47b7151851 744 (s_remote.addr == p_src.addr) && /* remote addr check */
daniele 29:1a47b7151851 745 ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
daniele 29:1a47b7151851 746 found = s;
daniele 29:1a47b7151851 747 break;
daniele 29:1a47b7151851 748 } else if ( (s->remote_port == 0) && /* not connected... listening */
daniele 29:1a47b7151851 749 ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
daniele 29:1a47b7151851 750 /* listen socket */
daniele 29:1a47b7151851 751 found = s;
daniele 29:1a47b7151851 752 }
daniele 29:1a47b7151851 753 }
daniele 29:1a47b7151851 754 #endif
daniele 29:1a47b7151851 755 #ifdef PICO_SUPPORT_IPV6 /* XXX TODO make compare for ipv6 addresses */
daniele 29:1a47b7151851 756 if (IS_IPV6(f)) {
daniele 29:1a47b7151851 757 ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
daniele 29:1a47b7151851 758 if ( (s->remote_port == localport) ) { // && (((struct pico_ip6) s->remote_addr.ip6).addr == ((struct pico_ip6)(ip6hdr->src)).addr) ) {
daniele 29:1a47b7151851 759 found = s;
daniele 29:1a47b7151851 760 break;
daniele 29:1a47b7151851 761 } else if (s->remote_port == 0) {
daniele 29:1a47b7151851 762 /* listen socket */
daniele 29:1a47b7151851 763 found = s;
daniele 29:1a47b7151851 764 }
daniele 29:1a47b7151851 765 }
daniele 29:1a47b7151851 766 #endif
daniele 29:1a47b7151851 767 } /* FOREACH */
daniele 29:1a47b7151851 768 if (found != NULL) {
daniele 29:1a47b7151851 769 pico_tcp_input(found,f);
daniele 29:1a47b7151851 770 if ((found->ev_pending) && found->wakeup) {
daniele 29:1a47b7151851 771 found->wakeup(found->ev_pending, found);
daniele 29:1a47b7151851 772 }
daniele 29:1a47b7151851 773 return 0;
daniele 29:1a47b7151851 774 } else {
daniele 29:1a47b7151851 775 dbg("SOCKET> mmm something wrong (prob sockport)\n");
daniele 29:1a47b7151851 776 return -1;
daniele 29:1a47b7151851 777 }
daniele 29:1a47b7151851 778 } /* TCP CASE */
daniele 29:1a47b7151851 779 #endif
daniele 29:1a47b7151851 780
daniele 29:1a47b7151851 781 #ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 782 if (p->proto_number == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 783 pico_tree_foreach_safe(index,&sp->socks, _tmp){
daniele 29:1a47b7151851 784 s = index->keyValue;
daniele 29:1a47b7151851 785 if (IS_IPV4(f)) { /* IPV4 */
daniele 29:1a47b7151851 786 struct pico_ip4 s_local, p_dst;
daniele 29:1a47b7151851 787 ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
daniele 29:1a47b7151851 788 s_local.addr = s->local_addr.ip4.addr;
daniele 29:1a47b7151851 789 p_dst.addr = ip4hdr->dst.addr;
daniele 29:1a47b7151851 790 if ((pico_ipv4_is_broadcast(p_dst.addr)) || pico_ipv4_is_multicast(p_dst.addr)) {
daniele 29:1a47b7151851 791 struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4);
daniele 29:1a47b7151851 792 if (pico_ipv4_is_multicast(p_dst.addr) && (pico_socket_mcast_filter(s, &ip4hdr->dst, &ip4hdr->src) < 0))
daniele 29:1a47b7151851 793 return -1;
daniele 29:1a47b7151851 794 if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */
daniele 29:1a47b7151851 795 (dev == f->dev) ) { /* the source of the bcast packet is a neighbor... */
daniele 29:1a47b7151851 796 cpy = pico_frame_copy(f);
daniele 29:1a47b7151851 797 if (!cpy)
daniele 29:1a47b7151851 798 return -1;
daniele 29:1a47b7151851 799 if (pico_enqueue(&s->q_in, cpy) > 0) {
daniele 29:1a47b7151851 800 if (s->wakeup)
daniele 29:1a47b7151851 801 s->wakeup(PICO_SOCK_EV_RD, s);
daniele 29:1a47b7151851 802 }
daniele 29:1a47b7151851 803 }
daniele 29:1a47b7151851 804 } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))
daniele 29:1a47b7151851 805 { /* Either local socket is ANY, or matches dst */
daniele 29:1a47b7151851 806 cpy = pico_frame_copy(f);
daniele 29:1a47b7151851 807 if (!cpy)
daniele 29:1a47b7151851 808 return -1;
daniele 29:1a47b7151851 809 if (pico_enqueue(&s->q_in, cpy) > 0) {
daniele 29:1a47b7151851 810 if (s->wakeup)
daniele 29:1a47b7151851 811 s->wakeup(PICO_SOCK_EV_RD, s);
daniele 29:1a47b7151851 812 }
daniele 29:1a47b7151851 813 }
daniele 29:1a47b7151851 814 } else {
daniele 29:1a47b7151851 815 /*... IPv6 */
daniele 29:1a47b7151851 816 }
daniele 29:1a47b7151851 817 } /* FOREACH */
daniele 29:1a47b7151851 818 pico_frame_discard(f);
daniele 29:1a47b7151851 819 if (s)
daniele 29:1a47b7151851 820 return 0;
daniele 29:1a47b7151851 821 else
daniele 29:1a47b7151851 822 return -1;
daniele 29:1a47b7151851 823 }
daniele 29:1a47b7151851 824 #endif
daniele 29:1a47b7151851 825 return -1;
daniele 29:1a47b7151851 826 }
daniele 29:1a47b7151851 827
daniele 29:1a47b7151851 828 struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *))
daniele 29:1a47b7151851 829 {
daniele 29:1a47b7151851 830
daniele 29:1a47b7151851 831 struct pico_socket *s = NULL;
daniele 29:1a47b7151851 832
daniele 29:1a47b7151851 833 #ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 834 if (proto == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 835 s = pico_udp_open();
daniele 29:1a47b7151851 836 s->proto = &pico_proto_udp;
daniele 29:1a47b7151851 837 }
daniele 29:1a47b7151851 838 #endif
daniele 29:1a47b7151851 839
daniele 29:1a47b7151851 840 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 841 if (proto == PICO_PROTO_TCP) {
daniele 29:1a47b7151851 842 s = pico_tcp_open();
daniele 29:1a47b7151851 843 s->proto = &pico_proto_tcp;
daniele 29:1a47b7151851 844 /*check if Nagle enabled */
daniele 29:1a47b7151851 845 if (!IS_NAGLE_ENABLED(s))
daniele 29:1a47b7151851 846 dbg("ERROR Nagle should be enabled here\n\n");
daniele 29:1a47b7151851 847 }
daniele 29:1a47b7151851 848 #endif
daniele 29:1a47b7151851 849
daniele 29:1a47b7151851 850 if (!s) {
daniele 29:1a47b7151851 851 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 29:1a47b7151851 852 return NULL;
daniele 29:1a47b7151851 853 }
daniele 29:1a47b7151851 854
daniele 29:1a47b7151851 855 #ifdef PICO_SUPPORT_IPV4
daniele 29:1a47b7151851 856 if (net == PICO_PROTO_IPV4)
daniele 29:1a47b7151851 857 s->net = &pico_proto_ipv4;
daniele 29:1a47b7151851 858 #endif
daniele 29:1a47b7151851 859
daniele 29:1a47b7151851 860 #ifdef PICO_SUPPORT_IPV6
daniele 29:1a47b7151851 861 if (net == PICO_PROTO_IPV6)
daniele 29:1a47b7151851 862 s->net = &pico_proto_ipv6;
daniele 29:1a47b7151851 863 #endif
daniele 29:1a47b7151851 864
daniele 29:1a47b7151851 865 s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
daniele 29:1a47b7151851 866 s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
daniele 29:1a47b7151851 867 s->wakeup = wakeup;
daniele 29:1a47b7151851 868
daniele 29:1a47b7151851 869 if (!s->net) {
daniele 29:1a47b7151851 870 pico_free(s);
daniele 29:1a47b7151851 871 pico_err = PICO_ERR_ENETUNREACH;
daniele 29:1a47b7151851 872 return NULL;
daniele 29:1a47b7151851 873 }
daniele 29:1a47b7151851 874 return s;
daniele 29:1a47b7151851 875 }
daniele 29:1a47b7151851 876
daniele 29:1a47b7151851 877
daniele 29:1a47b7151851 878 struct pico_socket *pico_socket_clone(struct pico_socket *facsimile)
daniele 29:1a47b7151851 879 {
daniele 29:1a47b7151851 880 struct pico_socket *s = NULL;
daniele 29:1a47b7151851 881
daniele 29:1a47b7151851 882 #ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 883 if (facsimile->proto->proto_number == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 884 s = pico_udp_open();
daniele 29:1a47b7151851 885 s->proto = &pico_proto_udp;
daniele 29:1a47b7151851 886 }
daniele 29:1a47b7151851 887 #endif
daniele 29:1a47b7151851 888
daniele 29:1a47b7151851 889 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 890 if (facsimile->proto->proto_number == PICO_PROTO_TCP) {
daniele 29:1a47b7151851 891 s = pico_tcp_open();
daniele 29:1a47b7151851 892 s->proto = &pico_proto_tcp;
daniele 29:1a47b7151851 893 }
daniele 29:1a47b7151851 894 #endif
daniele 29:1a47b7151851 895
daniele 29:1a47b7151851 896 if (!s) {
daniele 29:1a47b7151851 897 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 29:1a47b7151851 898 return NULL;
daniele 29:1a47b7151851 899 }
daniele 29:1a47b7151851 900 s->local_port = facsimile->local_port;
daniele 29:1a47b7151851 901 s->remote_port = facsimile->remote_port;
daniele 29:1a47b7151851 902 s->state = facsimile->state;
daniele 29:1a47b7151851 903
daniele 29:1a47b7151851 904 #ifdef PICO_SUPPORT_IPV4
daniele 29:1a47b7151851 905 if (facsimile->net == &pico_proto_ipv4) {
daniele 29:1a47b7151851 906 s->net = &pico_proto_ipv4;
daniele 29:1a47b7151851 907 memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip4));
daniele 29:1a47b7151851 908 memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip4));
daniele 29:1a47b7151851 909 }
daniele 29:1a47b7151851 910 #endif
daniele 29:1a47b7151851 911
daniele 29:1a47b7151851 912 #ifdef PICO_SUPPORT_IPV6
daniele 29:1a47b7151851 913 if (net == &pico_proto_ipv6) {
daniele 29:1a47b7151851 914 s->net = &pico_proto_ipv6;
daniele 29:1a47b7151851 915 memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip6));
daniele 29:1a47b7151851 916 memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip6));
daniele 29:1a47b7151851 917 }
daniele 29:1a47b7151851 918 #endif
daniele 29:1a47b7151851 919 s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
daniele 29:1a47b7151851 920 s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
daniele 29:1a47b7151851 921 s->wakeup = NULL;
daniele 29:1a47b7151851 922 if (!s->net) {
daniele 29:1a47b7151851 923 pico_free(s);
daniele 29:1a47b7151851 924 pico_err = PICO_ERR_ENETUNREACH;
daniele 29:1a47b7151851 925 return NULL;
daniele 29:1a47b7151851 926 }
daniele 29:1a47b7151851 927 return s;
daniele 29:1a47b7151851 928 }
daniele 29:1a47b7151851 929
daniele 29:1a47b7151851 930 int pico_socket_read(struct pico_socket *s, void *buf, int len)
daniele 29:1a47b7151851 931 {
daniele 29:1a47b7151851 932 if (!s || buf == NULL) {
daniele 29:1a47b7151851 933 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 934 return -1;
daniele 29:1a47b7151851 935 } else {
daniele 29:1a47b7151851 936 /* check if exists in tree */
daniele 29:1a47b7151851 937 /* See task #178 */
daniele 29:1a47b7151851 938 if (pico_check_socket(s) != 0) {
daniele 29:1a47b7151851 939 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 940 return -1;
daniele 29:1a47b7151851 941 }
daniele 29:1a47b7151851 942 }
daniele 29:1a47b7151851 943
daniele 29:1a47b7151851 944 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 29:1a47b7151851 945 pico_err = PICO_ERR_EIO;
daniele 29:1a47b7151851 946 return -1;
daniele 29:1a47b7151851 947 }
daniele 29:1a47b7151851 948 #ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 949 if (PROTO(s) == PICO_PROTO_UDP)
daniele 29:1a47b7151851 950 return pico_udp_recv(s, buf, len, NULL, NULL);
daniele 29:1a47b7151851 951 #endif
daniele 29:1a47b7151851 952
daniele 29:1a47b7151851 953 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 954 if (PROTO(s) == PICO_PROTO_TCP){
daniele 29:1a47b7151851 955 /* check if in shutdown state and if no more data in tcpq_in */
daniele 29:1a47b7151851 956 if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s) ) {
daniele 29:1a47b7151851 957 pico_err = PICO_ERR_ESHUTDOWN;
daniele 29:1a47b7151851 958 return -1;
daniele 29:1a47b7151851 959 } else {
daniele 29:1a47b7151851 960 return pico_tcp_read(s, buf, len);
daniele 29:1a47b7151851 961 }
daniele 29:1a47b7151851 962 }
daniele 29:1a47b7151851 963 #endif
daniele 29:1a47b7151851 964 return 0;
daniele 29:1a47b7151851 965 }
daniele 29:1a47b7151851 966
daniele 29:1a47b7151851 967 int pico_socket_write(struct pico_socket *s, void *buf, int len)
daniele 29:1a47b7151851 968 {
daniele 29:1a47b7151851 969 if (!s || buf == NULL) {
daniele 29:1a47b7151851 970 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 971 return -1;
daniele 29:1a47b7151851 972 } else {
daniele 29:1a47b7151851 973 /* check if exists in tree */
daniele 29:1a47b7151851 974 /* See task #178 */
daniele 29:1a47b7151851 975 if (pico_check_socket(s) != 0) {
daniele 29:1a47b7151851 976 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 977 return -1;
daniele 29:1a47b7151851 978 }
daniele 29:1a47b7151851 979 }
daniele 29:1a47b7151851 980
daniele 29:1a47b7151851 981 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 29:1a47b7151851 982 pico_err = PICO_ERR_EIO;
daniele 29:1a47b7151851 983 return -1;
daniele 29:1a47b7151851 984 }
daniele 29:1a47b7151851 985 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
daniele 29:1a47b7151851 986 pico_err = PICO_ERR_ENOTCONN;
daniele 29:1a47b7151851 987 return -1;
daniele 29:1a47b7151851 988 } else if (s->state & PICO_SOCKET_STATE_SHUT_LOCAL) { /* check if in shutdown state */
daniele 29:1a47b7151851 989 pico_err = PICO_ERR_ESHUTDOWN;
daniele 29:1a47b7151851 990 return -1;
daniele 29:1a47b7151851 991 } else {
daniele 29:1a47b7151851 992 return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
daniele 29:1a47b7151851 993 }
daniele 29:1a47b7151851 994 }
daniele 29:1a47b7151851 995
daniele 29:1a47b7151851 996 uint16_t pico_socket_high_port(uint16_t proto)
daniele 29:1a47b7151851 997 {
daniele 29:1a47b7151851 998 uint16_t port;
daniele 29:1a47b7151851 999 if (0 ||
daniele 29:1a47b7151851 1000 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 1001 (proto == PICO_PROTO_TCP) ||
daniele 29:1a47b7151851 1002 #endif
daniele 29:1a47b7151851 1003 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 1004 (proto == PICO_PROTO_UDP) ||
daniele 29:1a47b7151851 1005 #endif
daniele 29:1a47b7151851 1006 0) {
daniele 29:1a47b7151851 1007 do {
daniele 29:1a47b7151851 1008 uint32_t rand = pico_rand();
daniele 29:1a47b7151851 1009 port = (uint16_t) (rand & 0xFFFFU);
daniele 29:1a47b7151851 1010 port = (uint16_t)(port % (65535 - 1024)) + 1024U;
daniele 29:1a47b7151851 1011 if (pico_is_port_free(proto, port, NULL, NULL)) {
daniele 29:1a47b7151851 1012 return short_be(port);
daniele 29:1a47b7151851 1013 }
daniele 29:1a47b7151851 1014 } while(1);
daniele 29:1a47b7151851 1015 }
daniele 29:1a47b7151851 1016 else return 0U;
daniele 29:1a47b7151851 1017 }
daniele 29:1a47b7151851 1018
daniele 29:1a47b7151851 1019
daniele 29:1a47b7151851 1020 int pico_socket_sendto(struct pico_socket *s, void *buf, int len, void *dst, uint16_t remote_port)
daniele 29:1a47b7151851 1021 {
daniele 29:1a47b7151851 1022 struct pico_frame *f;
daniele 29:1a47b7151851 1023 struct pico_remote_duple *remote_duple = NULL;
tass 48:40fc4462265c 1024 int socket_mtu = PICO_SOCKET4_MTU;
daniele 29:1a47b7151851 1025 int header_offset = 0;
daniele 29:1a47b7151851 1026 int total_payload_written = 0;
daniele 29:1a47b7151851 1027 #ifdef PICO_SUPPORT_IPV4
daniele 29:1a47b7151851 1028 struct pico_ip4 *src4;
daniele 29:1a47b7151851 1029 #endif
daniele 29:1a47b7151851 1030
daniele 29:1a47b7151851 1031 #ifdef PICO_SUPPORT_IPV6
daniele 29:1a47b7151851 1032 struct pico_ip6 *src6;
daniele 29:1a47b7151851 1033 #endif
daniele 29:1a47b7151851 1034 if (len == 0) {
daniele 29:1a47b7151851 1035 return 0;
daniele 29:1a47b7151851 1036 } else if (len < 0) {
daniele 29:1a47b7151851 1037 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1038 return -1;
daniele 29:1a47b7151851 1039 }
daniele 29:1a47b7151851 1040
daniele 29:1a47b7151851 1041 if (buf == NULL || s == NULL) {
daniele 29:1a47b7151851 1042 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1043 return -1;
daniele 29:1a47b7151851 1044 }
daniele 29:1a47b7151851 1045
daniele 29:1a47b7151851 1046 if (!dst || !remote_port) {
daniele 29:1a47b7151851 1047 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 29:1a47b7151851 1048 return -1;
daniele 29:1a47b7151851 1049 }
daniele 29:1a47b7151851 1050
daniele 29:1a47b7151851 1051 if ((s->state & PICO_SOCKET_STATE_CONNECTED) != 0) {
daniele 29:1a47b7151851 1052 if (remote_port != s->remote_port) {
daniele 29:1a47b7151851 1053 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1054 return -1;
daniele 29:1a47b7151851 1055 }
daniele 29:1a47b7151851 1056 }
daniele 29:1a47b7151851 1057
daniele 29:1a47b7151851 1058 #ifdef PICO_SUPPORT_IPV4
daniele 29:1a47b7151851 1059 if (IS_SOCK_IPV4(s)) {
tass 48:40fc4462265c 1060 socket_mtu = PICO_SOCKET4_MTU;
daniele 29:1a47b7151851 1061 if ((s->state & PICO_SOCKET_STATE_CONNECTED)) {
daniele 29:1a47b7151851 1062 if (s->remote_addr.ip4.addr != ((struct pico_ip4 *)dst)->addr ) {
daniele 29:1a47b7151851 1063 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 29:1a47b7151851 1064 return -1;
daniele 29:1a47b7151851 1065 }
daniele 29:1a47b7151851 1066 } else {
daniele 29:1a47b7151851 1067 src4 = pico_ipv4_source_find(dst);
daniele 29:1a47b7151851 1068 if (!src4) {
daniele 29:1a47b7151851 1069 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 29:1a47b7151851 1070 return -1;
daniele 29:1a47b7151851 1071 }
daniele 29:1a47b7151851 1072 if (src4->addr != PICO_IPV4_INADDR_ANY)
daniele 29:1a47b7151851 1073 s->local_addr.ip4.addr = src4->addr;
daniele 29:1a47b7151851 1074 # ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 1075 /* socket remote info could change in a consecutive call, make persistent */
daniele 29:1a47b7151851 1076 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 1077 remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
daniele 29:1a47b7151851 1078 remote_duple->remote_addr.ip4.addr = ((struct pico_ip4 *)dst)->addr;
daniele 29:1a47b7151851 1079 remote_duple->remote_port = remote_port;
daniele 29:1a47b7151851 1080 }
daniele 29:1a47b7151851 1081 # endif
daniele 29:1a47b7151851 1082 }
tass 48:40fc4462265c 1083 #endif
tass 48:40fc4462265c 1084 } else if (IS_SOCK_IPV6(s)) {
tass 48:40fc4462265c 1085 socket_mtu = PICO_SOCKET6_MTU;
tass 48:40fc4462265c 1086 #ifdef PICO_SUPPORT_IPV6
daniele 29:1a47b7151851 1087 if (s->state & PICO_SOCKET_STATE_CONNECTED) {
daniele 29:1a47b7151851 1088 if (memcmp(&s->remote_addr, dst, PICO_SIZE_IP6))
daniele 29:1a47b7151851 1089 return -1;
daniele 29:1a47b7151851 1090 } else {
daniele 29:1a47b7151851 1091 src6 = pico_ipv6_source_find(dst);
daniele 29:1a47b7151851 1092 if (!src6) {
daniele 29:1a47b7151851 1093 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 29:1a47b7151851 1094 return -1;
daniele 29:1a47b7151851 1095 }
daniele 29:1a47b7151851 1096 memcpy(&s->local_addr, src6, PICO_SIZE_IP6);
daniele 29:1a47b7151851 1097 memcpy(&s->remote_addr, dst, PICO_SIZE_IP6);
daniele 29:1a47b7151851 1098 # ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 1099 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 1100 remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
daniele 29:1a47b7151851 1101 remote_duple->remote_addr.ip6.addr = ((struct pico_ip6 *)dst)->addr;
daniele 29:1a47b7151851 1102 remote_duple->remote_port = remote_port;
daniele 29:1a47b7151851 1103 }
daniele 29:1a47b7151851 1104 # endif
daniele 29:1a47b7151851 1105 }
tass 48:40fc4462265c 1106 #endif
daniele 29:1a47b7151851 1107 }
daniele 29:1a47b7151851 1108
daniele 29:1a47b7151851 1109 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 29:1a47b7151851 1110 s->local_port = pico_socket_high_port(s->proto->proto_number);
daniele 29:1a47b7151851 1111 if (s->local_port == 0) {
daniele 29:1a47b7151851 1112 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1113 return -1;
daniele 29:1a47b7151851 1114 }
daniele 29:1a47b7151851 1115 }
daniele 29:1a47b7151851 1116 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
daniele 29:1a47b7151851 1117 s->remote_port = remote_port;
daniele 29:1a47b7151851 1118 }
daniele 29:1a47b7151851 1119
daniele 29:1a47b7151851 1120 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 1121 if (PROTO(s) == PICO_PROTO_TCP)
daniele 29:1a47b7151851 1122 header_offset = pico_tcp_overhead(s);
daniele 29:1a47b7151851 1123 #endif
daniele 29:1a47b7151851 1124
daniele 29:1a47b7151851 1125 #ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 1126 if (PROTO(s) == PICO_PROTO_UDP)
daniele 29:1a47b7151851 1127 header_offset = sizeof(struct pico_udp_hdr);
daniele 29:1a47b7151851 1128 #endif
daniele 29:1a47b7151851 1129
daniele 29:1a47b7151851 1130 while (total_payload_written < len) {
daniele 29:1a47b7151851 1131 int transport_len = (len - total_payload_written) + header_offset;
tass 48:40fc4462265c 1132 if (transport_len > socket_mtu)
tass 48:40fc4462265c 1133 transport_len = socket_mtu;
tass 48:40fc4462265c 1134 #ifdef PICO_SUPPORT_IPFRAG
daniele 29:1a47b7151851 1135 else {
daniele 29:1a47b7151851 1136 if (total_payload_written)
daniele 29:1a47b7151851 1137 transport_len -= header_offset; /* last fragment, do not allocate memory for transport header */
daniele 29:1a47b7151851 1138 }
daniele 29:1a47b7151851 1139 #endif /* PICO_SUPPORT_IPFRAG */
daniele 29:1a47b7151851 1140
daniele 29:1a47b7151851 1141 f = pico_socket_frame_alloc(s, transport_len);
daniele 29:1a47b7151851 1142 if (!f) {
daniele 29:1a47b7151851 1143 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 1144 return -1;
daniele 29:1a47b7151851 1145 }
daniele 29:1a47b7151851 1146 f->payload += header_offset;
daniele 29:1a47b7151851 1147 f->payload_len -= header_offset;
daniele 29:1a47b7151851 1148 f->sock = s;
daniele 29:1a47b7151851 1149 if (remote_duple) {
daniele 29:1a47b7151851 1150 f->info = pico_zalloc(sizeof(struct pico_remote_duple));
daniele 29:1a47b7151851 1151 memcpy(f->info, remote_duple, sizeof(struct pico_remote_duple));
daniele 29:1a47b7151851 1152 }
daniele 29:1a47b7151851 1153
tass 48:40fc4462265c 1154 #ifdef PICO_SUPPORT_IPFRAG
tass 48:40fc4462265c 1155 #ifdef PICO_SUPPORT_UDP
tass 48:40fc4462265c 1156 if (PROTO(s) == PICO_PROTO_UDP && ((len + header_offset) > socket_mtu)) {
daniele 29:1a47b7151851 1157 /* hacking way to identify fragmentation frames: payload != transport_hdr -> first frame */
daniele 29:1a47b7151851 1158 if (!total_payload_written) {
daniele 29:1a47b7151851 1159 frag_dbg("FRAG: first fragmented frame %p | len = %u offset = 0\n", f, f->payload_len);
daniele 29:1a47b7151851 1160 /* transport header length field contains total length + header length */
daniele 29:1a47b7151851 1161 f->transport_len = len + header_offset;
daniele 29:1a47b7151851 1162 f->frag = short_be(PICO_IPV4_MOREFRAG);
daniele 29:1a47b7151851 1163 } else {
daniele 29:1a47b7151851 1164 /* no transport header in fragmented IP */
daniele 29:1a47b7151851 1165 f->payload = f->transport_hdr;
daniele 29:1a47b7151851 1166 f->payload_len += header_offset;
daniele 29:1a47b7151851 1167 /* set offset in octets */
daniele 29:1a47b7151851 1168 f->frag = short_be((total_payload_written + header_offset) / 8);
daniele 29:1a47b7151851 1169 if (total_payload_written + f->payload_len < len) {
daniele 29:1a47b7151851 1170 frag_dbg("FRAG: intermediate fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
daniele 29:1a47b7151851 1171 f->frag |= short_be(PICO_IPV4_MOREFRAG);
daniele 29:1a47b7151851 1172 } else {
daniele 29:1a47b7151851 1173 frag_dbg("FRAG: last fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
daniele 29:1a47b7151851 1174 f->frag &= short_be(PICO_IPV4_FRAG_MASK);
daniele 29:1a47b7151851 1175 }
daniele 29:1a47b7151851 1176 }
daniele 29:1a47b7151851 1177 } else {
daniele 29:1a47b7151851 1178 f->frag = short_be(PICO_IPV4_DONTFRAG);
daniele 29:1a47b7151851 1179 }
daniele 29:1a47b7151851 1180 # endif /* PICO_SUPPORT_UDP */
daniele 29:1a47b7151851 1181 #endif /* PICO_SUPPORT_IPFRAG */
daniele 29:1a47b7151851 1182
daniele 29:1a47b7151851 1183 if (f->payload_len <= 0) {
daniele 29:1a47b7151851 1184 pico_frame_discard(f);
daniele 29:1a47b7151851 1185 if (remote_duple)
daniele 29:1a47b7151851 1186 pico_free(remote_duple);
daniele 29:1a47b7151851 1187 return total_payload_written;
daniele 29:1a47b7151851 1188 }
daniele 29:1a47b7151851 1189
daniele 29:1a47b7151851 1190 memcpy(f->payload, buf + total_payload_written, f->payload_len);
daniele 29:1a47b7151851 1191 //dbg("Pushing segment, hdr len: %d, payload_len: %d\n", header_offset, f->payload_len);
daniele 29:1a47b7151851 1192
daniele 29:1a47b7151851 1193 if (s->proto->push(s->proto, f) > 0) {
daniele 29:1a47b7151851 1194 total_payload_written += f->payload_len;
daniele 29:1a47b7151851 1195 } else {
daniele 29:1a47b7151851 1196 pico_frame_discard(f);
daniele 29:1a47b7151851 1197 pico_err = PICO_ERR_EAGAIN;
daniele 29:1a47b7151851 1198 break;
daniele 29:1a47b7151851 1199 }
daniele 29:1a47b7151851 1200 }
daniele 29:1a47b7151851 1201 if (remote_duple)
daniele 29:1a47b7151851 1202 pico_free(remote_duple);
daniele 29:1a47b7151851 1203 return total_payload_written;
daniele 29:1a47b7151851 1204 }
daniele 29:1a47b7151851 1205
daniele 29:1a47b7151851 1206 int pico_socket_send(struct pico_socket *s, void *buf, int len)
daniele 29:1a47b7151851 1207 {
daniele 29:1a47b7151851 1208 if (!s || buf == NULL) {
daniele 29:1a47b7151851 1209 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1210 return -1;
daniele 29:1a47b7151851 1211 } else {
daniele 29:1a47b7151851 1212 /* check if exists in tree */
daniele 29:1a47b7151851 1213 /* See task #178 */
daniele 29:1a47b7151851 1214 if (pico_check_socket(s) != 0) {
daniele 29:1a47b7151851 1215 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1216 return -1;
daniele 29:1a47b7151851 1217 }
daniele 29:1a47b7151851 1218 }
daniele 29:1a47b7151851 1219
daniele 29:1a47b7151851 1220 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
daniele 29:1a47b7151851 1221 pico_err = PICO_ERR_ENOTCONN;
daniele 29:1a47b7151851 1222 return -1;
daniele 29:1a47b7151851 1223 }
daniele 29:1a47b7151851 1224 return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
daniele 29:1a47b7151851 1225 }
daniele 29:1a47b7151851 1226
daniele 29:1a47b7151851 1227 int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port)
daniele 29:1a47b7151851 1228 {
daniele 29:1a47b7151851 1229 if (!s || buf == NULL) { /// || orig == NULL || remote_port == NULL) {
daniele 29:1a47b7151851 1230 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1231 return -1;
daniele 29:1a47b7151851 1232 } else {
daniele 29:1a47b7151851 1233 /* check if exists in tree */
daniele 29:1a47b7151851 1234 if (pico_check_socket(s) != 0) {
daniele 29:1a47b7151851 1235 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1236 /* See task #178 */
daniele 29:1a47b7151851 1237 return -1;
daniele 29:1a47b7151851 1238 }
daniele 29:1a47b7151851 1239 }
daniele 29:1a47b7151851 1240
daniele 29:1a47b7151851 1241 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 29:1a47b7151851 1242 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 29:1a47b7151851 1243 return -1;
daniele 29:1a47b7151851 1244 }
daniele 29:1a47b7151851 1245 #ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 1246 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 1247 return pico_udp_recv(s, buf, len, orig, remote_port);
daniele 29:1a47b7151851 1248 }
daniele 29:1a47b7151851 1249 #endif
daniele 29:1a47b7151851 1250 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 1251 if (PROTO(s) == PICO_PROTO_TCP) {
daniele 29:1a47b7151851 1252 /* check if in shutdown state and if tcpq_in empty */
daniele 29:1a47b7151851 1253 if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) {
daniele 29:1a47b7151851 1254 pico_err = PICO_ERR_ESHUTDOWN;
daniele 29:1a47b7151851 1255 return -1;
daniele 29:1a47b7151851 1256 } else {
daniele 29:1a47b7151851 1257 //dbg("socket tcp recv\n");
daniele 29:1a47b7151851 1258 return pico_tcp_read(s, buf, len);
daniele 29:1a47b7151851 1259 }
daniele 29:1a47b7151851 1260 }
daniele 29:1a47b7151851 1261 #endif
daniele 29:1a47b7151851 1262 //dbg("socket return 0\n");
daniele 29:1a47b7151851 1263 return 0;
daniele 29:1a47b7151851 1264 }
daniele 29:1a47b7151851 1265
daniele 29:1a47b7151851 1266 int pico_socket_recv(struct pico_socket *s, void *buf, int len)
daniele 29:1a47b7151851 1267 {
daniele 29:1a47b7151851 1268 return pico_socket_recvfrom(s, buf, len, NULL, NULL);
daniele 29:1a47b7151851 1269 }
daniele 29:1a47b7151851 1270
daniele 29:1a47b7151851 1271
daniele 29:1a47b7151851 1272 int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port)
daniele 29:1a47b7151851 1273 {
daniele 29:1a47b7151851 1274 if (!s || !local_addr || !port) {
daniele 29:1a47b7151851 1275 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1276 return -1;
daniele 29:1a47b7151851 1277 }
daniele 29:1a47b7151851 1278
daniele 29:1a47b7151851 1279 if (!is_sock_ipv6(s)) {
daniele 29:1a47b7151851 1280 struct pico_ip4 *ip = (struct pico_ip4 *)local_addr;
daniele 29:1a47b7151851 1281 if (ip->addr != PICO_IPV4_INADDR_ANY) {
daniele 29:1a47b7151851 1282 if (!pico_ipv4_link_find(local_addr)) {
daniele 29:1a47b7151851 1283 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1284 return -1;
daniele 29:1a47b7151851 1285 }
daniele 29:1a47b7151851 1286 }
daniele 29:1a47b7151851 1287 } else {
daniele 29:1a47b7151851 1288 /*... IPv6 */
daniele 29:1a47b7151851 1289 }
daniele 29:1a47b7151851 1290
daniele 29:1a47b7151851 1291
daniele 29:1a47b7151851 1292 /* When given port = 0, get a random high port to bind to. */
daniele 29:1a47b7151851 1293 if (*port == 0) {
daniele 29:1a47b7151851 1294 *port = pico_socket_high_port(PROTO(s));
daniele 29:1a47b7151851 1295 if (*port == 0) {
daniele 29:1a47b7151851 1296 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1297 return -1;
daniele 29:1a47b7151851 1298 }
daniele 29:1a47b7151851 1299 }
daniele 29:1a47b7151851 1300
daniele 29:1a47b7151851 1301 if (pico_is_port_free(PROTO(s), *port, local_addr, s->net) == 0) {
daniele 29:1a47b7151851 1302 pico_err = PICO_ERR_EADDRINUSE;
daniele 29:1a47b7151851 1303 return -1;
daniele 29:1a47b7151851 1304 }
daniele 29:1a47b7151851 1305 s->local_port = *port;
daniele 29:1a47b7151851 1306
daniele 29:1a47b7151851 1307 if (is_sock_ipv6(s)) {
daniele 29:1a47b7151851 1308 struct pico_ip6 *ip = (struct pico_ip6 *) local_addr;
daniele 29:1a47b7151851 1309 memcpy(s->local_addr.ip6.addr, ip, PICO_SIZE_IP6);
daniele 29:1a47b7151851 1310 /* XXX: port ipv4 functionality to ipv6 */
daniele 29:1a47b7151851 1311 /* Check for port already in use */
daniele 29:1a47b7151851 1312 if (pico_is_port_free(PROTO(s), *port, &local_addr, s->net)) {
daniele 29:1a47b7151851 1313 pico_err = PICO_ERR_EADDRINUSE;
daniele 29:1a47b7151851 1314 return -1;
daniele 29:1a47b7151851 1315 }
daniele 29:1a47b7151851 1316 } else if (is_sock_ipv4(s)) {
daniele 29:1a47b7151851 1317 struct pico_ip4 *ip = (struct pico_ip4 *) local_addr;
daniele 29:1a47b7151851 1318 s->local_addr.ip4.addr = ip->addr;
daniele 29:1a47b7151851 1319 }
daniele 29:1a47b7151851 1320 return pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
daniele 29:1a47b7151851 1321 }
daniele 29:1a47b7151851 1322
daniele 29:1a47b7151851 1323 int pico_socket_connect(struct pico_socket *s, void *remote_addr, uint16_t remote_port)
daniele 29:1a47b7151851 1324 {
daniele 29:1a47b7151851 1325 int ret = -1;
daniele 29:1a47b7151851 1326 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 29:1a47b7151851 1327 if (!s || remote_addr == NULL || remote_port == 0) {
daniele 29:1a47b7151851 1328 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1329 return -1;
daniele 29:1a47b7151851 1330 }
daniele 29:1a47b7151851 1331
daniele 29:1a47b7151851 1332 s->remote_port = remote_port;
daniele 29:1a47b7151851 1333
daniele 29:1a47b7151851 1334 if (s->local_port == 0) {
daniele 29:1a47b7151851 1335 s->local_port = pico_socket_high_port(PROTO(s));
daniele 29:1a47b7151851 1336 if (!s->local_port) {
daniele 29:1a47b7151851 1337 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1338 return -1;
daniele 29:1a47b7151851 1339 }
daniele 29:1a47b7151851 1340 }
daniele 29:1a47b7151851 1341
daniele 29:1a47b7151851 1342 if (is_sock_ipv6(s)) {
daniele 29:1a47b7151851 1343 struct pico_ip6 *ip = (struct pico_ip6 *) remote_addr;
daniele 29:1a47b7151851 1344 memcpy(s->remote_addr.ip6.addr, ip, PICO_SIZE_IP6);
daniele 29:1a47b7151851 1345 } else if (is_sock_ipv4(s)) {
daniele 29:1a47b7151851 1346 struct pico_ip4 *local, *ip = (struct pico_ip4 *) remote_addr;
daniele 29:1a47b7151851 1347 s->remote_addr.ip4.addr = ip->addr;
daniele 29:1a47b7151851 1348 local = pico_ipv4_source_find(ip);
daniele 29:1a47b7151851 1349 if (local) {
daniele 29:1a47b7151851 1350 s->local_addr.ip4.addr = local->addr;
daniele 29:1a47b7151851 1351 } else {
daniele 29:1a47b7151851 1352 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 29:1a47b7151851 1353 return -1;
daniele 29:1a47b7151851 1354 }
daniele 29:1a47b7151851 1355 }
daniele 29:1a47b7151851 1356
daniele 29:1a47b7151851 1357 pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
daniele 29:1a47b7151851 1358
daniele 29:1a47b7151851 1359 #ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 1360 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 1361 pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED, 0, 0);
daniele 29:1a47b7151851 1362 pico_err = PICO_ERR_NOERR;
daniele 29:1a47b7151851 1363 ret = 0;
daniele 29:1a47b7151851 1364 }
daniele 29:1a47b7151851 1365 #endif
daniele 29:1a47b7151851 1366
daniele 29:1a47b7151851 1367 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 1368 if (PROTO(s) == PICO_PROTO_TCP) {
daniele 29:1a47b7151851 1369 if (pico_tcp_initconn(s) == 0) {
daniele 29:1a47b7151851 1370 pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, 0, 0);
daniele 29:1a47b7151851 1371 pico_err = PICO_ERR_NOERR;
daniele 29:1a47b7151851 1372 ret = 0;
daniele 29:1a47b7151851 1373 } else {
daniele 29:1a47b7151851 1374 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 29:1a47b7151851 1375 }
daniele 29:1a47b7151851 1376 }
daniele 29:1a47b7151851 1377 #endif
daniele 29:1a47b7151851 1378
daniele 29:1a47b7151851 1379 return ret;
daniele 29:1a47b7151851 1380 }
daniele 29:1a47b7151851 1381
daniele 29:1a47b7151851 1382 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 1383
daniele 29:1a47b7151851 1384 int pico_socket_listen(struct pico_socket *s, int backlog)
daniele 29:1a47b7151851 1385 {
daniele 29:1a47b7151851 1386 if (!s || backlog < 1) {
daniele 29:1a47b7151851 1387 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1388 return -1;
daniele 29:1a47b7151851 1389 } else {
daniele 29:1a47b7151851 1390 /* check if exists in tree */
daniele 29:1a47b7151851 1391 /* See task #178 */
daniele 29:1a47b7151851 1392 if (pico_check_socket(s) != 0) {
daniele 29:1a47b7151851 1393 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1394 return -1;
daniele 29:1a47b7151851 1395 }
daniele 29:1a47b7151851 1396 }
daniele 29:1a47b7151851 1397
daniele 29:1a47b7151851 1398 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 1399 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1400 return -1;
daniele 29:1a47b7151851 1401 }
daniele 29:1a47b7151851 1402
daniele 29:1a47b7151851 1403 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 29:1a47b7151851 1404 pico_err = PICO_ERR_EISCONN;
daniele 29:1a47b7151851 1405 return -1;
daniele 29:1a47b7151851 1406 }
daniele 29:1a47b7151851 1407
daniele 29:1a47b7151851 1408 if (backlog < 1) {
daniele 29:1a47b7151851 1409 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1410 return -1;
daniele 29:1a47b7151851 1411 }
daniele 29:1a47b7151851 1412
daniele 29:1a47b7151851 1413 if (PROTO(s) == PICO_PROTO_TCP)
daniele 29:1a47b7151851 1414 pico_socket_alter_state(s, PICO_SOCKET_STATE_TCP_SYN_SENT, 0, PICO_SOCKET_STATE_TCP_LISTEN);
daniele 29:1a47b7151851 1415 s->max_backlog = backlog;
daniele 29:1a47b7151851 1416
daniele 29:1a47b7151851 1417 return 0;
daniele 29:1a47b7151851 1418 }
daniele 29:1a47b7151851 1419
daniele 29:1a47b7151851 1420 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port)
daniele 29:1a47b7151851 1421 {
daniele 29:1a47b7151851 1422 if (!s || !orig || !port) {
daniele 29:1a47b7151851 1423 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1424 return NULL;
daniele 29:1a47b7151851 1425 }
daniele 29:1a47b7151851 1426
daniele 29:1a47b7151851 1427 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1428
daniele 29:1a47b7151851 1429 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 29:1a47b7151851 1430 return NULL;
daniele 29:1a47b7151851 1431 }
daniele 29:1a47b7151851 1432
daniele 29:1a47b7151851 1433 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 1434 return NULL;
daniele 29:1a47b7151851 1435 }
daniele 29:1a47b7151851 1436
daniele 29:1a47b7151851 1437 if (TCPSTATE(s) == PICO_SOCKET_STATE_TCP_LISTEN) {
daniele 29:1a47b7151851 1438 struct pico_sockport *sp = pico_get_sockport(PICO_PROTO_TCP, s->local_port);
daniele 29:1a47b7151851 1439 struct pico_socket *found;
daniele 29:1a47b7151851 1440 /* If at this point no incoming connection socket is found,
daniele 29:1a47b7151851 1441 * the accept call is valid, but no connection is established yet.
daniele 29:1a47b7151851 1442 */
daniele 29:1a47b7151851 1443 pico_err = PICO_ERR_EAGAIN;
daniele 29:1a47b7151851 1444 if (sp) {
daniele 29:1a47b7151851 1445 struct pico_tree_node * index;
daniele 29:1a47b7151851 1446 //RB_FOREACH(found, socket_tree, &sp->socks) {
daniele 29:1a47b7151851 1447 pico_tree_foreach(index,&sp->socks){
daniele 29:1a47b7151851 1448 found = index->keyValue;
daniele 29:1a47b7151851 1449 if (s == found->parent) {
daniele 29:1a47b7151851 1450 found->parent = NULL;
daniele 29:1a47b7151851 1451 pico_err = PICO_ERR_NOERR;
daniele 29:1a47b7151851 1452 memcpy(orig, &found->remote_addr, sizeof(struct pico_ip4));
daniele 29:1a47b7151851 1453 *port = found->remote_port;
daniele 29:1a47b7151851 1454 return found;
daniele 29:1a47b7151851 1455 }
daniele 29:1a47b7151851 1456 }
daniele 29:1a47b7151851 1457 }
daniele 29:1a47b7151851 1458 }
daniele 29:1a47b7151851 1459 return NULL;
daniele 29:1a47b7151851 1460 }
daniele 29:1a47b7151851 1461
daniele 29:1a47b7151851 1462 #else
daniele 29:1a47b7151851 1463
daniele 29:1a47b7151851 1464 int pico_socket_listen(struct pico_socket *s, int backlog)
daniele 29:1a47b7151851 1465 {
daniele 29:1a47b7151851 1466 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1467 return -1;
daniele 29:1a47b7151851 1468 }
daniele 29:1a47b7151851 1469
daniele 29:1a47b7151851 1470 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *local_port)
daniele 29:1a47b7151851 1471 {
daniele 29:1a47b7151851 1472 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1473 return NULL;
daniele 29:1a47b7151851 1474 }
daniele 29:1a47b7151851 1475
daniele 29:1a47b7151851 1476 #endif
daniele 29:1a47b7151851 1477
daniele 29:1a47b7151851 1478 #define PICO_SOCKET_SETOPT_EN(socket,index) (socket->opt_flags |= (1 << index))
daniele 29:1a47b7151851 1479 #define PICO_SOCKET_SETOPT_DIS(socket,index) (socket->opt_flags &= ~(1 << index))
daniele 29:1a47b7151851 1480
daniele 29:1a47b7151851 1481 int pico_socket_setoption(struct pico_socket *s, int option, void *value) // XXX no check against proto (vs setsockopt) or implicit by socket?
daniele 29:1a47b7151851 1482 {
daniele 29:1a47b7151851 1483 if (s == NULL) {
daniele 29:1a47b7151851 1484 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1485 return -1;
daniele 29:1a47b7151851 1486 }
daniele 29:1a47b7151851 1487
daniele 29:1a47b7151851 1488 pico_err = PICO_ERR_NOERR;
daniele 29:1a47b7151851 1489
daniele 29:1a47b7151851 1490 switch (option)
daniele 29:1a47b7151851 1491 {
daniele 29:1a47b7151851 1492 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 1493 case PICO_TCP_NODELAY:
daniele 29:1a47b7151851 1494 if (!value) {
daniele 29:1a47b7151851 1495 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1496 return -1;
daniele 29:1a47b7151851 1497 }
daniele 29:1a47b7151851 1498 if (s->proto->proto_number == PICO_PROTO_TCP) {
daniele 29:1a47b7151851 1499 int *val = (int*)value;
daniele 29:1a47b7151851 1500 if (*val > 0) {
daniele 29:1a47b7151851 1501 dbg("setsockopt: Nagle algorithm disabled.\n");
daniele 29:1a47b7151851 1502 PICO_SOCKET_SETOPT_EN(s,PICO_SOCKET_OPT_TCPNODELAY);
daniele 29:1a47b7151851 1503 } else {
daniele 29:1a47b7151851 1504 dbg("setsockopt: Nagle algorithm enabled.\n");
daniele 29:1a47b7151851 1505 PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_TCPNODELAY);
daniele 29:1a47b7151851 1506 }
daniele 29:1a47b7151851 1507 } else {
daniele 29:1a47b7151851 1508 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1509 }
daniele 29:1a47b7151851 1510 break;
daniele 29:1a47b7151851 1511 #endif
daniele 29:1a47b7151851 1512
daniele 29:1a47b7151851 1513
daniele 29:1a47b7151851 1514 #ifdef PICO_SUPPORT_MCAST
daniele 29:1a47b7151851 1515 case PICO_IP_MULTICAST_IF:
daniele 29:1a47b7151851 1516 pico_err = PICO_ERR_EOPNOTSUPP;
daniele 29:1a47b7151851 1517 return -1;
daniele 29:1a47b7151851 1518 break;
daniele 29:1a47b7151851 1519
daniele 29:1a47b7151851 1520 case PICO_IP_MULTICAST_TTL:
daniele 29:1a47b7151851 1521 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 1522 return pico_udp_set_mc_ttl(s, *((uint8_t *) value));
daniele 29:1a47b7151851 1523 }
daniele 29:1a47b7151851 1524 break;
daniele 29:1a47b7151851 1525
daniele 29:1a47b7151851 1526 case PICO_IP_MULTICAST_LOOP:
daniele 29:1a47b7151851 1527 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 1528 switch (*(uint8_t *) value)
daniele 29:1a47b7151851 1529 {
daniele 29:1a47b7151851 1530 case 0:
daniele 29:1a47b7151851 1531 /* do not loop back multicast datagram */
daniele 29:1a47b7151851 1532 PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
daniele 29:1a47b7151851 1533 break;
daniele 29:1a47b7151851 1534
daniele 29:1a47b7151851 1535 case 1:
daniele 29:1a47b7151851 1536 /* do loop back multicast datagram */
daniele 29:1a47b7151851 1537 PICO_SOCKET_SETOPT_EN(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
daniele 29:1a47b7151851 1538 break;
daniele 29:1a47b7151851 1539
daniele 29:1a47b7151851 1540 default:
daniele 29:1a47b7151851 1541 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1542 return -1;
daniele 29:1a47b7151851 1543 }
daniele 29:1a47b7151851 1544 }
daniele 29:1a47b7151851 1545 break;
daniele 29:1a47b7151851 1546
daniele 29:1a47b7151851 1547 case PICO_IP_ADD_MEMBERSHIP:
daniele 29:1a47b7151851 1548 /* EXCLUDE mode */
daniele 29:1a47b7151851 1549 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 48:40fc4462265c 1550 int filter_mode;
daniele 29:1a47b7151851 1551 struct pico_ip_mreq *mreq = NULL;
daniele 29:1a47b7151851 1552 struct pico_mcast_listen *listen = NULL, ltest = {0};
daniele 29:1a47b7151851 1553 struct pico_ipv4_link *mcast_link = NULL;
daniele 29:1a47b7151851 1554
daniele 29:1a47b7151851 1555 if (!value) {
daniele 29:1a47b7151851 1556 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1557 return -1;
daniele 29:1a47b7151851 1558 }
daniele 29:1a47b7151851 1559 mreq = (struct pico_ip_mreq *) value;
daniele 29:1a47b7151851 1560 mcast_link = pico_socket_setoption_mcastargs_validation(mreq, NULL);
daniele 29:1a47b7151851 1561 if (!mcast_link) {
daniele 29:1a47b7151851 1562 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1563 return -1;
daniele 29:1a47b7151851 1564 }
daniele 29:1a47b7151851 1565 if (!mreq->mcast_link_addr.addr)
daniele 29:1a47b7151851 1566 mreq->mcast_link_addr.addr = mcast_link->address.addr;
daniele 29:1a47b7151851 1567
daniele 29:1a47b7151851 1568 if (!s->MCASTListen) { /* No RBTree allocated yet */
daniele 29:1a47b7151851 1569 s->MCASTListen = pico_zalloc(sizeof(struct pico_tree));
daniele 29:1a47b7151851 1570 if (!s->MCASTListen) {
daniele 29:1a47b7151851 1571 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 1572 return -1;
daniele 29:1a47b7151851 1573 }
daniele 29:1a47b7151851 1574 s->MCASTListen->root = &LEAF;
daniele 29:1a47b7151851 1575 s->MCASTListen->compare = mcast_listen_cmp;
daniele 29:1a47b7151851 1576 }
daniele 29:1a47b7151851 1577 ltest.mcast_link = mreq->mcast_link_addr;
daniele 29:1a47b7151851 1578 ltest.mcast_group = mreq->mcast_group_addr;
daniele 29:1a47b7151851 1579 listen = pico_tree_findKey(s->MCASTListen, &ltest);
daniele 29:1a47b7151851 1580 if (listen) {
daniele 29:1a47b7151851 1581 if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
daniele 29:1a47b7151851 1582 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
daniele 29:1a47b7151851 1583 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1584 return -1;
daniele 29:1a47b7151851 1585 } else {
daniele 29:1a47b7151851 1586 so_mcast_dbg("pico_socket_setoption: ERROR duplicate PICO_IP_ADD_MEMBERSHIP\n");
daniele 29:1a47b7151851 1587 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1588 return -1;
daniele 29:1a47b7151851 1589 }
daniele 29:1a47b7151851 1590 } else {
daniele 29:1a47b7151851 1591 listen = pico_zalloc(sizeof(struct pico_mcast_listen));
daniele 29:1a47b7151851 1592 if (!listen) {
daniele 29:1a47b7151851 1593 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 1594 return -1;
daniele 29:1a47b7151851 1595 }
daniele 29:1a47b7151851 1596 listen->filter_mode = PICO_IP_MULTICAST_EXCLUDE;
daniele 29:1a47b7151851 1597 listen->mcast_link = mreq->mcast_link_addr;
daniele 29:1a47b7151851 1598 listen->mcast_group = mreq->mcast_group_addr;
daniele 29:1a47b7151851 1599 listen->MCASTSources.root = &LEAF;
daniele 29:1a47b7151851 1600 listen->MCASTSources.compare = mcast_sources_cmp;
daniele 29:1a47b7151851 1601 pico_tree_insert(s->MCASTListen, listen);
daniele 29:1a47b7151851 1602 }
daniele 29:1a47b7151851 1603
daniele 29:1a47b7151851 1604 pico_tree_insert(&MCASTSockets, s);
daniele 29:1a47b7151851 1605 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
daniele 29:1a47b7151851 1606 if (filter_mode < 0)
daniele 29:1a47b7151851 1607 return -1;
daniele 29:1a47b7151851 1608
daniele 29:1a47b7151851 1609 return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, filter_mode, &MCASTFilter);
daniele 29:1a47b7151851 1610 }
daniele 29:1a47b7151851 1611 break;
daniele 29:1a47b7151851 1612
daniele 29:1a47b7151851 1613 case PICO_IP_DROP_MEMBERSHIP:
daniele 29:1a47b7151851 1614 /* EXCLUDE mode */
daniele 29:1a47b7151851 1615 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 48:40fc4462265c 1616 int filter_mode = 0;
daniele 29:1a47b7151851 1617 struct pico_ip_mreq *mreq = NULL;
daniele 29:1a47b7151851 1618 struct pico_mcast_listen *listen = NULL, ltest = {0};
daniele 29:1a47b7151851 1619 struct pico_ip4 *source = NULL;
daniele 29:1a47b7151851 1620 struct pico_ipv4_link *mcast_link = NULL;
daniele 29:1a47b7151851 1621 struct pico_tree_node *index, *_tmp;
daniele 29:1a47b7151851 1622
daniele 29:1a47b7151851 1623 if (!value) {
daniele 29:1a47b7151851 1624 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1625 return -1;
daniele 29:1a47b7151851 1626 }
daniele 29:1a47b7151851 1627 mreq = (struct pico_ip_mreq *) value;
daniele 29:1a47b7151851 1628 mcast_link = pico_socket_setoption_mcastargs_validation(mreq, NULL);
daniele 29:1a47b7151851 1629 if (!mcast_link) {
daniele 29:1a47b7151851 1630 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1631 return -1;
daniele 29:1a47b7151851 1632 }
daniele 29:1a47b7151851 1633 if (!mreq->mcast_link_addr.addr)
daniele 29:1a47b7151851 1634 mreq->mcast_link_addr.addr = mcast_link->address.addr;
daniele 29:1a47b7151851 1635
daniele 29:1a47b7151851 1636 if (!s->MCASTListen) { /* No RBTree allocated yet */
daniele 29:1a47b7151851 1637 so_mcast_dbg("socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before any PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n");
daniele 29:1a47b7151851 1638 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1639 return -1;
daniele 29:1a47b7151851 1640 }
daniele 29:1a47b7151851 1641 ltest.mcast_link = mreq->mcast_link_addr;
daniele 29:1a47b7151851 1642 ltest.mcast_group = mreq->mcast_group_addr;
daniele 29:1a47b7151851 1643 listen = pico_tree_findKey(s->MCASTListen, &ltest);
daniele 29:1a47b7151851 1644 if (!listen) {
daniele 29:1a47b7151851 1645 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n");
daniele 29:1a47b7151851 1646 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 29:1a47b7151851 1647 return -1;
daniele 29:1a47b7151851 1648 } else {
daniele 29:1a47b7151851 1649 pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
daniele 29:1a47b7151851 1650 {
daniele 29:1a47b7151851 1651 source = index->keyValue;
daniele 29:1a47b7151851 1652 pico_tree_delete(&listen->MCASTSources, source);
daniele 29:1a47b7151851 1653 pico_free(source);
daniele 29:1a47b7151851 1654 }
daniele 29:1a47b7151851 1655 pico_tree_delete(s->MCASTListen, listen);
daniele 29:1a47b7151851 1656 pico_free(listen);
daniele 29:1a47b7151851 1657 if (pico_tree_empty(s->MCASTListen)) {
daniele 29:1a47b7151851 1658 pico_free(s->MCASTListen);
daniele 29:1a47b7151851 1659 s->MCASTListen = NULL;
daniele 29:1a47b7151851 1660 pico_tree_delete(&MCASTSockets, s);
daniele 29:1a47b7151851 1661 }
daniele 29:1a47b7151851 1662 }
daniele 29:1a47b7151851 1663
daniele 29:1a47b7151851 1664 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
daniele 29:1a47b7151851 1665 if (filter_mode < 0)
daniele 29:1a47b7151851 1666 return -1;
daniele 29:1a47b7151851 1667
daniele 29:1a47b7151851 1668 return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, filter_mode, &MCASTFilter);
daniele 29:1a47b7151851 1669 }
daniele 29:1a47b7151851 1670 break;
daniele 29:1a47b7151851 1671
daniele 29:1a47b7151851 1672 case PICO_IP_UNBLOCK_SOURCE:
daniele 29:1a47b7151851 1673 /* EXCLUDE mode */
daniele 29:1a47b7151851 1674 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 48:40fc4462265c 1675 int filter_mode = 0;
daniele 29:1a47b7151851 1676 struct pico_ip_mreq_source *mreq = NULL;
daniele 29:1a47b7151851 1677 struct pico_mcast_listen *listen = NULL, ltest = {0};
daniele 29:1a47b7151851 1678 struct pico_ip4 *source = NULL, stest = {0};
daniele 29:1a47b7151851 1679 struct pico_ipv4_link *mcast_link = NULL;
daniele 29:1a47b7151851 1680
daniele 29:1a47b7151851 1681 if (!value) {
daniele 29:1a47b7151851 1682 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1683 return -1;
daniele 29:1a47b7151851 1684 }
daniele 29:1a47b7151851 1685 mreq = (struct pico_ip_mreq_source *) value;
daniele 29:1a47b7151851 1686 mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq);
daniele 29:1a47b7151851 1687 if (!mcast_link) {
daniele 29:1a47b7151851 1688 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1689 return -1;
daniele 29:1a47b7151851 1690 }
daniele 29:1a47b7151851 1691 if (!mreq->mcast_link_addr.addr)
daniele 29:1a47b7151851 1692 mreq->mcast_link_addr.addr = mcast_link->address.addr;
daniele 29:1a47b7151851 1693
daniele 29:1a47b7151851 1694 if (!s->MCASTListen) { /* No RBTree allocated yet */
daniele 29:1a47b7151851 1695 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before any PICO_IP_ADD_MEMBERSHIP\n");
daniele 29:1a47b7151851 1696 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1697 return -1;
daniele 29:1a47b7151851 1698 }
daniele 29:1a47b7151851 1699 ltest.mcast_link = mreq->mcast_link_addr;
daniele 29:1a47b7151851 1700 ltest.mcast_group = mreq->mcast_group_addr;
daniele 29:1a47b7151851 1701 listen = pico_tree_findKey(s->MCASTListen, &ltest);
daniele 29:1a47b7151851 1702 if (!listen) {
daniele 29:1a47b7151851 1703 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
daniele 29:1a47b7151851 1704 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1705 return -1;
daniele 29:1a47b7151851 1706 } else {
daniele 29:1a47b7151851 1707 if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
daniele 29:1a47b7151851 1708 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
daniele 29:1a47b7151851 1709 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1710 return -1;
daniele 29:1a47b7151851 1711 }
daniele 29:1a47b7151851 1712 stest.addr = mreq->mcast_source_addr.addr;
daniele 29:1a47b7151851 1713 source = pico_tree_findKey(&listen->MCASTSources, &stest);
daniele 29:1a47b7151851 1714 if (!source) {
daniele 29:1a47b7151851 1715 so_mcast_dbg("pico_socket_setoption: ERROR address to unblock not in source list\n");
daniele 29:1a47b7151851 1716 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 29:1a47b7151851 1717 return -1;
daniele 29:1a47b7151851 1718 } else {
daniele 29:1a47b7151851 1719 pico_tree_delete(&listen->MCASTSources, source);
daniele 29:1a47b7151851 1720 pico_free(source);
daniele 29:1a47b7151851 1721 }
daniele 29:1a47b7151851 1722 }
daniele 29:1a47b7151851 1723
daniele 29:1a47b7151851 1724 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
daniele 29:1a47b7151851 1725 if (filter_mode < 0)
daniele 29:1a47b7151851 1726 return -1;
daniele 29:1a47b7151851 1727
daniele 29:1a47b7151851 1728 return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, filter_mode, &MCASTFilter);
daniele 29:1a47b7151851 1729 }
daniele 29:1a47b7151851 1730 break;
daniele 29:1a47b7151851 1731
daniele 29:1a47b7151851 1732 case PICO_IP_BLOCK_SOURCE:
daniele 29:1a47b7151851 1733 /* EXCLUDE mode */
daniele 29:1a47b7151851 1734 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 48:40fc4462265c 1735 int filter_mode = 0;
daniele 29:1a47b7151851 1736 struct pico_ip_mreq_source *mreq = NULL;
daniele 29:1a47b7151851 1737 struct pico_mcast_listen *listen = NULL, ltest = {0};
daniele 29:1a47b7151851 1738 struct pico_ip4 *source = NULL, stest = {0};
daniele 29:1a47b7151851 1739 struct pico_ipv4_link *mcast_link = NULL;
daniele 29:1a47b7151851 1740
daniele 29:1a47b7151851 1741 if (!value) {
daniele 29:1a47b7151851 1742 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1743 return -1;
daniele 29:1a47b7151851 1744 }
daniele 29:1a47b7151851 1745 mreq = (struct pico_ip_mreq_source *) value;
daniele 29:1a47b7151851 1746 mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq);
daniele 29:1a47b7151851 1747 if (!mcast_link) {
daniele 29:1a47b7151851 1748 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1749 return -1;
daniele 29:1a47b7151851 1750 }
daniele 29:1a47b7151851 1751 if (!mreq->mcast_link_addr.addr)
daniele 29:1a47b7151851 1752 mreq->mcast_link_addr.addr = mcast_link->address.addr;
daniele 29:1a47b7151851 1753
daniele 29:1a47b7151851 1754 if (!s->MCASTListen) { /* No RBTree allocated yet */
daniele 29:1a47b7151851 1755 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before any PICO_IP_ADD_MEMBERSHIP\n");
daniele 29:1a47b7151851 1756 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1757 return -1;
daniele 29:1a47b7151851 1758 }
daniele 29:1a47b7151851 1759 ltest.mcast_link = mreq->mcast_link_addr;
daniele 29:1a47b7151851 1760 ltest.mcast_group = mreq->mcast_group_addr;
daniele 29:1a47b7151851 1761 listen = pico_tree_findKey(s->MCASTListen, &ltest);
daniele 29:1a47b7151851 1762 if (!listen) {
daniele 29:1a47b7151851 1763 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
daniele 29:1a47b7151851 1764 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1765 return -1;
daniele 29:1a47b7151851 1766 } else {
daniele 29:1a47b7151851 1767 if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
daniele 29:1a47b7151851 1768 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
daniele 29:1a47b7151851 1769 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1770 return -1;
daniele 29:1a47b7151851 1771 }
daniele 29:1a47b7151851 1772 stest.addr = mreq->mcast_source_addr.addr;
daniele 29:1a47b7151851 1773 source = pico_tree_findKey(&listen->MCASTSources, &stest);
daniele 29:1a47b7151851 1774 if (source) {
daniele 29:1a47b7151851 1775 so_mcast_dbg("pico_socket_setoption: ERROR address to block already in source list\n");
daniele 29:1a47b7151851 1776 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 29:1a47b7151851 1777 return -1;
daniele 29:1a47b7151851 1778 } else {
daniele 29:1a47b7151851 1779 source = pico_zalloc(sizeof(struct pico_ip4));
daniele 29:1a47b7151851 1780 if (!source) {
daniele 29:1a47b7151851 1781 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 1782 return -1;
daniele 29:1a47b7151851 1783 }
daniele 29:1a47b7151851 1784 source->addr = mreq->mcast_source_addr.addr;
daniele 29:1a47b7151851 1785 pico_tree_insert(&listen->MCASTSources, source);
daniele 29:1a47b7151851 1786 }
daniele 29:1a47b7151851 1787 }
daniele 29:1a47b7151851 1788
daniele 29:1a47b7151851 1789 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
daniele 29:1a47b7151851 1790 if (filter_mode < 0)
daniele 29:1a47b7151851 1791 return -1;
daniele 29:1a47b7151851 1792
daniele 29:1a47b7151851 1793 return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, filter_mode, &MCASTFilter);
daniele 29:1a47b7151851 1794 }
daniele 29:1a47b7151851 1795 break;
daniele 29:1a47b7151851 1796
daniele 29:1a47b7151851 1797 case PICO_IP_ADD_SOURCE_MEMBERSHIP:
daniele 29:1a47b7151851 1798 /* INCLUDE mode */
daniele 29:1a47b7151851 1799 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 48:40fc4462265c 1800 int filter_mode = 0, reference_count = 0;
daniele 29:1a47b7151851 1801 struct pico_ip_mreq_source *mreq = NULL;
daniele 29:1a47b7151851 1802 struct pico_mcast_listen *listen = NULL, ltest = {0};
daniele 29:1a47b7151851 1803 struct pico_ip4 *source = NULL, stest = {0};
daniele 29:1a47b7151851 1804 struct pico_ipv4_link *mcast_link = NULL;
daniele 29:1a47b7151851 1805
daniele 29:1a47b7151851 1806 if (!value) {
daniele 29:1a47b7151851 1807 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1808 return -1;
daniele 29:1a47b7151851 1809 }
daniele 29:1a47b7151851 1810 mreq = (struct pico_ip_mreq_source *) value;
daniele 29:1a47b7151851 1811 mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq);
daniele 29:1a47b7151851 1812 if (!mcast_link) {
daniele 29:1a47b7151851 1813 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1814 return -1;
daniele 29:1a47b7151851 1815 }
daniele 29:1a47b7151851 1816 if (!mreq->mcast_link_addr.addr)
daniele 29:1a47b7151851 1817 mreq->mcast_link_addr.addr = mcast_link->address.addr;
daniele 29:1a47b7151851 1818
daniele 29:1a47b7151851 1819 if (!s->MCASTListen) { /* No RBTree allocated yet */
daniele 29:1a47b7151851 1820 s->MCASTListen = pico_zalloc(sizeof(struct pico_tree));
daniele 29:1a47b7151851 1821 if (!s->MCASTListen) {
daniele 29:1a47b7151851 1822 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 1823 return -1;
daniele 29:1a47b7151851 1824 }
daniele 29:1a47b7151851 1825 s->MCASTListen->root = &LEAF;
daniele 29:1a47b7151851 1826 s->MCASTListen->compare = mcast_listen_cmp;
daniele 29:1a47b7151851 1827 }
daniele 29:1a47b7151851 1828 ltest.mcast_link = mreq->mcast_link_addr;
daniele 29:1a47b7151851 1829 ltest.mcast_group = mreq->mcast_group_addr;
daniele 29:1a47b7151851 1830 listen = pico_tree_findKey(s->MCASTListen, &ltest);
daniele 29:1a47b7151851 1831 if (listen) {
daniele 29:1a47b7151851 1832 if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
daniele 29:1a47b7151851 1833 so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
daniele 29:1a47b7151851 1834 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1835 return -1;
daniele 29:1a47b7151851 1836 }
daniele 29:1a47b7151851 1837 stest.addr = mreq->mcast_source_addr.addr;
daniele 29:1a47b7151851 1838 source = pico_tree_findKey(&listen->MCASTSources, &stest);
daniele 29:1a47b7151851 1839 if (source) {
daniele 29:1a47b7151851 1840 so_mcast_dbg("pico_socket_setoption: ERROR source address to allow already in source list\n");
daniele 29:1a47b7151851 1841 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 29:1a47b7151851 1842 return -1;
daniele 29:1a47b7151851 1843 } else {
daniele 29:1a47b7151851 1844 source = pico_zalloc(sizeof(struct pico_ip4));
daniele 29:1a47b7151851 1845 if (!source) {
daniele 29:1a47b7151851 1846 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 1847 return -1;
daniele 29:1a47b7151851 1848 }
daniele 29:1a47b7151851 1849 source->addr = mreq->mcast_source_addr.addr;
daniele 29:1a47b7151851 1850 pico_tree_insert(&listen->MCASTSources, source);
daniele 29:1a47b7151851 1851 }
daniele 29:1a47b7151851 1852 } else {
daniele 29:1a47b7151851 1853 listen = pico_zalloc(sizeof(struct pico_mcast_listen));
daniele 29:1a47b7151851 1854 if (!listen) {
daniele 29:1a47b7151851 1855 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 1856 return -1;
daniele 29:1a47b7151851 1857 }
daniele 29:1a47b7151851 1858 listen->filter_mode = PICO_IP_MULTICAST_INCLUDE;
daniele 29:1a47b7151851 1859 listen->mcast_link = mreq->mcast_link_addr;
daniele 29:1a47b7151851 1860 listen->mcast_group = mreq->mcast_group_addr;
daniele 29:1a47b7151851 1861 listen->MCASTSources.root = &LEAF;
daniele 29:1a47b7151851 1862 listen->MCASTSources.compare = mcast_sources_cmp;
daniele 29:1a47b7151851 1863 source = pico_zalloc(sizeof(struct pico_ip4));
daniele 29:1a47b7151851 1864 if (!source) {
daniele 29:1a47b7151851 1865 pico_free(listen);
daniele 29:1a47b7151851 1866 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 1867 return -1;
daniele 29:1a47b7151851 1868 }
daniele 29:1a47b7151851 1869 source->addr = mreq->mcast_source_addr.addr;
daniele 29:1a47b7151851 1870 pico_tree_insert(&listen->MCASTSources, source);
daniele 29:1a47b7151851 1871 pico_tree_insert(s->MCASTListen, listen);
daniele 29:1a47b7151851 1872 reference_count = 1;
daniele 29:1a47b7151851 1873 }
daniele 29:1a47b7151851 1874
daniele 29:1a47b7151851 1875 pico_tree_insert(&MCASTSockets, s);
daniele 29:1a47b7151851 1876 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
daniele 29:1a47b7151851 1877 if (filter_mode < 0)
daniele 29:1a47b7151851 1878 return -1;
daniele 29:1a47b7151851 1879
daniele 29:1a47b7151851 1880 return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, reference_count, filter_mode, &MCASTFilter);
daniele 29:1a47b7151851 1881 }
daniele 29:1a47b7151851 1882 break;
daniele 29:1a47b7151851 1883
daniele 29:1a47b7151851 1884 case PICO_IP_DROP_SOURCE_MEMBERSHIP:
daniele 29:1a47b7151851 1885 /* INCLUDE mode */
daniele 29:1a47b7151851 1886 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 48:40fc4462265c 1887 int filter_mode = 0, reference_count = 0;
daniele 29:1a47b7151851 1888 struct pico_ip_mreq_source *mreq = NULL;
daniele 29:1a47b7151851 1889 struct pico_mcast_listen *listen = NULL, ltest = {0};
daniele 29:1a47b7151851 1890 struct pico_ip4 *source = NULL, stest = {0};
daniele 29:1a47b7151851 1891 struct pico_ipv4_link *mcast_link = NULL;
daniele 29:1a47b7151851 1892
daniele 29:1a47b7151851 1893 if (!value) {
daniele 29:1a47b7151851 1894 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1895 return -1;
daniele 29:1a47b7151851 1896 }
daniele 29:1a47b7151851 1897 mreq = (struct pico_ip_mreq_source *) value;
daniele 29:1a47b7151851 1898 mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq);
daniele 29:1a47b7151851 1899 if (!mcast_link) {
daniele 29:1a47b7151851 1900 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1901 return -1;
daniele 29:1a47b7151851 1902 }
daniele 29:1a47b7151851 1903 if (!mreq->mcast_link_addr.addr)
daniele 29:1a47b7151851 1904 mreq->mcast_link_addr.addr = mcast_link->address.addr;
daniele 29:1a47b7151851 1905
daniele 29:1a47b7151851 1906 if (!s->MCASTListen) { /* No RBTree allocated yet */
daniele 29:1a47b7151851 1907 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before any PICO_IP_ADD_SOURCE_MEMBERSHIP\n");
daniele 29:1a47b7151851 1908 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1909 return -1;
daniele 29:1a47b7151851 1910 }
daniele 29:1a47b7151851 1911 ltest.mcast_link = mreq->mcast_link_addr;
daniele 29:1a47b7151851 1912 ltest.mcast_group = mreq->mcast_group_addr;
daniele 29:1a47b7151851 1913 listen = pico_tree_findKey(s->MCASTListen, &ltest);
daniele 29:1a47b7151851 1914 if (!listen) {
daniele 29:1a47b7151851 1915 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before PICO_IP_ADD_SOURCE_MEMBERSHIP\n");
daniele 29:1a47b7151851 1916 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 29:1a47b7151851 1917 return -1;
daniele 29:1a47b7151851 1918 } else {
daniele 29:1a47b7151851 1919 if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
daniele 29:1a47b7151851 1920 so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
daniele 29:1a47b7151851 1921 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1922 return -1;
daniele 29:1a47b7151851 1923 }
daniele 29:1a47b7151851 1924 stest.addr = mreq->mcast_source_addr.addr;
daniele 29:1a47b7151851 1925 source = pico_tree_findKey(&listen->MCASTSources, &stest);
daniele 29:1a47b7151851 1926 if (!source) {
daniele 29:1a47b7151851 1927 so_mcast_dbg("pico_socket_setoption: ERROR address to drop not in source list\n");
daniele 29:1a47b7151851 1928 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 29:1a47b7151851 1929 return -1;
daniele 29:1a47b7151851 1930 } else {
daniele 29:1a47b7151851 1931 pico_tree_delete(&listen->MCASTSources, source);
daniele 29:1a47b7151851 1932 pico_free(source);
daniele 29:1a47b7151851 1933 if (pico_tree_empty(&listen->MCASTSources)) { /* 1 if empty, 0 otherwise */
daniele 29:1a47b7151851 1934 reference_count = 1;
daniele 29:1a47b7151851 1935 pico_tree_delete(s->MCASTListen, listen);
daniele 29:1a47b7151851 1936 pico_free(listen);
daniele 29:1a47b7151851 1937 if (pico_tree_empty(s->MCASTListen)) {
daniele 29:1a47b7151851 1938 pico_free(s->MCASTListen);
daniele 29:1a47b7151851 1939 s->MCASTListen = NULL;
daniele 29:1a47b7151851 1940 pico_tree_delete(&MCASTSockets, s);
daniele 29:1a47b7151851 1941 }
daniele 29:1a47b7151851 1942 }
daniele 29:1a47b7151851 1943 }
daniele 29:1a47b7151851 1944 }
daniele 29:1a47b7151851 1945
daniele 29:1a47b7151851 1946 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
daniele 29:1a47b7151851 1947 if (filter_mode < 0)
daniele 29:1a47b7151851 1948 return -1;
daniele 29:1a47b7151851 1949
daniele 29:1a47b7151851 1950 return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, reference_count, filter_mode, &MCASTFilter);
daniele 29:1a47b7151851 1951 }
daniele 29:1a47b7151851 1952 break;
daniele 29:1a47b7151851 1953 #endif /* PICO_SUPPORT_MCAST */
daniele 29:1a47b7151851 1954
daniele 29:1a47b7151851 1955 default:
daniele 29:1a47b7151851 1956 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1957 return -1;
daniele 29:1a47b7151851 1958 }
daniele 29:1a47b7151851 1959
daniele 29:1a47b7151851 1960 if (pico_err != PICO_ERR_NOERR)
daniele 29:1a47b7151851 1961 return -1;
daniele 29:1a47b7151851 1962 else
daniele 29:1a47b7151851 1963 return 0;
daniele 29:1a47b7151851 1964 }
daniele 29:1a47b7151851 1965
daniele 29:1a47b7151851 1966 #define PICO_SOCKET_GETOPT(socket,index) ((socket->opt_flags & (1 << index)) != 0)
daniele 29:1a47b7151851 1967
daniele 29:1a47b7151851 1968 int pico_socket_getoption(struct pico_socket *s, int option, void *value)
daniele 29:1a47b7151851 1969 {
daniele 29:1a47b7151851 1970 if (!s || !value) {
daniele 29:1a47b7151851 1971 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1972 return -1;
daniele 29:1a47b7151851 1973 }
daniele 29:1a47b7151851 1974
daniele 29:1a47b7151851 1975 switch (option)
daniele 29:1a47b7151851 1976 {
daniele 29:1a47b7151851 1977 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 1978 case PICO_TCP_NODELAY:
daniele 29:1a47b7151851 1979 if (s->proto->proto_number == PICO_PROTO_TCP)
daniele 29:1a47b7151851 1980 /* state of the NODELAY option */
daniele 29:1a47b7151851 1981 *(int *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_TCPNODELAY);
daniele 29:1a47b7151851 1982 else
daniele 29:1a47b7151851 1983 *(int *)value = 0;
daniele 29:1a47b7151851 1984 break;
daniele 29:1a47b7151851 1985 #endif
daniele 29:1a47b7151851 1986
daniele 29:1a47b7151851 1987 #ifdef PICO_SUPPORT_MCAST
daniele 29:1a47b7151851 1988 case PICO_IP_MULTICAST_IF:
daniele 29:1a47b7151851 1989 pico_err = PICO_ERR_EOPNOTSUPP;
daniele 29:1a47b7151851 1990 return -1;
daniele 29:1a47b7151851 1991 break;
daniele 29:1a47b7151851 1992
daniele 29:1a47b7151851 1993 case PICO_IP_MULTICAST_TTL:
daniele 29:1a47b7151851 1994 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 1995 pico_udp_get_mc_ttl(s, (uint8_t *) value);
daniele 29:1a47b7151851 1996 } else {
daniele 29:1a47b7151851 1997 *(uint8_t *)value = 0;
daniele 29:1a47b7151851 1998 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 1999 return -1;
daniele 29:1a47b7151851 2000 }
daniele 29:1a47b7151851 2001 break;
daniele 29:1a47b7151851 2002
daniele 29:1a47b7151851 2003 case PICO_IP_MULTICAST_LOOP:
daniele 29:1a47b7151851 2004 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 2005 *(uint8_t *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
daniele 29:1a47b7151851 2006 } else {
daniele 29:1a47b7151851 2007 *(uint8_t *)value = 0;
daniele 29:1a47b7151851 2008 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 2009 return -1;
daniele 29:1a47b7151851 2010 }
daniele 29:1a47b7151851 2011 break;
daniele 29:1a47b7151851 2012 #endif /* PICO_SUPPORT_MCAST */
daniele 29:1a47b7151851 2013
daniele 29:1a47b7151851 2014 default:
daniele 29:1a47b7151851 2015 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 2016 return -1;
daniele 29:1a47b7151851 2017 }
daniele 29:1a47b7151851 2018
daniele 29:1a47b7151851 2019 return 0;
daniele 29:1a47b7151851 2020 }
daniele 29:1a47b7151851 2021
daniele 29:1a47b7151851 2022
daniele 29:1a47b7151851 2023 int pico_socket_shutdown(struct pico_socket *s, int mode)
daniele 29:1a47b7151851 2024 {
daniele 29:1a47b7151851 2025 if (!s) {
daniele 29:1a47b7151851 2026 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 2027 return -1;
daniele 29:1a47b7151851 2028 } else {
daniele 29:1a47b7151851 2029 /* check if exists in tree */
daniele 29:1a47b7151851 2030 /* See task #178 */
daniele 29:1a47b7151851 2031 if (pico_check_socket(s) != 0) {
daniele 29:1a47b7151851 2032 pico_free(s); /* close socket after bind or connect failed */
daniele 29:1a47b7151851 2033 return 0;
daniele 29:1a47b7151851 2034 }
daniele 29:1a47b7151851 2035 }
daniele 29:1a47b7151851 2036
daniele 29:1a47b7151851 2037 #ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 2038 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 29:1a47b7151851 2039 if (mode & PICO_SHUT_RDWR)
daniele 29:1a47b7151851 2040 pico_socket_alter_state(s, PICO_SOCKET_STATE_CLOSED, PICO_SOCKET_STATE_CLOSING |PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED, 0);
daniele 29:1a47b7151851 2041 else if (mode & PICO_SHUT_RD)
tass 51:ab4529a384a6 2042 pico_socket_alter_state(s, 0, PICO_SOCKET_STATE_BOUND, 0);
daniele 29:1a47b7151851 2043 }
daniele 29:1a47b7151851 2044 #endif
daniele 29:1a47b7151851 2045 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 2046 if (PROTO(s) == PICO_PROTO_TCP) {
tass 51:ab4529a384a6 2047 if(mode & PICO_SHUT_RDWR)
tass 51:ab4529a384a6 2048 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL | PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
tass 51:ab4529a384a6 2049 else if (mode & PICO_SHUT_WR)
daniele 29:1a47b7151851 2050 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL, 0, 0);
daniele 29:1a47b7151851 2051 else if (mode & PICO_SHUT_RD)
daniele 29:1a47b7151851 2052 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
daniele 29:1a47b7151851 2053
daniele 29:1a47b7151851 2054 }
daniele 29:1a47b7151851 2055 #endif
daniele 29:1a47b7151851 2056 return 0;
daniele 29:1a47b7151851 2057 }
daniele 29:1a47b7151851 2058
daniele 29:1a47b7151851 2059 int pico_socket_close(struct pico_socket *s)
daniele 29:1a47b7151851 2060 {
daniele 29:1a47b7151851 2061 return pico_socket_shutdown(s, PICO_SHUT_RDWR);
daniele 29:1a47b7151851 2062 }
daniele 29:1a47b7151851 2063
daniele 29:1a47b7151851 2064 #ifdef PICO_SUPPORT_CRC
daniele 29:1a47b7151851 2065 static inline int pico_transport_crc_check(struct pico_frame *f)
daniele 29:1a47b7151851 2066 {
daniele 29:1a47b7151851 2067 struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr;
daniele 29:1a47b7151851 2068 struct pico_udp_hdr *udp_hdr = NULL;
daniele 29:1a47b7151851 2069 uint16_t checksum_invalid = 1;
daniele 29:1a47b7151851 2070
daniele 29:1a47b7151851 2071 switch (net_hdr->proto)
daniele 29:1a47b7151851 2072 {
daniele 29:1a47b7151851 2073 case PICO_PROTO_TCP:
daniele 29:1a47b7151851 2074 checksum_invalid = short_be(pico_tcp_checksum_ipv4(f));
daniele 29:1a47b7151851 2075 //dbg("TCP CRC validation == %u\n", checksum_invalid);
daniele 29:1a47b7151851 2076 if (checksum_invalid) {
daniele 29:1a47b7151851 2077 //dbg("TCP CRC: validation failed!\n");
daniele 29:1a47b7151851 2078 pico_frame_discard(f);
daniele 29:1a47b7151851 2079 return 0;
daniele 29:1a47b7151851 2080 }
daniele 29:1a47b7151851 2081 break;
daniele 29:1a47b7151851 2082
daniele 29:1a47b7151851 2083 case PICO_PROTO_UDP:
daniele 29:1a47b7151851 2084 udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
daniele 29:1a47b7151851 2085 if (short_be(udp_hdr->crc)) {
daniele 29:1a47b7151851 2086 checksum_invalid = short_be(pico_udp_checksum_ipv4(f));
daniele 29:1a47b7151851 2087 //dbg("UDP CRC validation == %u\n", checksum_invalid);
daniele 29:1a47b7151851 2088 if (checksum_invalid) {
daniele 29:1a47b7151851 2089 //dbg("UDP CRC: validation failed!\n");
daniele 29:1a47b7151851 2090 pico_frame_discard(f);
daniele 29:1a47b7151851 2091 return 0;
daniele 29:1a47b7151851 2092 }
daniele 29:1a47b7151851 2093 }
daniele 29:1a47b7151851 2094 break;
daniele 29:1a47b7151851 2095
daniele 29:1a47b7151851 2096 default:
daniele 29:1a47b7151851 2097 // Do nothing
daniele 29:1a47b7151851 2098 break;
daniele 29:1a47b7151851 2099 }
daniele 29:1a47b7151851 2100 return 1;
daniele 29:1a47b7151851 2101 }
daniele 29:1a47b7151851 2102 #else
daniele 29:1a47b7151851 2103 static inline int pico_transport_crc_check(struct pico_frame *f)
daniele 29:1a47b7151851 2104 {
tass 51:ab4529a384a6 2105 IGNORE_PARAMETER(f);
tass 51:ab4529a384a6 2106 return 1;
daniele 29:1a47b7151851 2107 }
daniele 29:1a47b7151851 2108 #endif /* PICO_SUPPORT_CRC */
daniele 29:1a47b7151851 2109
daniele 29:1a47b7151851 2110 int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f)
daniele 29:1a47b7151851 2111 {
daniele 29:1a47b7151851 2112 struct pico_trans *hdr = (struct pico_trans *) f->transport_hdr;
daniele 29:1a47b7151851 2113 int ret = 0;
daniele 29:1a47b7151851 2114
daniele 29:1a47b7151851 2115 if (!hdr) {
daniele 29:1a47b7151851 2116 pico_err = PICO_ERR_EFAULT;
daniele 29:1a47b7151851 2117 return -1;
daniele 29:1a47b7151851 2118 }
daniele 29:1a47b7151851 2119
daniele 29:1a47b7151851 2120 ret = pico_transport_crc_check(f);
daniele 29:1a47b7151851 2121 if (ret < 1)
daniele 29:1a47b7151851 2122 return ret;
daniele 29:1a47b7151851 2123 else
daniele 29:1a47b7151851 2124 ret = 0;
daniele 29:1a47b7151851 2125
daniele 29:1a47b7151851 2126 if ((hdr) && (pico_socket_deliver(self, f, hdr->dport) == 0))
daniele 29:1a47b7151851 2127 return ret;
daniele 29:1a47b7151851 2128
daniele 29:1a47b7151851 2129 if (!IS_BCAST(f)) {
daniele 29:1a47b7151851 2130 dbg("Socket not found... \n");
daniele 29:1a47b7151851 2131 pico_notify_socket_unreachable(f);
daniele 29:1a47b7151851 2132 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 2133 /* if tcp protocol send RST segment */
daniele 29:1a47b7151851 2134 //if (self->proto_number == PICO_PROTO_TCP)
daniele 29:1a47b7151851 2135 // pico_tcp_reply_rst(f);
daniele 29:1a47b7151851 2136 #endif
daniele 29:1a47b7151851 2137 ret = -1;
daniele 29:1a47b7151851 2138 pico_err = PICO_ERR_ENOENT;
daniele 29:1a47b7151851 2139 }
daniele 29:1a47b7151851 2140 pico_frame_discard(f);
daniele 29:1a47b7151851 2141 return ret;
daniele 29:1a47b7151851 2142 }
daniele 29:1a47b7151851 2143
daniele 29:1a47b7151851 2144 #define SL_LOOP_MIN 1
daniele 29:1a47b7151851 2145
daniele 29:1a47b7151851 2146
daniele 29:1a47b7151851 2147 int pico_sockets_loop(int loop_score)
daniele 29:1a47b7151851 2148 {
daniele 29:1a47b7151851 2149 static struct pico_tree_node *index_udp, * index_tcp;
daniele 29:1a47b7151851 2150
daniele 29:1a47b7151851 2151 struct pico_sockport *start;
daniele 29:1a47b7151851 2152 struct pico_socket *s;
daniele 29:1a47b7151851 2153
daniele 29:1a47b7151851 2154 #ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 2155 struct pico_frame *f;
daniele 29:1a47b7151851 2156
daniele 29:1a47b7151851 2157 if (sp_udp == NULL)
daniele 29:1a47b7151851 2158 {
daniele 29:1a47b7151851 2159 index_udp = pico_tree_firstNode(UDPTable.root);
daniele 29:1a47b7151851 2160 sp_udp = index_udp->keyValue;
daniele 29:1a47b7151851 2161 }
daniele 29:1a47b7151851 2162
daniele 29:1a47b7151851 2163 /* init start node */
daniele 29:1a47b7151851 2164 start = sp_udp;
daniele 29:1a47b7151851 2165
daniele 29:1a47b7151851 2166 /* round-robin all transport protocols, break if traversed all protocols */
daniele 29:1a47b7151851 2167 while (loop_score > SL_LOOP_MIN && sp_udp != NULL) {
daniele 29:1a47b7151851 2168 struct pico_tree_node * index;
daniele 29:1a47b7151851 2169
daniele 29:1a47b7151851 2170 pico_tree_foreach(index,&sp_udp->socks){
daniele 29:1a47b7151851 2171 s = index->keyValue;
daniele 29:1a47b7151851 2172 f = pico_dequeue(&s->q_out);
daniele 29:1a47b7151851 2173 while (f && (loop_score > 0)) {
daniele 29:1a47b7151851 2174 pico_proto_udp.push(&pico_proto_udp, f);
daniele 29:1a47b7151851 2175 loop_score -= 1;
daniele 29:1a47b7151851 2176 f = pico_dequeue(&s->q_out);
daniele 29:1a47b7151851 2177 }
daniele 29:1a47b7151851 2178 }
daniele 29:1a47b7151851 2179
daniele 29:1a47b7151851 2180 index_udp = pico_tree_next(index_udp);
daniele 29:1a47b7151851 2181 sp_udp = index_udp->keyValue;
daniele 29:1a47b7151851 2182
daniele 29:1a47b7151851 2183 if (sp_udp == NULL)
daniele 29:1a47b7151851 2184 {
daniele 29:1a47b7151851 2185 index_udp = pico_tree_firstNode(UDPTable.root);
daniele 29:1a47b7151851 2186 sp_udp = index_udp->keyValue;
daniele 29:1a47b7151851 2187 }
daniele 29:1a47b7151851 2188 if (sp_udp == start)
daniele 29:1a47b7151851 2189 break;
daniele 29:1a47b7151851 2190 }
daniele 29:1a47b7151851 2191 #endif
daniele 29:1a47b7151851 2192
daniele 29:1a47b7151851 2193 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 2194 if (sp_tcp == NULL)
daniele 29:1a47b7151851 2195 {
daniele 29:1a47b7151851 2196 index_tcp = pico_tree_firstNode(TCPTable.root);
daniele 29:1a47b7151851 2197 sp_tcp = index_tcp->keyValue;
daniele 29:1a47b7151851 2198 }
daniele 29:1a47b7151851 2199
daniele 29:1a47b7151851 2200 /* init start node */
daniele 29:1a47b7151851 2201 start = sp_tcp;
daniele 29:1a47b7151851 2202
daniele 29:1a47b7151851 2203 while (loop_score > SL_LOOP_MIN && sp_tcp != NULL) {
tass 48:40fc4462265c 2204 struct pico_tree_node * index = NULL;
daniele 29:1a47b7151851 2205 pico_tree_foreach(index, &sp_tcp->socks){
daniele 29:1a47b7151851 2206 s = index->keyValue;
daniele 29:1a47b7151851 2207 loop_score = pico_tcp_output(s, loop_score);
daniele 29:1a47b7151851 2208 if ((s->ev_pending) && s->wakeup) {
daniele 29:1a47b7151851 2209 s->wakeup(s->ev_pending, s);
daniele 29:1a47b7151851 2210 }
daniele 29:1a47b7151851 2211 if (loop_score <= 0) {
daniele 29:1a47b7151851 2212 loop_score = 0;
daniele 29:1a47b7151851 2213 break;
daniele 29:1a47b7151851 2214 }
daniele 29:1a47b7151851 2215 }
daniele 29:1a47b7151851 2216
daniele 29:1a47b7151851 2217 /* check if RB_FOREACH ended, if not, break to keep the cur sp_tcp */
tass 48:40fc4462265c 2218 if (index && index->keyValue)
daniele 29:1a47b7151851 2219 break;
daniele 29:1a47b7151851 2220
daniele 29:1a47b7151851 2221 index_tcp = pico_tree_next(index_tcp);
daniele 29:1a47b7151851 2222 sp_tcp = index_tcp->keyValue;
daniele 29:1a47b7151851 2223
daniele 29:1a47b7151851 2224 if (sp_tcp == NULL)
daniele 29:1a47b7151851 2225 {
daniele 29:1a47b7151851 2226 index_tcp = pico_tree_firstNode(TCPTable.root);
daniele 29:1a47b7151851 2227 sp_tcp = index_tcp->keyValue;
daniele 29:1a47b7151851 2228 }
daniele 29:1a47b7151851 2229 if (sp_tcp == start)
daniele 29:1a47b7151851 2230 break;
daniele 29:1a47b7151851 2231 }
daniele 29:1a47b7151851 2232 #endif
daniele 29:1a47b7151851 2233
daniele 29:1a47b7151851 2234 return loop_score;
daniele 29:1a47b7151851 2235 }
daniele 29:1a47b7151851 2236
daniele 29:1a47b7151851 2237
daniele 29:1a47b7151851 2238 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len)
daniele 29:1a47b7151851 2239 {
daniele 29:1a47b7151851 2240 struct pico_frame *f = NULL;
daniele 29:1a47b7151851 2241
daniele 29:1a47b7151851 2242 #ifdef PICO_SUPPORT_IPV6
daniele 29:1a47b7151851 2243 if (IS_SOCK_IPV6(s))
daniele 29:1a47b7151851 2244 f = pico_proto_ipv6.alloc(&pico_proto_ipv6, len);
daniele 29:1a47b7151851 2245 #endif
daniele 29:1a47b7151851 2246
daniele 29:1a47b7151851 2247 #ifdef PICO_SUPPORT_IPV4
daniele 29:1a47b7151851 2248 if (IS_SOCK_IPV4(s))
daniele 29:1a47b7151851 2249 f = pico_proto_ipv4.alloc(&pico_proto_ipv4, len);
daniele 29:1a47b7151851 2250 #endif
daniele 29:1a47b7151851 2251 if (!f) {
daniele 29:1a47b7151851 2252 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 2253 return f;
daniele 29:1a47b7151851 2254 }
daniele 29:1a47b7151851 2255 f->payload = f->transport_hdr;
daniele 29:1a47b7151851 2256 f->payload_len = len;
daniele 29:1a47b7151851 2257 f->sock = s;
daniele 29:1a47b7151851 2258 return f;
daniele 29:1a47b7151851 2259 }
daniele 29:1a47b7151851 2260
daniele 29:1a47b7151851 2261 int pico_transport_error(struct pico_frame *f, uint8_t proto, int code)
daniele 29:1a47b7151851 2262 {
daniele 29:1a47b7151851 2263 int ret = -1;
daniele 29:1a47b7151851 2264 struct pico_trans *trans = (struct pico_trans*) f->transport_hdr;
daniele 29:1a47b7151851 2265 struct pico_sockport *port = NULL;
daniele 29:1a47b7151851 2266 struct pico_socket *s = NULL;
daniele 29:1a47b7151851 2267 switch (proto) {
daniele 29:1a47b7151851 2268
daniele 29:1a47b7151851 2269
daniele 29:1a47b7151851 2270 #ifdef PICO_SUPPORT_UDP
daniele 29:1a47b7151851 2271 case PICO_PROTO_UDP:
daniele 29:1a47b7151851 2272 port = pico_get_sockport(proto, trans->sport);
daniele 29:1a47b7151851 2273 break;
daniele 29:1a47b7151851 2274 #endif
daniele 29:1a47b7151851 2275
daniele 29:1a47b7151851 2276 #ifdef PICO_SUPPORT_TCP
daniele 29:1a47b7151851 2277 case PICO_PROTO_TCP:
daniele 29:1a47b7151851 2278 port = pico_get_sockport(proto, trans->sport);
daniele 29:1a47b7151851 2279 break;
daniele 29:1a47b7151851 2280 #endif
daniele 29:1a47b7151851 2281
daniele 29:1a47b7151851 2282 default:
daniele 29:1a47b7151851 2283 /* Protocol not available */
daniele 29:1a47b7151851 2284 ret = -1;
daniele 29:1a47b7151851 2285 }
daniele 29:1a47b7151851 2286 if (port) {
daniele 29:1a47b7151851 2287 struct pico_tree_node * index;
daniele 29:1a47b7151851 2288 ret = 0;
daniele 29:1a47b7151851 2289
daniele 29:1a47b7151851 2290 pico_tree_foreach(index,&port->socks) {
daniele 29:1a47b7151851 2291 s = index->keyValue;
daniele 29:1a47b7151851 2292 if (trans->dport == s->remote_port) {
daniele 29:1a47b7151851 2293 if (s->wakeup) {
daniele 29:1a47b7151851 2294 //dbg("SOCKET ERROR FROM ICMP NOTIFICATION. (icmp code= %d)\n\n", code);
daniele 29:1a47b7151851 2295 switch(code) {
daniele 29:1a47b7151851 2296 case PICO_ICMP_UNREACH_PROTOCOL:
daniele 29:1a47b7151851 2297 pico_err = PICO_ERR_EPROTO;
daniele 29:1a47b7151851 2298 break;
daniele 29:1a47b7151851 2299
daniele 29:1a47b7151851 2300 case PICO_ICMP_UNREACH_PORT:
daniele 29:1a47b7151851 2301 pico_err = PICO_ERR_ECONNREFUSED;
daniele 29:1a47b7151851 2302 break;
daniele 29:1a47b7151851 2303
daniele 29:1a47b7151851 2304 case PICO_ICMP_UNREACH_NET:
daniele 29:1a47b7151851 2305 case PICO_ICMP_UNREACH_NET_PROHIB:
daniele 29:1a47b7151851 2306 case PICO_ICMP_UNREACH_NET_UNKNOWN:
daniele 29:1a47b7151851 2307 pico_err = PICO_ERR_ENETUNREACH;
daniele 29:1a47b7151851 2308 break;
daniele 29:1a47b7151851 2309
daniele 29:1a47b7151851 2310 default:
daniele 29:1a47b7151851 2311 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 29:1a47b7151851 2312 }
daniele 29:1a47b7151851 2313 s->wakeup(PICO_SOCK_EV_ERR, s);
daniele 29:1a47b7151851 2314 }
daniele 29:1a47b7151851 2315 break;
daniele 29:1a47b7151851 2316 }
daniele 29:1a47b7151851 2317 }
daniele 29:1a47b7151851 2318 }
daniele 29:1a47b7151851 2319 pico_frame_discard(f);
daniele 29:1a47b7151851 2320 return ret;
daniele 29:1a47b7151851 2321 }
daniele 29:1a47b7151851 2322 #endif
daniele 29:1a47b7151851 2323 #endif