[457] | 1 | /**
|
---|
| 2 | * @file
|
---|
| 3 | * Sequential API External module
|
---|
| 4 | *
|
---|
| 5 | * @defgroup netconn Netconn API
|
---|
| 6 | * @ingroup sequential_api
|
---|
| 7 | * Thread-safe, to be called from non-TCPIP threads only.
|
---|
| 8 | * TX/RX handling based on @ref netbuf (containing @ref pbuf)
|
---|
| 9 | * to avoid copying data around.
|
---|
| 10 | *
|
---|
| 11 | * @defgroup netconn_common Common functions
|
---|
| 12 | * @ingroup netconn
|
---|
| 13 | * For use with TCP and UDP
|
---|
| 14 | *
|
---|
| 15 | * @defgroup netconn_tcp TCP only
|
---|
| 16 | * @ingroup netconn
|
---|
| 17 | * TCP only functions
|
---|
| 18 | *
|
---|
| 19 | * @defgroup netconn_udp UDP only
|
---|
| 20 | * @ingroup netconn
|
---|
| 21 | * UDP only functions
|
---|
| 22 | */
|
---|
| 23 |
|
---|
| 24 | /*
|
---|
| 25 | * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
---|
| 26 | * All rights reserved.
|
---|
| 27 | *
|
---|
| 28 | * Redistribution and use in source and binary forms, with or without modification,
|
---|
| 29 | * are permitted provided that the following conditions are met:
|
---|
| 30 | *
|
---|
| 31 | * 1. Redistributions of source code must retain the above copyright notice,
|
---|
| 32 | * this list of conditions and the following disclaimer.
|
---|
| 33 | * 2. Redistributions in binary form must reproduce the above copyright notice,
|
---|
| 34 | * this list of conditions and the following disclaimer in the documentation
|
---|
| 35 | * and/or other materials provided with the distribution.
|
---|
| 36 | * 3. The name of the author may not be used to endorse or promote products
|
---|
| 37 | * derived from this software without specific prior written permission.
|
---|
| 38 | *
|
---|
| 39 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
---|
| 40 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
---|
| 41 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
---|
| 42 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
---|
| 43 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
---|
| 44 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
---|
| 45 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
---|
| 46 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
---|
| 47 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
---|
| 48 | * OF SUCH DAMAGE.
|
---|
| 49 | *
|
---|
| 50 | * This file is part of the lwIP TCP/IP stack.
|
---|
| 51 | *
|
---|
| 52 | * Author: Adam Dunkels <adam@sics.se>
|
---|
| 53 | */
|
---|
| 54 |
|
---|
| 55 | /* This is the part of the API that is linked with
|
---|
| 56 | the application */
|
---|
| 57 |
|
---|
| 58 | #include "lwip/opt.h"
|
---|
| 59 |
|
---|
| 60 | #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
---|
| 61 |
|
---|
| 62 | #include "lwip/api.h"
|
---|
| 63 | #include "lwip/memp.h"
|
---|
| 64 |
|
---|
| 65 | #include "lwip/ip.h"
|
---|
| 66 | #include "lwip/raw.h"
|
---|
| 67 | #include "lwip/udp.h"
|
---|
| 68 | #include "lwip/priv/api_msg.h"
|
---|
| 69 | #include "lwip/priv/tcp_priv.h"
|
---|
| 70 | #include "lwip/priv/tcpip_priv.h"
|
---|
| 71 |
|
---|
| 72 | #ifdef LWIP_HOOK_FILENAME
|
---|
| 73 | #include LWIP_HOOK_FILENAME
|
---|
| 74 | #endif
|
---|
| 75 |
|
---|
| 76 | #include <string.h>
|
---|
| 77 |
|
---|
| 78 | #define API_MSG_VAR_REF(name) API_VAR_REF(name)
|
---|
| 79 | #define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name)
|
---|
| 80 | #define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM)
|
---|
| 81 | #define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL)
|
---|
| 82 | #define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name)
|
---|
| 83 |
|
---|
| 84 | #if TCP_LISTEN_BACKLOG
|
---|
| 85 | /* need to allocate API message for accept so empty message pool does not result in event loss
|
---|
| 86 | * see bug #47512: MPU_COMPATIBLE may fail on empty pool */
|
---|
| 87 | #define API_MSG_VAR_ALLOC_ACCEPT(msg) API_MSG_VAR_ALLOC(msg)
|
---|
| 88 | #define API_MSG_VAR_FREE_ACCEPT(msg) API_MSG_VAR_FREE(msg)
|
---|
| 89 | #else /* TCP_LISTEN_BACKLOG */
|
---|
| 90 | #define API_MSG_VAR_ALLOC_ACCEPT(msg)
|
---|
| 91 | #define API_MSG_VAR_FREE_ACCEPT(msg)
|
---|
| 92 | #endif /* TCP_LISTEN_BACKLOG */
|
---|
| 93 |
|
---|
| 94 | #if LWIP_NETCONN_FULLDUPLEX
|
---|
| 95 | #define NETCONN_RECVMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->recvmbox) && (((conn)->flags & NETCONN_FLAG_MBOXINVALID) == 0))
|
---|
| 96 | #define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & (NETCONN_FLAG_MBOXCLOSED|NETCONN_FLAG_MBOXINVALID)) == 0))
|
---|
| 97 | #define NETCONN_MBOX_WAITING_INC(conn) SYS_ARCH_INC(conn->mbox_threads_waiting, 1)
|
---|
| 98 | #define NETCONN_MBOX_WAITING_DEC(conn) SYS_ARCH_DEC(conn->mbox_threads_waiting, 1)
|
---|
| 99 | #else /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 100 | #define NETCONN_RECVMBOX_WAITABLE(conn) sys_mbox_valid(&(conn)->recvmbox)
|
---|
| 101 | #define NETCONN_ACCEPTMBOX_WAITABLE(conn) (sys_mbox_valid(&(conn)->acceptmbox) && (((conn)->flags & NETCONN_FLAG_MBOXCLOSED) == 0))
|
---|
| 102 | #define NETCONN_MBOX_WAITING_INC(conn)
|
---|
| 103 | #define NETCONN_MBOX_WAITING_DEC(conn)
|
---|
| 104 | #endif /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 105 |
|
---|
| 106 | static err_t netconn_close_shutdown(struct netconn *conn, u8_t how);
|
---|
| 107 |
|
---|
| 108 | /**
|
---|
| 109 | * Call the lower part of a netconn_* function
|
---|
| 110 | * This function is then running in the thread context
|
---|
| 111 | * of tcpip_thread and has exclusive access to lwIP core code.
|
---|
| 112 | *
|
---|
| 113 | * @param fn function to call
|
---|
| 114 | * @param apimsg a struct containing the function to call and its parameters
|
---|
| 115 | * @return ERR_OK if the function was called, another err_t if not
|
---|
| 116 | */
|
---|
| 117 | static err_t
|
---|
| 118 | netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg)
|
---|
| 119 | {
|
---|
| 120 | err_t err;
|
---|
| 121 |
|
---|
| 122 | #ifdef LWIP_DEBUG
|
---|
| 123 | /* catch functions that don't set err */
|
---|
| 124 | apimsg->err = ERR_VAL;
|
---|
| 125 | #endif /* LWIP_DEBUG */
|
---|
| 126 |
|
---|
| 127 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 128 | apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
|
---|
| 129 | #endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 130 |
|
---|
| 131 | err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg));
|
---|
| 132 | if (err == ERR_OK) {
|
---|
| 133 | return apimsg->err;
|
---|
| 134 | }
|
---|
| 135 | return err;
|
---|
| 136 | }
|
---|
| 137 |
|
---|
| 138 | /**
|
---|
| 139 | * Create a new netconn (of a specific type) that has a callback function.
|
---|
| 140 | * The corresponding pcb is also created.
|
---|
| 141 | *
|
---|
| 142 | * @param t the type of 'connection' to create (@see enum netconn_type)
|
---|
| 143 | * @param proto the IP protocol for RAW IP pcbs
|
---|
| 144 | * @param callback a function to call on status changes (RX available, TX'ed)
|
---|
| 145 | * @return a newly allocated struct netconn or
|
---|
| 146 | * NULL on memory error
|
---|
| 147 | */
|
---|
| 148 | struct netconn *
|
---|
| 149 | netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
|
---|
| 150 | {
|
---|
| 151 | struct netconn *conn;
|
---|
| 152 | API_MSG_VAR_DECLARE(msg);
|
---|
| 153 | API_MSG_VAR_ALLOC_RETURN_NULL(msg);
|
---|
| 154 |
|
---|
| 155 | conn = netconn_alloc(t, callback);
|
---|
| 156 | if (conn != NULL) {
|
---|
| 157 | err_t err;
|
---|
| 158 |
|
---|
| 159 | API_MSG_VAR_REF(msg).msg.n.proto = proto;
|
---|
| 160 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 161 | err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg));
|
---|
| 162 | if (err != ERR_OK) {
|
---|
| 163 | LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
|
---|
| 164 | LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
|
---|
| 165 | #if LWIP_TCP
|
---|
| 166 | LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
|
---|
| 167 | #endif /* LWIP_TCP */
|
---|
| 168 | #if !LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 169 | LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
|
---|
| 170 | sys_sem_free(&conn->op_completed);
|
---|
| 171 | #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 172 | sys_mbox_free(&conn->recvmbox);
|
---|
| 173 | memp_free(MEMP_NETCONN, conn);
|
---|
| 174 | API_MSG_VAR_FREE(msg);
|
---|
| 175 | return NULL;
|
---|
| 176 | }
|
---|
| 177 | }
|
---|
| 178 | API_MSG_VAR_FREE(msg);
|
---|
| 179 | return conn;
|
---|
| 180 | }
|
---|
| 181 |
|
---|
| 182 | /**
|
---|
| 183 | * @ingroup netconn_common
|
---|
| 184 | * Close a netconn 'connection' and free all its resources but not the netconn itself.
|
---|
| 185 | * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
|
---|
| 186 | * after this returns.
|
---|
| 187 | *
|
---|
| 188 | * @param conn the netconn to delete
|
---|
| 189 | * @return ERR_OK if the connection was deleted
|
---|
| 190 | */
|
---|
| 191 | err_t
|
---|
| 192 | netconn_prepare_delete(struct netconn *conn)
|
---|
| 193 | {
|
---|
| 194 | err_t err;
|
---|
| 195 | API_MSG_VAR_DECLARE(msg);
|
---|
| 196 |
|
---|
| 197 | /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
|
---|
| 198 | if (conn == NULL) {
|
---|
| 199 | return ERR_OK;
|
---|
| 200 | }
|
---|
| 201 |
|
---|
| 202 | API_MSG_VAR_ALLOC(msg);
|
---|
| 203 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 204 | #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
|
---|
| 205 | /* get the time we started, which is later compared to
|
---|
| 206 | sys_now() + conn->send_timeout */
|
---|
| 207 | API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
|
---|
| 208 | #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
---|
| 209 | #if LWIP_TCP
|
---|
| 210 | API_MSG_VAR_REF(msg).msg.sd.polls_left =
|
---|
| 211 | ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
|
---|
| 212 | #endif /* LWIP_TCP */
|
---|
| 213 | #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
---|
| 214 | err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg));
|
---|
| 215 | API_MSG_VAR_FREE(msg);
|
---|
| 216 |
|
---|
| 217 | if (err != ERR_OK) {
|
---|
| 218 | return err;
|
---|
| 219 | }
|
---|
| 220 | return ERR_OK;
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | /**
|
---|
| 224 | * @ingroup netconn_common
|
---|
| 225 | * Close a netconn 'connection' and free its resources.
|
---|
| 226 | * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
|
---|
| 227 | * after this returns.
|
---|
| 228 | *
|
---|
| 229 | * @param conn the netconn to delete
|
---|
| 230 | * @return ERR_OK if the connection was deleted
|
---|
| 231 | */
|
---|
| 232 | err_t
|
---|
| 233 | netconn_delete(struct netconn *conn)
|
---|
| 234 | {
|
---|
| 235 | err_t err;
|
---|
| 236 |
|
---|
| 237 | /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
|
---|
| 238 | if (conn == NULL) {
|
---|
| 239 | return ERR_OK;
|
---|
| 240 | }
|
---|
| 241 |
|
---|
| 242 | #if LWIP_NETCONN_FULLDUPLEX
|
---|
| 243 | if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
|
---|
| 244 | /* Already called netconn_prepare_delete() before */
|
---|
| 245 | err = ERR_OK;
|
---|
| 246 | } else
|
---|
| 247 | #endif /* LWIP_NETCONN_FULLDUPLEX */
|
---|
| 248 | {
|
---|
| 249 | err = netconn_prepare_delete(conn);
|
---|
| 250 | }
|
---|
| 251 | if (err == ERR_OK) {
|
---|
| 252 | netconn_free(conn);
|
---|
| 253 | }
|
---|
| 254 | return err;
|
---|
| 255 | }
|
---|
| 256 |
|
---|
| 257 | /**
|
---|
| 258 | * Get the local or remote IP address and port of a netconn.
|
---|
| 259 | * For RAW netconns, this returns the protocol instead of a port!
|
---|
| 260 | *
|
---|
| 261 | * @param conn the netconn to query
|
---|
| 262 | * @param addr a pointer to which to save the IP address
|
---|
| 263 | * @param port a pointer to which to save the port (or protocol for RAW)
|
---|
| 264 | * @param local 1 to get the local IP address, 0 to get the remote one
|
---|
| 265 | * @return ERR_CONN for invalid connections
|
---|
| 266 | * ERR_OK if the information was retrieved
|
---|
| 267 | */
|
---|
| 268 | err_t
|
---|
| 269 | netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
|
---|
| 270 | {
|
---|
| 271 | API_MSG_VAR_DECLARE(msg);
|
---|
| 272 | err_t err;
|
---|
| 273 |
|
---|
| 274 | LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 275 | LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
|
---|
| 276 | LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
|
---|
| 277 |
|
---|
| 278 | API_MSG_VAR_ALLOC(msg);
|
---|
| 279 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 280 | API_MSG_VAR_REF(msg).msg.ad.local = local;
|
---|
| 281 | #if LWIP_MPU_COMPATIBLE
|
---|
| 282 | err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg));
|
---|
| 283 | *addr = msg->msg.ad.ipaddr;
|
---|
| 284 | *port = msg->msg.ad.port;
|
---|
| 285 | #else /* LWIP_MPU_COMPATIBLE */
|
---|
| 286 | msg.msg.ad.ipaddr = addr;
|
---|
| 287 | msg.msg.ad.port = port;
|
---|
| 288 | err = netconn_apimsg(lwip_netconn_do_getaddr, &msg);
|
---|
| 289 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 290 | API_MSG_VAR_FREE(msg);
|
---|
| 291 |
|
---|
| 292 | return err;
|
---|
| 293 | }
|
---|
| 294 |
|
---|
| 295 | /**
|
---|
| 296 | * @ingroup netconn_common
|
---|
| 297 | * Bind a netconn to a specific local IP address and port.
|
---|
| 298 | * Binding one netconn twice might not always be checked correctly!
|
---|
| 299 | *
|
---|
| 300 | * @param conn the netconn to bind
|
---|
| 301 | * @param addr the local IP address to bind the netconn to
|
---|
| 302 | * (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses)
|
---|
| 303 | * @param port the local port to bind the netconn to (not used for RAW)
|
---|
| 304 | * @return ERR_OK if bound, any other err_t on failure
|
---|
| 305 | */
|
---|
| 306 | err_t
|
---|
| 307 | netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
|
---|
| 308 | {
|
---|
| 309 | API_MSG_VAR_DECLARE(msg);
|
---|
| 310 | err_t err;
|
---|
| 311 |
|
---|
| 312 | LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 313 |
|
---|
| 314 | #if LWIP_IPV4
|
---|
| 315 | /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
|
---|
| 316 | if (addr == NULL) {
|
---|
| 317 | addr = IP4_ADDR_ANY;
|
---|
| 318 | }
|
---|
| 319 | #endif /* LWIP_IPV4 */
|
---|
| 320 |
|
---|
| 321 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 322 | /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
|
---|
| 323 | * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind
|
---|
| 324 | */
|
---|
| 325 | if ((netconn_get_ipv6only(conn) == 0) &&
|
---|
| 326 | ip_addr_cmp(addr, IP6_ADDR_ANY)) {
|
---|
| 327 | addr = IP_ANY_TYPE;
|
---|
| 328 | }
|
---|
| 329 | #endif /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 330 |
|
---|
| 331 | API_MSG_VAR_ALLOC(msg);
|
---|
| 332 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 333 | API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
|
---|
| 334 | API_MSG_VAR_REF(msg).msg.bc.port = port;
|
---|
| 335 | err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
|
---|
| 336 | API_MSG_VAR_FREE(msg);
|
---|
| 337 |
|
---|
| 338 | return err;
|
---|
| 339 | }
|
---|
| 340 |
|
---|
| 341 | /**
|
---|
| 342 | * @ingroup netconn_common
|
---|
| 343 | * Bind a netconn to a specific interface and port.
|
---|
| 344 | * Binding one netconn twice might not always be checked correctly!
|
---|
| 345 | *
|
---|
| 346 | * @param conn the netconn to bind
|
---|
| 347 | * @param if_idx the local interface index to bind the netconn to
|
---|
| 348 | * @return ERR_OK if bound, any other err_t on failure
|
---|
| 349 | */
|
---|
| 350 | err_t
|
---|
| 351 | netconn_bind_if(struct netconn *conn, u8_t if_idx)
|
---|
| 352 | {
|
---|
| 353 | API_MSG_VAR_DECLARE(msg);
|
---|
| 354 | err_t err;
|
---|
| 355 |
|
---|
| 356 | LWIP_ERROR("netconn_bind_if: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 357 |
|
---|
| 358 | API_MSG_VAR_ALLOC(msg);
|
---|
| 359 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 360 | API_MSG_VAR_REF(msg).msg.bc.if_idx = if_idx;
|
---|
| 361 | err = netconn_apimsg(lwip_netconn_do_bind_if, &API_MSG_VAR_REF(msg));
|
---|
| 362 | API_MSG_VAR_FREE(msg);
|
---|
| 363 |
|
---|
| 364 | return err;
|
---|
| 365 | }
|
---|
| 366 |
|
---|
| 367 | /**
|
---|
| 368 | * @ingroup netconn_common
|
---|
| 369 | * Connect a netconn to a specific remote IP address and port.
|
---|
| 370 | *
|
---|
| 371 | * @param conn the netconn to connect
|
---|
| 372 | * @param addr the remote IP address to connect to
|
---|
| 373 | * @param port the remote port to connect to (no used for RAW)
|
---|
| 374 | * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
|
---|
| 375 | */
|
---|
| 376 | err_t
|
---|
| 377 | netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
|
---|
| 378 | {
|
---|
| 379 | API_MSG_VAR_DECLARE(msg);
|
---|
| 380 | err_t err;
|
---|
| 381 |
|
---|
| 382 | LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 383 |
|
---|
| 384 | #if LWIP_IPV4
|
---|
| 385 | /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
|
---|
| 386 | if (addr == NULL) {
|
---|
| 387 | addr = IP4_ADDR_ANY;
|
---|
| 388 | }
|
---|
| 389 | #endif /* LWIP_IPV4 */
|
---|
| 390 |
|
---|
| 391 | API_MSG_VAR_ALLOC(msg);
|
---|
| 392 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 393 | API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
|
---|
| 394 | API_MSG_VAR_REF(msg).msg.bc.port = port;
|
---|
| 395 | err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg));
|
---|
| 396 | API_MSG_VAR_FREE(msg);
|
---|
| 397 |
|
---|
| 398 | return err;
|
---|
| 399 | }
|
---|
| 400 |
|
---|
| 401 | /**
|
---|
| 402 | * @ingroup netconn_udp
|
---|
| 403 | * Disconnect a netconn from its current peer (only valid for UDP netconns).
|
---|
| 404 | *
|
---|
| 405 | * @param conn the netconn to disconnect
|
---|
| 406 | * @return See @ref err_t
|
---|
| 407 | */
|
---|
| 408 | err_t
|
---|
| 409 | netconn_disconnect(struct netconn *conn)
|
---|
| 410 | {
|
---|
| 411 | API_MSG_VAR_DECLARE(msg);
|
---|
| 412 | err_t err;
|
---|
| 413 |
|
---|
| 414 | LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 415 |
|
---|
| 416 | API_MSG_VAR_ALLOC(msg);
|
---|
| 417 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 418 | err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg));
|
---|
| 419 | API_MSG_VAR_FREE(msg);
|
---|
| 420 |
|
---|
| 421 | return err;
|
---|
| 422 | }
|
---|
| 423 |
|
---|
| 424 | /**
|
---|
| 425 | * @ingroup netconn_tcp
|
---|
| 426 | * Set a TCP netconn into listen mode
|
---|
| 427 | *
|
---|
| 428 | * @param conn the tcp netconn to set to listen mode
|
---|
| 429 | * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
|
---|
| 430 | * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
|
---|
| 431 | * don't return any error (yet?))
|
---|
| 432 | */
|
---|
| 433 | err_t
|
---|
| 434 | netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
|
---|
| 435 | {
|
---|
| 436 | #if LWIP_TCP
|
---|
| 437 | API_MSG_VAR_DECLARE(msg);
|
---|
| 438 | err_t err;
|
---|
| 439 |
|
---|
| 440 | /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
|
---|
| 441 | LWIP_UNUSED_ARG(backlog);
|
---|
| 442 |
|
---|
| 443 | LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 444 |
|
---|
| 445 | API_MSG_VAR_ALLOC(msg);
|
---|
| 446 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 447 | #if TCP_LISTEN_BACKLOG
|
---|
| 448 | API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
|
---|
| 449 | #endif /* TCP_LISTEN_BACKLOG */
|
---|
| 450 | err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
|
---|
| 451 | API_MSG_VAR_FREE(msg);
|
---|
| 452 |
|
---|
| 453 | return err;
|
---|
| 454 | #else /* LWIP_TCP */
|
---|
| 455 | LWIP_UNUSED_ARG(conn);
|
---|
| 456 | LWIP_UNUSED_ARG(backlog);
|
---|
| 457 | return ERR_ARG;
|
---|
| 458 | #endif /* LWIP_TCP */
|
---|
| 459 | }
|
---|
| 460 |
|
---|
| 461 | /**
|
---|
| 462 | * @ingroup netconn_tcp
|
---|
| 463 | * Accept a new connection on a TCP listening netconn.
|
---|
| 464 | *
|
---|
| 465 | * @param conn the TCP listen netconn
|
---|
| 466 | * @param new_conn pointer where the new connection is stored
|
---|
| 467 | * @return ERR_OK if a new connection has been received or an error
|
---|
| 468 | * code otherwise
|
---|
| 469 | */
|
---|
| 470 | err_t
|
---|
| 471 | netconn_accept(struct netconn *conn, struct netconn **new_conn)
|
---|
| 472 | {
|
---|
| 473 | #if LWIP_TCP
|
---|
| 474 | err_t err;
|
---|
| 475 | void *accept_ptr;
|
---|
| 476 | struct netconn *newconn;
|
---|
| 477 | #if TCP_LISTEN_BACKLOG
|
---|
| 478 | API_MSG_VAR_DECLARE(msg);
|
---|
| 479 | #endif /* TCP_LISTEN_BACKLOG */
|
---|
| 480 |
|
---|
| 481 | LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
|
---|
| 482 | *new_conn = NULL;
|
---|
| 483 | LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 484 |
|
---|
| 485 | /* NOTE: Although the opengroup spec says a pending error shall be returned to
|
---|
| 486 | send/recv/getsockopt(SO_ERROR) only, we return it for listening
|
---|
| 487 | connections also, to handle embedded-system errors */
|
---|
| 488 | err = netconn_err(conn);
|
---|
| 489 | if (err != ERR_OK) {
|
---|
| 490 | /* return pending error */
|
---|
| 491 | return err;
|
---|
| 492 | }
|
---|
| 493 | if (!NETCONN_ACCEPTMBOX_WAITABLE(conn)) {
|
---|
| 494 | /* don't accept if closed: this might block the application task
|
---|
| 495 | waiting on acceptmbox forever! */
|
---|
| 496 | return ERR_CLSD;
|
---|
| 497 | }
|
---|
| 498 |
|
---|
| 499 | API_MSG_VAR_ALLOC_ACCEPT(msg);
|
---|
| 500 |
|
---|
| 501 | NETCONN_MBOX_WAITING_INC(conn);
|
---|
| 502 | if (netconn_is_nonblocking(conn)) {
|
---|
| 503 | if (sys_arch_mbox_tryfetch(&conn->acceptmbox, &accept_ptr) == SYS_ARCH_TIMEOUT) {
|
---|
| 504 | API_MSG_VAR_FREE_ACCEPT(msg);
|
---|
| 505 | NETCONN_MBOX_WAITING_DEC(conn);
|
---|
| 506 | return ERR_WOULDBLOCK;
|
---|
| 507 | }
|
---|
| 508 | } else {
|
---|
| 509 | #if LWIP_SO_RCVTIMEO
|
---|
| 510 | if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
---|
| 511 | API_MSG_VAR_FREE_ACCEPT(msg);
|
---|
| 512 | NETCONN_MBOX_WAITING_DEC(conn);
|
---|
| 513 | return ERR_TIMEOUT;
|
---|
| 514 | }
|
---|
| 515 | #else
|
---|
| 516 | sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0);
|
---|
| 517 | #endif /* LWIP_SO_RCVTIMEO*/
|
---|
| 518 | }
|
---|
| 519 | NETCONN_MBOX_WAITING_DEC(conn);
|
---|
| 520 | #if LWIP_NETCONN_FULLDUPLEX
|
---|
| 521 | if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
|
---|
| 522 | if (lwip_netconn_is_deallocated_msg(accept_ptr)) {
|
---|
| 523 | /* the netconn has been closed from another thread */
|
---|
| 524 | API_MSG_VAR_FREE_ACCEPT(msg);
|
---|
| 525 | return ERR_CONN;
|
---|
| 526 | }
|
---|
| 527 | }
|
---|
| 528 | #endif
|
---|
| 529 |
|
---|
| 530 | /* Register event with callback */
|
---|
| 531 | API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
---|
| 532 |
|
---|
| 533 | if (lwip_netconn_is_err_msg(accept_ptr, &err)) {
|
---|
| 534 | /* a connection has been aborted: e.g. out of pcbs or out of netconns during accept */
|
---|
| 535 | API_MSG_VAR_FREE_ACCEPT(msg);
|
---|
| 536 | return err;
|
---|
| 537 | }
|
---|
| 538 | if (accept_ptr == NULL) {
|
---|
| 539 | /* connection has been aborted */
|
---|
| 540 | API_MSG_VAR_FREE_ACCEPT(msg);
|
---|
| 541 | return ERR_CLSD;
|
---|
| 542 | }
|
---|
| 543 | newconn = (struct netconn *)accept_ptr;
|
---|
| 544 | #if TCP_LISTEN_BACKLOG
|
---|
| 545 | /* Let the stack know that we have accepted the connection. */
|
---|
| 546 | API_MSG_VAR_REF(msg).conn = newconn;
|
---|
| 547 | /* don't care for the return value of lwip_netconn_do_recv */
|
---|
| 548 | netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg));
|
---|
| 549 | API_MSG_VAR_FREE(msg);
|
---|
| 550 | #endif /* TCP_LISTEN_BACKLOG */
|
---|
| 551 |
|
---|
| 552 | *new_conn = newconn;
|
---|
| 553 | /* don't set conn->last_err: it's only ERR_OK, anyway */
|
---|
| 554 | return ERR_OK;
|
---|
| 555 | #else /* LWIP_TCP */
|
---|
| 556 | LWIP_UNUSED_ARG(conn);
|
---|
| 557 | LWIP_UNUSED_ARG(new_conn);
|
---|
| 558 | return ERR_ARG;
|
---|
| 559 | #endif /* LWIP_TCP */
|
---|
| 560 | }
|
---|
| 561 |
|
---|
| 562 | /**
|
---|
| 563 | * @ingroup netconn_common
|
---|
| 564 | * Receive data: actual implementation that doesn't care whether pbuf or netbuf
|
---|
| 565 | * is received (this is internal, it's just here for describing common errors)
|
---|
| 566 | *
|
---|
| 567 | * @param conn the netconn from which to receive data
|
---|
| 568 | * @param new_buf pointer where a new pbuf/netbuf is stored when received data
|
---|
| 569 | * @param apiflags flags that control function behaviour. For now only:
|
---|
| 570 | * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
|
---|
| 571 | * @return ERR_OK if data has been received, an error code otherwise (timeout,
|
---|
| 572 | * memory error or another error)
|
---|
| 573 | * ERR_CONN if not connected
|
---|
| 574 | * ERR_CLSD if TCP connection has been closed
|
---|
| 575 | * ERR_WOULDBLOCK if the netconn is nonblocking but would block to wait for data
|
---|
| 576 | * ERR_TIMEOUT if the netconn has a receive timeout and no data was received
|
---|
| 577 | */
|
---|
| 578 | static err_t
|
---|
| 579 | netconn_recv_data(struct netconn *conn, void **new_buf, u8_t apiflags)
|
---|
| 580 | {
|
---|
| 581 | void *buf = NULL;
|
---|
| 582 | u16_t len;
|
---|
| 583 |
|
---|
| 584 | LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
|
---|
| 585 | *new_buf = NULL;
|
---|
| 586 | LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 587 |
|
---|
| 588 | if (!NETCONN_RECVMBOX_WAITABLE(conn)) {
|
---|
| 589 | err_t err = netconn_err(conn);
|
---|
| 590 | if (err != ERR_OK) {
|
---|
| 591 | /* return pending error */
|
---|
| 592 | return err;
|
---|
| 593 | }
|
---|
| 594 | return ERR_CONN;
|
---|
| 595 | }
|
---|
| 596 |
|
---|
| 597 | NETCONN_MBOX_WAITING_INC(conn);
|
---|
| 598 | if (netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK) ||
|
---|
| 599 | (conn->flags & NETCONN_FLAG_MBOXCLOSED) || (conn->pending_err != ERR_OK)) {
|
---|
| 600 | if (sys_arch_mbox_tryfetch(&conn->recvmbox, &buf) == SYS_ARCH_TIMEOUT) {
|
---|
| 601 | err_t err;
|
---|
| 602 | NETCONN_MBOX_WAITING_DEC(conn);
|
---|
| 603 | err = netconn_err(conn);
|
---|
| 604 | if (err != ERR_OK) {
|
---|
| 605 | /* return pending error */
|
---|
| 606 | return err;
|
---|
| 607 | }
|
---|
| 608 | if (conn->flags & NETCONN_FLAG_MBOXCLOSED) {
|
---|
| 609 | return ERR_CONN;
|
---|
| 610 | }
|
---|
| 611 | return ERR_WOULDBLOCK;
|
---|
| 612 | }
|
---|
| 613 | } else {
|
---|
| 614 | #if LWIP_SO_RCVTIMEO
|
---|
| 615 | if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
---|
| 616 | NETCONN_MBOX_WAITING_DEC(conn);
|
---|
| 617 | return ERR_TIMEOUT;
|
---|
| 618 | }
|
---|
| 619 | #else
|
---|
| 620 | sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
|
---|
| 621 | #endif /* LWIP_SO_RCVTIMEO*/
|
---|
| 622 | }
|
---|
| 623 | NETCONN_MBOX_WAITING_DEC(conn);
|
---|
| 624 | #if LWIP_NETCONN_FULLDUPLEX
|
---|
| 625 | if (conn->flags & NETCONN_FLAG_MBOXINVALID) {
|
---|
| 626 | if (lwip_netconn_is_deallocated_msg(buf)) {
|
---|
| 627 | /* the netconn has been closed from another thread */
|
---|
| 628 | API_MSG_VAR_FREE_ACCEPT(msg);
|
---|
| 629 | return ERR_CONN;
|
---|
| 630 | }
|
---|
| 631 | }
|
---|
| 632 | #endif
|
---|
| 633 |
|
---|
| 634 | #if LWIP_TCP
|
---|
| 635 | #if (LWIP_UDP || LWIP_RAW)
|
---|
| 636 | if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
|
---|
| 637 | #endif /* (LWIP_UDP || LWIP_RAW) */
|
---|
| 638 | {
|
---|
| 639 | err_t err;
|
---|
| 640 | /* Check if this is an error message or a pbuf */
|
---|
| 641 | if (lwip_netconn_is_err_msg(buf, &err)) {
|
---|
| 642 | /* new_buf has been zeroed above already */
|
---|
| 643 | if (err == ERR_CLSD) {
|
---|
| 644 | /* connection closed translates to ERR_OK with *new_buf == NULL */
|
---|
| 645 | return ERR_OK;
|
---|
| 646 | }
|
---|
| 647 | return err;
|
---|
| 648 | }
|
---|
| 649 | len = ((struct pbuf *)buf)->tot_len;
|
---|
| 650 | }
|
---|
| 651 | #endif /* LWIP_TCP */
|
---|
| 652 | #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
|
---|
| 653 | else
|
---|
| 654 | #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
|
---|
| 655 | #if (LWIP_UDP || LWIP_RAW)
|
---|
| 656 | {
|
---|
| 657 | LWIP_ASSERT("buf != NULL", buf != NULL);
|
---|
| 658 | len = netbuf_len((struct netbuf *)buf);
|
---|
| 659 | }
|
---|
| 660 | #endif /* (LWIP_UDP || LWIP_RAW) */
|
---|
| 661 |
|
---|
| 662 | #if LWIP_SO_RCVBUF
|
---|
| 663 | SYS_ARCH_DEC(conn->recv_avail, len);
|
---|
| 664 | #endif /* LWIP_SO_RCVBUF */
|
---|
| 665 | /* Register event with callback */
|
---|
| 666 | API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
|
---|
| 667 |
|
---|
| 668 | LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
|
---|
| 669 |
|
---|
| 670 | *new_buf = buf;
|
---|
| 671 | /* don't set conn->last_err: it's only ERR_OK, anyway */
|
---|
| 672 | return ERR_OK;
|
---|
| 673 | }
|
---|
| 674 |
|
---|
| 675 | #if LWIP_TCP
|
---|
| 676 | static err_t
|
---|
| 677 | netconn_tcp_recvd_msg(struct netconn *conn, size_t len, struct api_msg *msg)
|
---|
| 678 | {
|
---|
| 679 | LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
|
---|
| 680 | NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
|
---|
| 681 |
|
---|
| 682 | msg->conn = conn;
|
---|
| 683 | msg->msg.r.len = len;
|
---|
| 684 |
|
---|
| 685 | return netconn_apimsg(lwip_netconn_do_recv, msg);
|
---|
| 686 | }
|
---|
| 687 |
|
---|
| 688 | err_t
|
---|
| 689 | netconn_tcp_recvd(struct netconn *conn, size_t len)
|
---|
| 690 | {
|
---|
| 691 | err_t err;
|
---|
| 692 | API_MSG_VAR_DECLARE(msg);
|
---|
| 693 | LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
|
---|
| 694 | NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
|
---|
| 695 |
|
---|
| 696 | API_MSG_VAR_ALLOC(msg);
|
---|
| 697 | err = netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg));
|
---|
| 698 | API_MSG_VAR_FREE(msg);
|
---|
| 699 | return err;
|
---|
| 700 | }
|
---|
| 701 |
|
---|
| 702 | static err_t
|
---|
| 703 | netconn_recv_data_tcp(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags)
|
---|
| 704 | {
|
---|
| 705 | err_t err;
|
---|
| 706 | struct pbuf *buf;
|
---|
| 707 | API_MSG_VAR_DECLARE(msg);
|
---|
| 708 | #if LWIP_MPU_COMPATIBLE
|
---|
| 709 | msg = NULL;
|
---|
| 710 | #endif
|
---|
| 711 |
|
---|
| 712 | if (!NETCONN_RECVMBOX_WAITABLE(conn)) {
|
---|
| 713 | /* This only happens when calling this function more than once *after* receiving FIN */
|
---|
| 714 | return ERR_CONN;
|
---|
| 715 | }
|
---|
| 716 | if (netconn_is_flag_set(conn, NETCONN_FIN_RX_PENDING)) {
|
---|
| 717 | netconn_clear_flags(conn, NETCONN_FIN_RX_PENDING);
|
---|
| 718 | goto handle_fin;
|
---|
| 719 | }
|
---|
| 720 |
|
---|
| 721 | if (!(apiflags & NETCONN_NOAUTORCVD)) {
|
---|
| 722 | /* need to allocate API message here so empty message pool does not result in event loss
|
---|
| 723 | * see bug #47512: MPU_COMPATIBLE may fail on empty pool */
|
---|
| 724 | API_MSG_VAR_ALLOC(msg);
|
---|
| 725 | }
|
---|
| 726 |
|
---|
| 727 | err = netconn_recv_data(conn, (void **)new_buf, apiflags);
|
---|
| 728 | if (err != ERR_OK) {
|
---|
| 729 | if (!(apiflags & NETCONN_NOAUTORCVD)) {
|
---|
| 730 | API_MSG_VAR_FREE(msg);
|
---|
| 731 | }
|
---|
| 732 | return err;
|
---|
| 733 | }
|
---|
| 734 | buf = *new_buf;
|
---|
| 735 | if (!(apiflags & NETCONN_NOAUTORCVD)) {
|
---|
| 736 | /* Let the stack know that we have taken the data. */
|
---|
| 737 | u16_t len = buf ? buf->tot_len : 1;
|
---|
| 738 | /* don't care for the return value of lwip_netconn_do_recv */
|
---|
| 739 | /* @todo: this should really be fixed, e.g. by retrying in poll on error */
|
---|
| 740 | netconn_tcp_recvd_msg(conn, len, &API_VAR_REF(msg));
|
---|
| 741 | API_MSG_VAR_FREE(msg);
|
---|
| 742 | }
|
---|
| 743 |
|
---|
| 744 | /* If we are closed, we indicate that we no longer wish to use the socket */
|
---|
| 745 | if (buf == NULL) {
|
---|
| 746 | if (apiflags & NETCONN_NOFIN) {
|
---|
| 747 | /* received a FIN but the caller cannot handle it right now:
|
---|
| 748 | re-enqueue it and return "no data" */
|
---|
| 749 | netconn_set_flags(conn, NETCONN_FIN_RX_PENDING);
|
---|
| 750 | return ERR_WOULDBLOCK;
|
---|
| 751 | } else {
|
---|
| 752 | handle_fin:
|
---|
| 753 | API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
---|
| 754 | if (conn->pcb.ip == NULL) {
|
---|
| 755 | /* race condition: RST during recv */
|
---|
| 756 | err = netconn_err(conn);
|
---|
| 757 | if (err != ERR_OK) {
|
---|
| 758 | return err;
|
---|
| 759 | }
|
---|
| 760 | return ERR_RST;
|
---|
| 761 | }
|
---|
| 762 | /* RX side is closed, so deallocate the recvmbox */
|
---|
| 763 | netconn_close_shutdown(conn, NETCONN_SHUT_RD);
|
---|
| 764 | /* Don' store ERR_CLSD as conn->err since we are only half-closed */
|
---|
| 765 | return ERR_CLSD;
|
---|
| 766 | }
|
---|
| 767 | }
|
---|
| 768 | return err;
|
---|
| 769 | }
|
---|
| 770 |
|
---|
| 771 | /**
|
---|
| 772 | * @ingroup netconn_tcp
|
---|
| 773 | * Receive data (in form of a pbuf) from a TCP netconn
|
---|
| 774 | *
|
---|
| 775 | * @param conn the netconn from which to receive data
|
---|
| 776 | * @param new_buf pointer where a new pbuf is stored when received data
|
---|
| 777 | * @return ERR_OK if data has been received, an error code otherwise (timeout,
|
---|
| 778 | * memory error or another error, @see netconn_recv_data)
|
---|
| 779 | * ERR_ARG if conn is not a TCP netconn
|
---|
| 780 | */
|
---|
| 781 | err_t
|
---|
| 782 | netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
|
---|
| 783 | {
|
---|
| 784 | LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
|
---|
| 785 | NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
|
---|
| 786 |
|
---|
| 787 | return netconn_recv_data_tcp(conn, new_buf, 0);
|
---|
| 788 | }
|
---|
| 789 |
|
---|
| 790 | /**
|
---|
| 791 | * @ingroup netconn_tcp
|
---|
| 792 | * Receive data (in form of a pbuf) from a TCP netconn
|
---|
| 793 | *
|
---|
| 794 | * @param conn the netconn from which to receive data
|
---|
| 795 | * @param new_buf pointer where a new pbuf is stored when received data
|
---|
| 796 | * @param apiflags flags that control function behaviour. For now only:
|
---|
| 797 | * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
|
---|
| 798 | * @return ERR_OK if data has been received, an error code otherwise (timeout,
|
---|
| 799 | * memory error or another error, @see netconn_recv_data)
|
---|
| 800 | * ERR_ARG if conn is not a TCP netconn
|
---|
| 801 | */
|
---|
| 802 | err_t
|
---|
| 803 | netconn_recv_tcp_pbuf_flags(struct netconn *conn, struct pbuf **new_buf, u8_t apiflags)
|
---|
| 804 | {
|
---|
| 805 | LWIP_ERROR("netconn_recv_tcp_pbuf: invalid conn", (conn != NULL) &&
|
---|
| 806 | NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
|
---|
| 807 |
|
---|
| 808 | return netconn_recv_data_tcp(conn, new_buf, apiflags);
|
---|
| 809 | }
|
---|
| 810 | #endif /* LWIP_TCP */
|
---|
| 811 |
|
---|
| 812 | /**
|
---|
| 813 | * Receive data (in form of a netbuf) from a UDP or RAW netconn
|
---|
| 814 | *
|
---|
| 815 | * @param conn the netconn from which to receive data
|
---|
| 816 | * @param new_buf pointer where a new netbuf is stored when received data
|
---|
| 817 | * @return ERR_OK if data has been received, an error code otherwise (timeout,
|
---|
| 818 | * memory error or another error)
|
---|
| 819 | * ERR_ARG if conn is not a UDP/RAW netconn
|
---|
| 820 | */
|
---|
| 821 | err_t
|
---|
| 822 | netconn_recv_udp_raw_netbuf(struct netconn *conn, struct netbuf **new_buf)
|
---|
| 823 | {
|
---|
| 824 | LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) &&
|
---|
| 825 | NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;);
|
---|
| 826 |
|
---|
| 827 | return netconn_recv_data(conn, (void **)new_buf, 0);
|
---|
| 828 | }
|
---|
| 829 |
|
---|
| 830 | /**
|
---|
| 831 | * Receive data (in form of a netbuf) from a UDP or RAW netconn
|
---|
| 832 | *
|
---|
| 833 | * @param conn the netconn from which to receive data
|
---|
| 834 | * @param new_buf pointer where a new netbuf is stored when received data
|
---|
| 835 | * @param apiflags flags that control function behaviour. For now only:
|
---|
| 836 | * - NETCONN_DONTBLOCK: only read data that is available now, don't wait for more data
|
---|
| 837 | * @return ERR_OK if data has been received, an error code otherwise (timeout,
|
---|
| 838 | * memory error or another error)
|
---|
| 839 | * ERR_ARG if conn is not a UDP/RAW netconn
|
---|
| 840 | */
|
---|
| 841 | err_t
|
---|
| 842 | netconn_recv_udp_raw_netbuf_flags(struct netconn *conn, struct netbuf **new_buf, u8_t apiflags)
|
---|
| 843 | {
|
---|
| 844 | LWIP_ERROR("netconn_recv_udp_raw_netbuf: invalid conn", (conn != NULL) &&
|
---|
| 845 | NETCONNTYPE_GROUP(netconn_type(conn)) != NETCONN_TCP, return ERR_ARG;);
|
---|
| 846 |
|
---|
| 847 | return netconn_recv_data(conn, (void **)new_buf, apiflags);
|
---|
| 848 | }
|
---|
| 849 |
|
---|
| 850 | /**
|
---|
| 851 | * @ingroup netconn_common
|
---|
| 852 | * Receive data (in form of a netbuf containing a packet buffer) from a netconn
|
---|
| 853 | *
|
---|
| 854 | * @param conn the netconn from which to receive data
|
---|
| 855 | * @param new_buf pointer where a new netbuf is stored when received data
|
---|
| 856 | * @return ERR_OK if data has been received, an error code otherwise (timeout,
|
---|
| 857 | * memory error or another error)
|
---|
| 858 | */
|
---|
| 859 | err_t
|
---|
| 860 | netconn_recv(struct netconn *conn, struct netbuf **new_buf)
|
---|
| 861 | {
|
---|
| 862 | #if LWIP_TCP
|
---|
| 863 | struct netbuf *buf = NULL;
|
---|
| 864 | err_t err;
|
---|
| 865 | #endif /* LWIP_TCP */
|
---|
| 866 |
|
---|
| 867 | LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
|
---|
| 868 | *new_buf = NULL;
|
---|
| 869 | LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 870 |
|
---|
| 871 | #if LWIP_TCP
|
---|
| 872 | #if (LWIP_UDP || LWIP_RAW)
|
---|
| 873 | if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
|
---|
| 874 | #endif /* (LWIP_UDP || LWIP_RAW) */
|
---|
| 875 | {
|
---|
| 876 | struct pbuf *p = NULL;
|
---|
| 877 | /* This is not a listening netconn, since recvmbox is set */
|
---|
| 878 |
|
---|
| 879 | buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
|
---|
| 880 | if (buf == NULL) {
|
---|
| 881 | return ERR_MEM;
|
---|
| 882 | }
|
---|
| 883 |
|
---|
| 884 | err = netconn_recv_data_tcp(conn, &p, 0);
|
---|
| 885 | if (err != ERR_OK) {
|
---|
| 886 | memp_free(MEMP_NETBUF, buf);
|
---|
| 887 | return err;
|
---|
| 888 | }
|
---|
| 889 | LWIP_ASSERT("p != NULL", p != NULL);
|
---|
| 890 |
|
---|
| 891 | buf->p = p;
|
---|
| 892 | buf->ptr = p;
|
---|
| 893 | buf->port = 0;
|
---|
| 894 | ip_addr_set_zero(&buf->addr);
|
---|
| 895 | *new_buf = buf;
|
---|
| 896 | /* don't set conn->last_err: it's only ERR_OK, anyway */
|
---|
| 897 | return ERR_OK;
|
---|
| 898 | }
|
---|
| 899 | #endif /* LWIP_TCP */
|
---|
| 900 | #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
|
---|
| 901 | else
|
---|
| 902 | #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
|
---|
| 903 | {
|
---|
| 904 | #if (LWIP_UDP || LWIP_RAW)
|
---|
| 905 | return netconn_recv_data(conn, (void **)new_buf, 0);
|
---|
| 906 | #endif /* (LWIP_UDP || LWIP_RAW) */
|
---|
| 907 | }
|
---|
| 908 | }
|
---|
| 909 |
|
---|
| 910 | /**
|
---|
| 911 | * @ingroup netconn_udp
|
---|
| 912 | * Send data (in form of a netbuf) to a specific remote IP address and port.
|
---|
| 913 | * Only to be used for UDP and RAW netconns (not TCP).
|
---|
| 914 | *
|
---|
| 915 | * @param conn the netconn over which to send data
|
---|
| 916 | * @param buf a netbuf containing the data to send
|
---|
| 917 | * @param addr the remote IP address to which to send the data
|
---|
| 918 | * @param port the remote port to which to send the data
|
---|
| 919 | * @return ERR_OK if data was sent, any other err_t on error
|
---|
| 920 | */
|
---|
| 921 | err_t
|
---|
| 922 | netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
|
---|
| 923 | {
|
---|
| 924 | if (buf != NULL) {
|
---|
| 925 | ip_addr_set(&buf->addr, addr);
|
---|
| 926 | buf->port = port;
|
---|
| 927 | return netconn_send(conn, buf);
|
---|
| 928 | }
|
---|
| 929 | return ERR_VAL;
|
---|
| 930 | }
|
---|
| 931 |
|
---|
| 932 | /**
|
---|
| 933 | * @ingroup netconn_udp
|
---|
| 934 | * Send data over a UDP or RAW netconn (that is already connected).
|
---|
| 935 | *
|
---|
| 936 | * @param conn the UDP or RAW netconn over which to send data
|
---|
| 937 | * @param buf a netbuf containing the data to send
|
---|
| 938 | * @return ERR_OK if data was sent, any other err_t on error
|
---|
| 939 | */
|
---|
| 940 | err_t
|
---|
| 941 | netconn_send(struct netconn *conn, struct netbuf *buf)
|
---|
| 942 | {
|
---|
| 943 | API_MSG_VAR_DECLARE(msg);
|
---|
| 944 | err_t err;
|
---|
| 945 |
|
---|
| 946 | LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 947 |
|
---|
| 948 | LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
|
---|
| 949 |
|
---|
| 950 | API_MSG_VAR_ALLOC(msg);
|
---|
| 951 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 952 | API_MSG_VAR_REF(msg).msg.b = buf;
|
---|
| 953 | err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg));
|
---|
| 954 | API_MSG_VAR_FREE(msg);
|
---|
| 955 |
|
---|
| 956 | return err;
|
---|
| 957 | }
|
---|
| 958 |
|
---|
| 959 | /**
|
---|
| 960 | * @ingroup netconn_tcp
|
---|
| 961 | * Send data over a TCP netconn.
|
---|
| 962 | *
|
---|
| 963 | * @param conn the TCP netconn over which to send data
|
---|
| 964 | * @param dataptr pointer to the application buffer that contains the data to send
|
---|
| 965 | * @param size size of the application data to send
|
---|
| 966 | * @param apiflags combination of following flags :
|
---|
| 967 | * - NETCONN_COPY: data will be copied into memory belonging to the stack
|
---|
| 968 | * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
|
---|
| 969 | * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
|
---|
| 970 | * @param bytes_written pointer to a location that receives the number of written bytes
|
---|
| 971 | * @return ERR_OK if data was sent, any other err_t on error
|
---|
| 972 | */
|
---|
| 973 | err_t
|
---|
| 974 | netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
|
---|
| 975 | u8_t apiflags, size_t *bytes_written)
|
---|
| 976 | {
|
---|
| 977 | struct netvector vector;
|
---|
| 978 | vector.ptr = dataptr;
|
---|
| 979 | vector.len = size;
|
---|
| 980 | return netconn_write_vectors_partly(conn, &vector, 1, apiflags, bytes_written);
|
---|
| 981 | }
|
---|
| 982 |
|
---|
| 983 | /**
|
---|
| 984 | * Send vectorized data atomically over a TCP netconn.
|
---|
| 985 | *
|
---|
| 986 | * @param conn the TCP netconn over which to send data
|
---|
| 987 | * @param vectors array of vectors containing data to send
|
---|
| 988 | * @param vectorcnt number of vectors in the array
|
---|
| 989 | * @param apiflags combination of following flags :
|
---|
| 990 | * - NETCONN_COPY: data will be copied into memory belonging to the stack
|
---|
| 991 | * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
|
---|
| 992 | * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
|
---|
| 993 | * @param bytes_written pointer to a location that receives the number of written bytes
|
---|
| 994 | * @return ERR_OK if data was sent, any other err_t on error
|
---|
| 995 | */
|
---|
| 996 | err_t
|
---|
| 997 | netconn_write_vectors_partly(struct netconn *conn, struct netvector *vectors, u16_t vectorcnt,
|
---|
| 998 | u8_t apiflags, size_t *bytes_written)
|
---|
| 999 | {
|
---|
| 1000 | API_MSG_VAR_DECLARE(msg);
|
---|
| 1001 | err_t err;
|
---|
| 1002 | u8_t dontblock;
|
---|
| 1003 | size_t size;
|
---|
| 1004 | int i;
|
---|
| 1005 |
|
---|
| 1006 | LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 1007 | LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP), return ERR_VAL;);
|
---|
| 1008 | dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
|
---|
| 1009 | #if LWIP_SO_SNDTIMEO
|
---|
| 1010 | if (conn->send_timeout != 0) {
|
---|
| 1011 | dontblock = 1;
|
---|
| 1012 | }
|
---|
| 1013 | #endif /* LWIP_SO_SNDTIMEO */
|
---|
| 1014 | if (dontblock && !bytes_written) {
|
---|
| 1015 | /* This implies netconn_write() cannot be used for non-blocking send, since
|
---|
| 1016 | it has no way to return the number of bytes written. */
|
---|
| 1017 | return ERR_VAL;
|
---|
| 1018 | }
|
---|
| 1019 |
|
---|
| 1020 | /* sum up the total size */
|
---|
| 1021 | size = 0;
|
---|
| 1022 | for (i = 0; i < vectorcnt; i++) {
|
---|
| 1023 | size += vectors[i].len;
|
---|
| 1024 | if (size < vectors[i].len) {
|
---|
| 1025 | /* overflow */
|
---|
| 1026 | return ERR_VAL;
|
---|
| 1027 | }
|
---|
| 1028 | }
|
---|
| 1029 | if (size == 0) {
|
---|
| 1030 | return ERR_OK;
|
---|
| 1031 | } else if (size > SSIZE_MAX) {
|
---|
| 1032 | ssize_t limited;
|
---|
| 1033 | /* this is required by the socket layer (cannot send full size_t range) */
|
---|
| 1034 | if (!bytes_written) {
|
---|
| 1035 | return ERR_VAL;
|
---|
| 1036 | }
|
---|
| 1037 | /* limit the amount of data to send */
|
---|
| 1038 | limited = SSIZE_MAX;
|
---|
| 1039 | size = (size_t)limited;
|
---|
| 1040 | }
|
---|
| 1041 |
|
---|
| 1042 | API_MSG_VAR_ALLOC(msg);
|
---|
| 1043 | /* non-blocking write sends as much */
|
---|
| 1044 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 1045 | API_MSG_VAR_REF(msg).msg.w.vector = vectors;
|
---|
| 1046 | API_MSG_VAR_REF(msg).msg.w.vector_cnt = vectorcnt;
|
---|
| 1047 | API_MSG_VAR_REF(msg).msg.w.vector_off = 0;
|
---|
| 1048 | API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags;
|
---|
| 1049 | API_MSG_VAR_REF(msg).msg.w.len = size;
|
---|
| 1050 | API_MSG_VAR_REF(msg).msg.w.offset = 0;
|
---|
| 1051 | #if LWIP_SO_SNDTIMEO
|
---|
| 1052 | if (conn->send_timeout != 0) {
|
---|
| 1053 | /* get the time we started, which is later compared to
|
---|
| 1054 | sys_now() + conn->send_timeout */
|
---|
| 1055 | API_MSG_VAR_REF(msg).msg.w.time_started = sys_now();
|
---|
| 1056 | } else {
|
---|
| 1057 | API_MSG_VAR_REF(msg).msg.w.time_started = 0;
|
---|
| 1058 | }
|
---|
| 1059 | #endif /* LWIP_SO_SNDTIMEO */
|
---|
| 1060 |
|
---|
| 1061 | /* For locking the core: this _can_ be delayed on low memory/low send buffer,
|
---|
| 1062 | but if it is, this is done inside api_msg.c:do_write(), so we can use the
|
---|
| 1063 | non-blocking version here. */
|
---|
| 1064 | err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
|
---|
| 1065 | if (err == ERR_OK) {
|
---|
| 1066 | if (bytes_written != NULL) {
|
---|
| 1067 | *bytes_written = API_MSG_VAR_REF(msg).msg.w.offset;
|
---|
| 1068 | }
|
---|
| 1069 | /* for blocking, check all requested bytes were written, NOTE: send_timeout is
|
---|
| 1070 | treated as dontblock (see dontblock assignment above) */
|
---|
| 1071 | if (!dontblock) {
|
---|
| 1072 | LWIP_ASSERT("do_write failed to write all bytes", API_MSG_VAR_REF(msg).msg.w.offset == size);
|
---|
| 1073 | }
|
---|
| 1074 | }
|
---|
| 1075 | API_MSG_VAR_FREE(msg);
|
---|
| 1076 |
|
---|
| 1077 | return err;
|
---|
| 1078 | }
|
---|
| 1079 |
|
---|
| 1080 | /**
|
---|
| 1081 | * @ingroup netconn_tcp
|
---|
| 1082 | * Close or shutdown a TCP netconn (doesn't delete it).
|
---|
| 1083 | *
|
---|
| 1084 | * @param conn the TCP netconn to close or shutdown
|
---|
| 1085 | * @param how fully close or only shutdown one side?
|
---|
| 1086 | * @return ERR_OK if the netconn was closed, any other err_t on error
|
---|
| 1087 | */
|
---|
| 1088 | static err_t
|
---|
| 1089 | netconn_close_shutdown(struct netconn *conn, u8_t how)
|
---|
| 1090 | {
|
---|
| 1091 | API_MSG_VAR_DECLARE(msg);
|
---|
| 1092 | err_t err;
|
---|
| 1093 | LWIP_UNUSED_ARG(how);
|
---|
| 1094 |
|
---|
| 1095 | LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 1096 |
|
---|
| 1097 | API_MSG_VAR_ALLOC(msg);
|
---|
| 1098 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 1099 | #if LWIP_TCP
|
---|
| 1100 | /* shutting down both ends is the same as closing */
|
---|
| 1101 | API_MSG_VAR_REF(msg).msg.sd.shut = how;
|
---|
| 1102 | #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
|
---|
| 1103 | /* get the time we started, which is later compared to
|
---|
| 1104 | sys_now() + conn->send_timeout */
|
---|
| 1105 | API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
|
---|
| 1106 | #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
---|
| 1107 | API_MSG_VAR_REF(msg).msg.sd.polls_left =
|
---|
| 1108 | ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
|
---|
| 1109 | #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
|
---|
| 1110 | #endif /* LWIP_TCP */
|
---|
| 1111 | err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg));
|
---|
| 1112 | API_MSG_VAR_FREE(msg);
|
---|
| 1113 |
|
---|
| 1114 | return err;
|
---|
| 1115 | }
|
---|
| 1116 |
|
---|
| 1117 | /**
|
---|
| 1118 | * @ingroup netconn_tcp
|
---|
| 1119 | * Close a TCP netconn (doesn't delete it).
|
---|
| 1120 | *
|
---|
| 1121 | * @param conn the TCP netconn to close
|
---|
| 1122 | * @return ERR_OK if the netconn was closed, any other err_t on error
|
---|
| 1123 | */
|
---|
| 1124 | err_t
|
---|
| 1125 | netconn_close(struct netconn *conn)
|
---|
| 1126 | {
|
---|
| 1127 | /* shutting down both ends is the same as closing */
|
---|
| 1128 | return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
|
---|
| 1129 | }
|
---|
| 1130 |
|
---|
| 1131 | /**
|
---|
| 1132 | * @ingroup netconn_common
|
---|
| 1133 | * Get and reset pending error on a netconn
|
---|
| 1134 | *
|
---|
| 1135 | * @param conn the netconn to get the error from
|
---|
| 1136 | * @return and pending error or ERR_OK if no error was pending
|
---|
| 1137 | */
|
---|
| 1138 | err_t
|
---|
| 1139 | netconn_err(struct netconn *conn)
|
---|
| 1140 | {
|
---|
| 1141 | err_t err;
|
---|
| 1142 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 1143 | if (conn == NULL) {
|
---|
| 1144 | return ERR_OK;
|
---|
| 1145 | }
|
---|
| 1146 | SYS_ARCH_PROTECT(lev);
|
---|
| 1147 | err = conn->pending_err;
|
---|
| 1148 | conn->pending_err = ERR_OK;
|
---|
| 1149 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 1150 | return err;
|
---|
| 1151 | }
|
---|
| 1152 |
|
---|
| 1153 | /**
|
---|
| 1154 | * @ingroup netconn_tcp
|
---|
| 1155 | * Shut down one or both sides of a TCP netconn (doesn't delete it).
|
---|
| 1156 | *
|
---|
| 1157 | * @param conn the TCP netconn to shut down
|
---|
| 1158 | * @param shut_rx shut down the RX side (no more read possible after this)
|
---|
| 1159 | * @param shut_tx shut down the TX side (no more write possible after this)
|
---|
| 1160 | * @return ERR_OK if the netconn was closed, any other err_t on error
|
---|
| 1161 | */
|
---|
| 1162 | err_t
|
---|
| 1163 | netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
|
---|
| 1164 | {
|
---|
| 1165 | return netconn_close_shutdown(conn, (u8_t)((shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)));
|
---|
| 1166 | }
|
---|
| 1167 |
|
---|
| 1168 | #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
|
---|
| 1169 | /**
|
---|
| 1170 | * @ingroup netconn_udp
|
---|
| 1171 | * Join multicast groups for UDP netconns.
|
---|
| 1172 | *
|
---|
| 1173 | * @param conn the UDP netconn for which to change multicast addresses
|
---|
| 1174 | * @param multiaddr IP address of the multicast group to join or leave
|
---|
| 1175 | * @param netif_addr the IP address of the network interface on which to send
|
---|
| 1176 | * the igmp message
|
---|
| 1177 | * @param join_or_leave flag whether to send a join- or leave-message
|
---|
| 1178 | * @return ERR_OK if the action was taken, any err_t on error
|
---|
| 1179 | */
|
---|
| 1180 | err_t
|
---|
| 1181 | netconn_join_leave_group(struct netconn *conn,
|
---|
| 1182 | const ip_addr_t *multiaddr,
|
---|
| 1183 | const ip_addr_t *netif_addr,
|
---|
| 1184 | enum netconn_igmp join_or_leave)
|
---|
| 1185 | {
|
---|
| 1186 | API_MSG_VAR_DECLARE(msg);
|
---|
| 1187 | err_t err;
|
---|
| 1188 |
|
---|
| 1189 | LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 1190 |
|
---|
| 1191 | API_MSG_VAR_ALLOC(msg);
|
---|
| 1192 |
|
---|
| 1193 | #if LWIP_IPV4
|
---|
| 1194 | /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
|
---|
| 1195 | if (multiaddr == NULL) {
|
---|
| 1196 | multiaddr = IP4_ADDR_ANY;
|
---|
| 1197 | }
|
---|
| 1198 | if (netif_addr == NULL) {
|
---|
| 1199 | netif_addr = IP4_ADDR_ANY;
|
---|
| 1200 | }
|
---|
| 1201 | #endif /* LWIP_IPV4 */
|
---|
| 1202 |
|
---|
| 1203 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 1204 | API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
|
---|
| 1205 | API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr);
|
---|
| 1206 | API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
|
---|
| 1207 | err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg));
|
---|
| 1208 | API_MSG_VAR_FREE(msg);
|
---|
| 1209 |
|
---|
| 1210 | return err;
|
---|
| 1211 | }
|
---|
| 1212 | /**
|
---|
| 1213 | * @ingroup netconn_udp
|
---|
| 1214 | * Join multicast groups for UDP netconns.
|
---|
| 1215 | *
|
---|
| 1216 | * @param conn the UDP netconn for which to change multicast addresses
|
---|
| 1217 | * @param multiaddr IP address of the multicast group to join or leave
|
---|
| 1218 | * @param if_idx the index of the netif
|
---|
| 1219 | * @param join_or_leave flag whether to send a join- or leave-message
|
---|
| 1220 | * @return ERR_OK if the action was taken, any err_t on error
|
---|
| 1221 | */
|
---|
| 1222 | err_t
|
---|
| 1223 | netconn_join_leave_group_netif(struct netconn *conn,
|
---|
| 1224 | const ip_addr_t *multiaddr,
|
---|
| 1225 | u8_t if_idx,
|
---|
| 1226 | enum netconn_igmp join_or_leave)
|
---|
| 1227 | {
|
---|
| 1228 | API_MSG_VAR_DECLARE(msg);
|
---|
| 1229 | err_t err;
|
---|
| 1230 |
|
---|
| 1231 | LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
|
---|
| 1232 |
|
---|
| 1233 | API_MSG_VAR_ALLOC(msg);
|
---|
| 1234 |
|
---|
| 1235 | #if LWIP_IPV4
|
---|
| 1236 | /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
|
---|
| 1237 | if (multiaddr == NULL) {
|
---|
| 1238 | multiaddr = IP4_ADDR_ANY;
|
---|
| 1239 | }
|
---|
| 1240 | if (if_idx == NETIF_NO_INDEX) {
|
---|
| 1241 | return ERR_IF;
|
---|
| 1242 | }
|
---|
| 1243 | #endif /* LWIP_IPV4 */
|
---|
| 1244 |
|
---|
| 1245 | API_MSG_VAR_REF(msg).conn = conn;
|
---|
| 1246 | API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
|
---|
| 1247 | API_MSG_VAR_REF(msg).msg.jl.if_idx = if_idx;
|
---|
| 1248 | API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
|
---|
| 1249 | err = netconn_apimsg(lwip_netconn_do_join_leave_group_netif, &API_MSG_VAR_REF(msg));
|
---|
| 1250 | API_MSG_VAR_FREE(msg);
|
---|
| 1251 |
|
---|
| 1252 | return err;
|
---|
| 1253 | }
|
---|
| 1254 | #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
|
---|
| 1255 |
|
---|
| 1256 | #if LWIP_DNS
|
---|
| 1257 | /**
|
---|
| 1258 | * @ingroup netconn_common
|
---|
| 1259 | * Execute a DNS query, only one IP address is returned
|
---|
| 1260 | *
|
---|
| 1261 | * @param name a string representation of the DNS host name to query
|
---|
| 1262 | * @param addr a preallocated ip_addr_t where to store the resolved IP address
|
---|
| 1263 | * @param dns_addrtype IP address type (IPv4 / IPv6)
|
---|
| 1264 | * @return ERR_OK: resolving succeeded
|
---|
| 1265 | * ERR_MEM: memory error, try again later
|
---|
| 1266 | * ERR_ARG: dns client not initialized or invalid hostname
|
---|
| 1267 | * ERR_VAL: dns server response was invalid
|
---|
| 1268 | */
|
---|
| 1269 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 1270 | err_t
|
---|
| 1271 | netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype)
|
---|
| 1272 | #else
|
---|
| 1273 | err_t
|
---|
| 1274 | netconn_gethostbyname(const char *name, ip_addr_t *addr)
|
---|
| 1275 | #endif
|
---|
| 1276 | {
|
---|
| 1277 | API_VAR_DECLARE(struct dns_api_msg, msg);
|
---|
| 1278 | #if !LWIP_MPU_COMPATIBLE
|
---|
| 1279 | sys_sem_t sem;
|
---|
| 1280 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 1281 | err_t err;
|
---|
| 1282 | err_t cberr;
|
---|
| 1283 |
|
---|
| 1284 | LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
|
---|
| 1285 | LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
|
---|
| 1286 | #if LWIP_MPU_COMPATIBLE
|
---|
| 1287 | if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
|
---|
| 1288 | return ERR_ARG;
|
---|
| 1289 | }
|
---|
| 1290 | #endif
|
---|
| 1291 |
|
---|
| 1292 | #ifdef LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE
|
---|
| 1293 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 1294 | if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, dns_addrtype, &err)) {
|
---|
| 1295 | #else
|
---|
| 1296 | if (LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE(name, addr, NETCONN_DNS_DEFAULT, &err)) {
|
---|
| 1297 | #endif /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 1298 | return err;
|
---|
| 1299 | }
|
---|
| 1300 | #endif /* LWIP_HOOK_NETCONN_EXTERNAL_RESOLVE */
|
---|
| 1301 |
|
---|
| 1302 | API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
|
---|
| 1303 | #if LWIP_MPU_COMPATIBLE
|
---|
| 1304 | strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH - 1);
|
---|
| 1305 | API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH - 1] = 0;
|
---|
| 1306 | #else /* LWIP_MPU_COMPATIBLE */
|
---|
| 1307 | msg.err = &err;
|
---|
| 1308 | msg.sem = &sem;
|
---|
| 1309 | API_VAR_REF(msg).addr = API_VAR_REF(addr);
|
---|
| 1310 | API_VAR_REF(msg).name = name;
|
---|
| 1311 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 1312 | #if LWIP_IPV4 && LWIP_IPV6
|
---|
| 1313 | API_VAR_REF(msg).dns_addrtype = dns_addrtype;
|
---|
| 1314 | #endif /* LWIP_IPV4 && LWIP_IPV6 */
|
---|
| 1315 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 1316 | API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
|
---|
| 1317 | #else /* LWIP_NETCONN_SEM_PER_THREAD*/
|
---|
| 1318 | err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
|
---|
| 1319 | if (err != ERR_OK) {
|
---|
| 1320 | API_VAR_FREE(MEMP_DNS_API_MSG, msg);
|
---|
| 1321 | return err;
|
---|
| 1322 | }
|
---|
| 1323 | #endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 1324 |
|
---|
| 1325 | cberr = tcpip_send_msg_wait_sem(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg), API_EXPR_REF(API_VAR_REF(msg).sem));
|
---|
| 1326 | #if !LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 1327 | sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
|
---|
| 1328 | #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 1329 | if (cberr != ERR_OK) {
|
---|
| 1330 | API_VAR_FREE(MEMP_DNS_API_MSG, msg);
|
---|
| 1331 | return cberr;
|
---|
| 1332 | }
|
---|
| 1333 |
|
---|
| 1334 | #if LWIP_MPU_COMPATIBLE
|
---|
| 1335 | *addr = msg->addr;
|
---|
| 1336 | err = msg->err;
|
---|
| 1337 | #endif /* LWIP_MPU_COMPATIBLE */
|
---|
| 1338 |
|
---|
| 1339 | API_VAR_FREE(MEMP_DNS_API_MSG, msg);
|
---|
| 1340 | return err;
|
---|
| 1341 | }
|
---|
| 1342 | #endif /* LWIP_DNS*/
|
---|
| 1343 |
|
---|
| 1344 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 1345 | void
|
---|
| 1346 | netconn_thread_init(void)
|
---|
| 1347 | {
|
---|
| 1348 | sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
|
---|
| 1349 | if ((sem == NULL) || !sys_sem_valid(sem)) {
|
---|
| 1350 | /* call alloc only once */
|
---|
| 1351 | LWIP_NETCONN_THREAD_SEM_ALLOC();
|
---|
| 1352 | LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET()));
|
---|
| 1353 | }
|
---|
| 1354 | }
|
---|
| 1355 |
|
---|
| 1356 | void
|
---|
| 1357 | netconn_thread_cleanup(void)
|
---|
| 1358 | {
|
---|
| 1359 | sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
|
---|
| 1360 | if ((sem != NULL) && sys_sem_valid(sem)) {
|
---|
| 1361 | /* call free only once */
|
---|
| 1362 | LWIP_NETCONN_THREAD_SEM_FREE();
|
---|
| 1363 | }
|
---|
| 1364 | }
|
---|
| 1365 | #endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 1366 |
|
---|
| 1367 | #endif /* LWIP_NETCONN */
|
---|