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