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