xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.1.0/src/api/api_lib.c (revision 104654410c56c573564690304ae786df310c91fc)
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