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