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