1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2013-2019 Damien P. George
7  * Copyright (c) 2015 Galen Hazelwood
8  * Copyright (c) 2015-2017 Paul Sokolovsky
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy
11  * of this software and associated documentation files (the "Software"), to deal
12  * in the Software without restriction, including without limitation the rights
13  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  * copies of the Software, and to permit persons to whom the Software is
15  * furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  * THE SOFTWARE.
27  */
28 
29 #include <string.h>
30 #include <stdio.h>
31 
32 #include "py/objlist.h"
33 #include "py/runtime.h"
34 #include "py/stream.h"
35 #include "py/mperrno.h"
36 #include "py/mphal.h"
37 
38 #include "shared/netutils/netutils.h"
39 
40 #include "lwip/init.h"
41 #include "lwip/tcp.h"
42 #include "lwip/udp.h"
43 #include "lwip/raw.h"
44 #include "lwip/dns.h"
45 #include "lwip/igmp.h"
46 #if LWIP_VERSION_MAJOR < 2
47 #include "lwip/timers.h"
48 #include "lwip/tcp_impl.h"
49 #else
50 #include "lwip/timeouts.h"
51 #include "lwip/priv/tcp_priv.h"
52 #endif
53 
54 #if 0 // print debugging info
55 #define DEBUG_printf DEBUG_printf
56 #else // don't print debugging info
57 #define DEBUG_printf(...) (void)0
58 #endif
59 
60 // Timeout between closing a TCP socket and doing a tcp_abort on that
61 // socket, if the connection isn't closed cleanly in that time.
62 #define MICROPY_PY_LWIP_TCP_CLOSE_TIMEOUT_MS (10000)
63 
64 // All socket options should be globally distinct,
65 // because we ignore option levels for efficiency.
66 #define IP_ADD_MEMBERSHIP 0x400
67 
68 // For compatibilily with older lwIP versions.
69 #ifndef ip_set_option
70 #define ip_set_option(pcb, opt)   ((pcb)->so_options |= (opt))
71 #endif
72 #ifndef ip_reset_option
73 #define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt))
74 #endif
75 
76 // A port can define these hooks to provide concurrency protection
77 #ifndef MICROPY_PY_LWIP_ENTER
78 #define MICROPY_PY_LWIP_ENTER
79 #define MICROPY_PY_LWIP_REENTER
80 #define MICROPY_PY_LWIP_EXIT
81 #endif
82 
83 #ifdef MICROPY_PY_LWIP_SLIP
84 #include "netif/slipif.h"
85 #include "lwip/sio.h"
86 #endif
87 
88 #ifdef MICROPY_PY_LWIP_SLIP
89 /******************************************************************************/
90 // Slip object for modlwip. Requires a serial driver for the port that supports
91 // the lwip serial callback functions.
92 
93 typedef struct _lwip_slip_obj_t {
94     mp_obj_base_t base;
95     struct netif lwip_netif;
96 } lwip_slip_obj_t;
97 
98 // Slip object is unique for now. Possibly can fix this later. FIXME
99 STATIC lwip_slip_obj_t lwip_slip_obj;
100 
101 // Declare these early.
102 void mod_lwip_register_poll(void (*poll)(void *arg), void *poll_arg);
103 void mod_lwip_deregister_poll(void (*poll)(void *arg), void *poll_arg);
104 
slip_lwip_poll(void * netif)105 STATIC void slip_lwip_poll(void *netif) {
106     slipif_poll((struct netif *)netif);
107 }
108 
109 STATIC const mp_obj_type_t lwip_slip_type;
110 
111 // lwIP SLIP callback functions
sio_open(u8_t dvnum)112 sio_fd_t sio_open(u8_t dvnum) {
113     // We support singleton SLIP interface, so just return any truish value.
114     return (sio_fd_t)1;
115 }
116 
sio_send(u8_t c,sio_fd_t fd)117 void sio_send(u8_t c, sio_fd_t fd) {
118     mp_obj_type_t *type = mp_obj_get_type(MP_STATE_VM(lwip_slip_stream));
119     int error;
120     type->stream_p->write(MP_STATE_VM(lwip_slip_stream), &c, 1, &error);
121 }
122 
sio_tryread(sio_fd_t fd,u8_t * data,u32_t len)123 u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len) {
124     mp_obj_type_t *type = mp_obj_get_type(MP_STATE_VM(lwip_slip_stream));
125     int error;
126     mp_uint_t out_sz = type->stream_p->read(MP_STATE_VM(lwip_slip_stream), data, len, &error);
127     if (out_sz == MP_STREAM_ERROR) {
128         if (mp_is_nonblocking_error(error)) {
129             return 0;
130         }
131         // Can't do much else, can we?
132         return 0;
133     }
134     return out_sz;
135 }
136 
137 // constructor lwip.slip(device=integer, iplocal=string, ipremote=string)
lwip_slip_make_new(mp_obj_t type_in,size_t n_args,size_t n_kw,const mp_obj_t * args)138 STATIC mp_obj_t lwip_slip_make_new(mp_obj_t type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
139     mp_arg_check_num(n_args, n_kw, 3, 3, false);
140 
141     lwip_slip_obj.base.type = &lwip_slip_type;
142 
143     MP_STATE_VM(lwip_slip_stream) = args[0];
144 
145     ip_addr_t iplocal, ipremote;
146     if (!ipaddr_aton(mp_obj_str_get_str(args[1]), &iplocal)) {
147         mp_raise_ValueError(MP_ERROR_TEXT("not a valid local IP"));
148     }
149     if (!ipaddr_aton(mp_obj_str_get_str(args[2]), &ipremote)) {
150         mp_raise_ValueError(MP_ERROR_TEXT("not a valid remote IP"));
151     }
152 
153     struct netif *n = &lwip_slip_obj.lwip_netif;
154     if (netif_add(n, &iplocal, IP_ADDR_BROADCAST, &ipremote, NULL, slipif_init, ip_input) == NULL) {
155         mp_raise_ValueError(MP_ERROR_TEXT("out of memory"));
156     }
157     netif_set_up(n);
158     netif_set_default(n);
159     mod_lwip_register_poll(slip_lwip_poll, n);
160 
161     return (mp_obj_t)&lwip_slip_obj;
162 }
163 
lwip_slip_status(mp_obj_t self_in)164 STATIC mp_obj_t lwip_slip_status(mp_obj_t self_in) {
165     // Null function for now.
166     return mp_const_none;
167 }
168 
169 STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_slip_status_obj, lwip_slip_status);
170 
171 STATIC const mp_rom_map_elem_t lwip_slip_locals_dict_table[] = {
172     { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&lwip_slip_status_obj) },
173 };
174 
175 STATIC MP_DEFINE_CONST_DICT(lwip_slip_locals_dict, lwip_slip_locals_dict_table);
176 
177 STATIC const mp_obj_type_t lwip_slip_type = {
178     { &mp_type_type },
179     .name = MP_QSTR_slip,
180     .make_new = lwip_slip_make_new,
181     .locals_dict = (mp_obj_dict_t *)&lwip_slip_locals_dict,
182 };
183 
184 #endif // MICROPY_PY_LWIP_SLIP
185 
186 /******************************************************************************/
187 // Table to convert lwIP err_t codes to socket errno codes, from the lwIP
188 // socket API.
189 
190 // lwIP 2 changed LWIP_VERSION and it can no longer be used in macros,
191 // so we define our own equivalent version that can.
192 #define LWIP_VERSION_MACRO (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 \
193         | LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)
194 
195 // Extension to lwIP error codes
196 #define _ERR_BADF -16
197 // TODO: We just know that change happened somewhere between 1.4.0 and 1.4.1,
198 // investigate in more detail.
199 #if LWIP_VERSION_MACRO < 0x01040100
200 static const int error_lookup_table[] = {
201     0,                /* ERR_OK          0      No error, everything OK. */
202     MP_ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */
203     MP_ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */
204     MP_EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */
205     MP_EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */
206     MP_EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
207     MP_EINVAL,        /* ERR_VAL        -6      Illegal value.           */
208     MP_EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */
209 
210     MP_ECONNABORTED,  /* ERR_ABRT       -8      Connection aborted.      */
211     MP_ECONNRESET,    /* ERR_RST        -9      Connection reset.        */
212     MP_ENOTCONN,      /* ERR_CLSD       -10     Connection closed.       */
213     MP_ENOTCONN,      /* ERR_CONN       -11     Not connected.           */
214     MP_EIO,           /* ERR_ARG        -12     Illegal argument.        */
215     MP_EADDRINUSE,    /* ERR_USE        -13     Address in use.          */
216     -1,               /* ERR_IF         -14     Low-level netif error    */
217     MP_EALREADY,      /* ERR_ISCONN     -15     Already connected.       */
218     MP_EBADF,         /* _ERR_BADF      -16     Closed socket (null pcb) */
219 };
220 #elif LWIP_VERSION_MACRO < 0x02000000
221 static const int error_lookup_table[] = {
222     0,                /* ERR_OK          0      No error, everything OK. */
223     MP_ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */
224     MP_ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */
225     MP_EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */
226     MP_EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */
227     MP_EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
228     MP_EINVAL,        /* ERR_VAL        -6      Illegal value.           */
229     MP_EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */
230 
231     MP_EADDRINUSE,    /* ERR_USE        -8      Address in use.          */
232     MP_EALREADY,      /* ERR_ISCONN     -9      Already connected.       */
233     MP_ECONNABORTED,  /* ERR_ABRT       -10     Connection aborted.      */
234     MP_ECONNRESET,    /* ERR_RST        -11     Connection reset.        */
235     MP_ENOTCONN,      /* ERR_CLSD       -12     Connection closed.       */
236     MP_ENOTCONN,      /* ERR_CONN       -13     Not connected.           */
237     MP_EIO,           /* ERR_ARG        -14     Illegal argument.        */
238     -1,               /* ERR_IF         -15     Low-level netif error    */
239     MP_EBADF,         /* _ERR_BADF      -16     Closed socket (null pcb) */
240 };
241 #else
242 // Matches lwIP 2.0.3
243 #undef _ERR_BADF
244 #define _ERR_BADF -17
245 static const int error_lookup_table[] = {
246     0,                /* ERR_OK          0      No error, everything OK  */
247     MP_ENOMEM,        /* ERR_MEM        -1      Out of memory error      */
248     MP_ENOBUFS,       /* ERR_BUF        -2      Buffer error             */
249     MP_EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */
250     MP_EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem          */
251     MP_EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
252     MP_EINVAL,        /* ERR_VAL        -6      Illegal value            */
253     MP_EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block    */
254     MP_EADDRINUSE,    /* ERR_USE        -8      Address in use           */
255     MP_EALREADY,      /* ERR_ALREADY    -9      Already connecting       */
256     MP_EALREADY,      /* ERR_ISCONN     -10     Conn already established */
257     MP_ENOTCONN,      /* ERR_CONN       -11     Not connected            */
258     -1,               /* ERR_IF         -12     Low-level netif error    */
259     MP_ECONNABORTED,  /* ERR_ABRT       -13     Connection aborted       */
260     MP_ECONNRESET,    /* ERR_RST        -14     Connection reset         */
261     MP_ENOTCONN,      /* ERR_CLSD       -15     Connection closed        */
262     MP_EIO,           /* ERR_ARG        -16     Illegal argument.        */
263     MP_EBADF,         /* _ERR_BADF      -17     Closed socket (null pcb) */
264 };
265 #endif
266 
267 /*******************************************************************************/
268 // The socket object provided by lwip.socket.
269 
270 #define MOD_NETWORK_AF_INET (2)
271 #define MOD_NETWORK_AF_INET6 (10)
272 
273 #define MOD_NETWORK_SOCK_STREAM (1)
274 #define MOD_NETWORK_SOCK_DGRAM (2)
275 #define MOD_NETWORK_SOCK_RAW (3)
276 
277 typedef struct _lwip_socket_obj_t {
278     mp_obj_base_t base;
279 
280     volatile union {
281         struct tcp_pcb *tcp;
282         struct udp_pcb *udp;
283         struct raw_pcb *raw;
284     } pcb;
285     volatile union {
286         struct pbuf *pbuf;
287         struct {
288             uint8_t alloc;
289             uint8_t iget;
290             uint8_t iput;
291             union {
292                 struct tcp_pcb *item; // if alloc == 0
293                 struct tcp_pcb **array; // if alloc != 0
294             } tcp;
295         } connection;
296     } incoming;
297     mp_obj_t callback;
298     byte peer[4];
299     mp_uint_t peer_port;
300     mp_uint_t timeout;
301     uint16_t recv_offset;
302 
303     uint8_t domain;
304     uint8_t type;
305 
306     #define STATE_NEW 0
307     #define STATE_LISTENING 1
308     #define STATE_CONNECTING 2
309     #define STATE_CONNECTED 3
310     #define STATE_PEER_CLOSED 4
311     #define STATE_ACTIVE_UDP 5
312     // Negative value is lwIP error
313     int8_t state;
314 } lwip_socket_obj_t;
315 
poll_sockets(void)316 static inline void poll_sockets(void) {
317     #ifdef MICROPY_EVENT_POLL_HOOK
318     MICROPY_EVENT_POLL_HOOK;
319     #else
320     mp_hal_delay_ms(1);
321     #endif
322 }
323 
lwip_socket_incoming_array(lwip_socket_obj_t * socket)324 STATIC struct tcp_pcb *volatile *lwip_socket_incoming_array(lwip_socket_obj_t *socket) {
325     if (socket->incoming.connection.alloc == 0) {
326         return &socket->incoming.connection.tcp.item;
327     } else {
328         return &socket->incoming.connection.tcp.array[0];
329     }
330 }
331 
lwip_socket_free_incoming(lwip_socket_obj_t * socket)332 STATIC void lwip_socket_free_incoming(lwip_socket_obj_t *socket) {
333     bool socket_is_listener =
334         socket->type == MOD_NETWORK_SOCK_STREAM
335         && socket->pcb.tcp->state == LISTEN;
336 
337     if (!socket_is_listener) {
338         if (socket->incoming.pbuf != NULL) {
339             pbuf_free(socket->incoming.pbuf);
340             socket->incoming.pbuf = NULL;
341         }
342     } else {
343         uint8_t alloc = socket->incoming.connection.alloc;
344         struct tcp_pcb *volatile *tcp_array = lwip_socket_incoming_array(socket);
345         for (uint8_t i = 0; i < alloc; ++i) {
346             // Deregister callback and abort
347             if (tcp_array[i] != NULL) {
348                 tcp_poll(tcp_array[i], NULL, 0);
349                 tcp_abort(tcp_array[i]);
350                 tcp_array[i] = NULL;
351             }
352         }
353     }
354 }
355 
356 /*******************************************************************************/
357 // Callback functions for the lwIP raw API.
358 
exec_user_callback(lwip_socket_obj_t * socket)359 static inline void exec_user_callback(lwip_socket_obj_t *socket) {
360     if (socket->callback != MP_OBJ_NULL) {
361         // Schedule the user callback to execute outside the lwIP context
362         mp_sched_schedule(socket->callback, MP_OBJ_FROM_PTR(socket));
363     }
364 }
365 
366 #if MICROPY_PY_LWIP_SOCK_RAW
367 // Callback for incoming raw packets.
368 #if LWIP_VERSION_MAJOR < 2
_lwip_raw_incoming(void * arg,struct raw_pcb * pcb,struct pbuf * p,ip_addr_t * addr)369 STATIC u8_t _lwip_raw_incoming(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr)
370 #else
371 STATIC u8_t _lwip_raw_incoming(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr)
372 #endif
373 {
374     lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg;
375 
376     if (socket->incoming.pbuf != NULL) {
377         pbuf_free(p);
378     } else {
379         socket->incoming.pbuf = p;
380         memcpy(&socket->peer, addr, sizeof(socket->peer));
381     }
382     return 1; // we ate the packet
383 }
384 #endif
385 
386 // Callback for incoming UDP packets. We simply stash the packet and the source address,
387 // in case we need it for recvfrom.
388 #if LWIP_VERSION_MAJOR < 2
_lwip_udp_incoming(void * arg,struct udp_pcb * upcb,struct pbuf * p,ip_addr_t * addr,u16_t port)389 STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
390 #else
391 STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
392 #endif
393 {
394     lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg;
395 
396     if (socket->incoming.pbuf != NULL) {
397         // That's why they call it "unreliable". No room in the inn, drop the packet.
398         pbuf_free(p);
399     } else {
400         socket->incoming.pbuf = p;
401         socket->peer_port = (mp_uint_t)port;
402         memcpy(&socket->peer, addr, sizeof(socket->peer));
403     }
404 }
405 
406 // Callback for general tcp errors.
_lwip_tcp_error(void * arg,err_t err)407 STATIC void _lwip_tcp_error(void *arg, err_t err) {
408     lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg;
409 
410     // Free any incoming buffers or connections that are stored
411     lwip_socket_free_incoming(socket);
412     // Pass the error code back via the connection variable.
413     socket->state = err;
414     // If we got here, the lwIP stack either has deallocated or will deallocate the pcb.
415     socket->pcb.tcp = NULL;
416 }
417 
418 // Callback for tcp connection requests. Error code err is unused. (See tcp.h)
_lwip_tcp_connected(void * arg,struct tcp_pcb * tpcb,err_t err)419 STATIC err_t _lwip_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) {
420     lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg;
421 
422     socket->state = STATE_CONNECTED;
423     return ERR_OK;
424 }
425 
426 // Handle errors (eg connection aborted) on TCP PCBs that have been put on the
427 // accept queue but are not yet actually accepted.
_lwip_tcp_err_unaccepted(void * arg,err_t err)428 STATIC void _lwip_tcp_err_unaccepted(void *arg, err_t err) {
429     struct tcp_pcb *pcb = (struct tcp_pcb *)arg;
430 
431     // The ->connected entry is repurposed to store the parent socket; this is safe
432     // because it's only ever used by lwIP if tcp_connect is called on the TCP PCB.
433     lwip_socket_obj_t *socket = (lwip_socket_obj_t *)pcb->connected;
434 
435     // Array is not volatile because thiss callback is executed within the lwIP context
436     uint8_t alloc = socket->incoming.connection.alloc;
437     struct tcp_pcb **tcp_array = (struct tcp_pcb **)lwip_socket_incoming_array(socket);
438 
439     // Search for PCB on the accept queue of the parent socket
440     struct tcp_pcb **shift_down = NULL;
441     uint8_t i = socket->incoming.connection.iget;
442     do {
443         if (shift_down == NULL) {
444             if (tcp_array[i] == pcb) {
445                 shift_down = &tcp_array[i];
446             }
447         } else {
448             *shift_down = tcp_array[i];
449             shift_down = &tcp_array[i];
450         }
451         if (++i >= alloc) {
452             i = 0;
453         }
454     } while (i != socket->incoming.connection.iput);
455 
456     // PCB found in queue, remove it
457     if (shift_down != NULL) {
458         *shift_down = NULL;
459         socket->incoming.connection.iput = shift_down - tcp_array;
460     }
461 }
462 
463 // By default, a child socket of listen socket is created with recv
464 // handler which discards incoming pbuf's. We don't want to do that,
465 // so set this handler which requests lwIP to keep pbuf's and deliver
466 // them later. We cannot cache pbufs in child socket on Python side,
467 // until it is created in accept().
_lwip_tcp_recv_unaccepted(void * arg,struct tcp_pcb * pcb,struct pbuf * p,err_t err)468 STATIC err_t _lwip_tcp_recv_unaccepted(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) {
469     return ERR_BUF;
470 }
471 
472 // Callback for incoming tcp connections.
_lwip_tcp_accept(void * arg,struct tcp_pcb * newpcb,err_t err)473 STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
474     // err can be ERR_MEM to notify us that there was no memory for an incoming connection
475     if (err != ERR_OK) {
476         return ERR_OK;
477     }
478 
479     lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg;
480     tcp_recv(newpcb, _lwip_tcp_recv_unaccepted);
481 
482     // Search for an empty slot to store the new connection
483     struct tcp_pcb *volatile *slot = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iput];
484     if (*slot == NULL) {
485         // Have an empty slot to store waiting connection
486         *slot = newpcb;
487         if (++socket->incoming.connection.iput >= socket->incoming.connection.alloc) {
488             socket->incoming.connection.iput = 0;
489         }
490 
491         // Schedule user accept callback
492         exec_user_callback(socket);
493 
494         // Set the error callback to handle the case of a dropped connection before we
495         // have a chance to take it off the accept queue.
496         // The ->connected entry is repurposed to store the parent socket; this is safe
497         // because it's only ever used by lwIP if tcp_connect is called on the TCP PCB.
498         newpcb->connected = (void *)socket;
499         tcp_arg(newpcb, newpcb);
500         tcp_err(newpcb, _lwip_tcp_err_unaccepted);
501 
502         return ERR_OK;
503     }
504 
505     DEBUG_printf("_lwip_tcp_accept: No room to queue pcb waiting for accept\n");
506     return ERR_BUF;
507 }
508 
509 // Callback for inbound tcp packets.
_lwip_tcp_recv(void * arg,struct tcp_pcb * tcpb,struct pbuf * p,err_t err)510 STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err_t err) {
511     lwip_socket_obj_t *socket = (lwip_socket_obj_t *)arg;
512 
513     if (p == NULL) {
514         // Other side has closed connection.
515         DEBUG_printf("_lwip_tcp_recv[%p]: other side closed connection\n", socket);
516         socket->state = STATE_PEER_CLOSED;
517         exec_user_callback(socket);
518         return ERR_OK;
519     }
520 
521     if (socket->incoming.pbuf == NULL) {
522         socket->incoming.pbuf = p;
523     } else {
524         #ifdef SOCKET_SINGLE_PBUF
525         return ERR_BUF;
526         #else
527         pbuf_cat(socket->incoming.pbuf, p);
528         #endif
529     }
530 
531     exec_user_callback(socket);
532 
533     return ERR_OK;
534 }
535 
536 /*******************************************************************************/
537 // Functions for socket send/receive operations. Socket send/recv and friends call
538 // these to do the work.
539 
540 // Helper function for send/sendto to handle raw/UDP packets.
lwip_raw_udp_send(lwip_socket_obj_t * socket,const byte * buf,mp_uint_t len,byte * ip,mp_uint_t port,int * _errno)541 STATIC mp_uint_t lwip_raw_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
542     if (len > 0xffff) {
543         // Any packet that big is probably going to fail the pbuf_alloc anyway, but may as well try
544         len = 0xffff;
545     }
546 
547     MICROPY_PY_LWIP_ENTER
548 
549     // FIXME: maybe PBUF_ROM?
550     struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
551     if (p == NULL) {
552         MICROPY_PY_LWIP_EXIT
553         *_errno = MP_ENOMEM;
554         return -1;
555     }
556 
557     memcpy(p->payload, buf, len);
558 
559     err_t err;
560     if (ip == NULL) {
561         #if MICROPY_PY_LWIP_SOCK_RAW
562         if (socket->type == MOD_NETWORK_SOCK_RAW) {
563             err = raw_send(socket->pcb.raw, p);
564         } else
565         #endif
566         {
567             err = udp_send(socket->pcb.udp, p);
568         }
569     } else {
570         ip_addr_t dest;
571         IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]);
572         #if MICROPY_PY_LWIP_SOCK_RAW
573         if (socket->type == MOD_NETWORK_SOCK_RAW) {
574             err = raw_sendto(socket->pcb.raw, p, &dest);
575         } else
576         #endif
577         {
578             err = udp_sendto(socket->pcb.udp, p, &dest, port);
579         }
580     }
581 
582     pbuf_free(p);
583 
584     MICROPY_PY_LWIP_EXIT
585 
586     // udp_sendto can return 1 on occasion for ESP8266 port.  It's not known why
587     // but it seems that the send actually goes through without error in this case.
588     // So we treat such cases as a success until further investigation.
589     if (err != ERR_OK && err != 1) {
590         *_errno = error_lookup_table[-err];
591         return -1;
592     }
593 
594     return len;
595 }
596 
597 // Helper function for recv/recvfrom to handle raw/UDP packets
lwip_raw_udp_receive(lwip_socket_obj_t * socket,byte * buf,mp_uint_t len,byte * ip,mp_uint_t * port,int * _errno)598 STATIC mp_uint_t lwip_raw_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
599 
600     if (socket->incoming.pbuf == NULL) {
601         if (socket->timeout == 0) {
602             // Non-blocking socket.
603             *_errno = MP_EAGAIN;
604             return -1;
605         }
606 
607         // Wait for data to arrive on UDP socket.
608         mp_uint_t start = mp_hal_ticks_ms();
609         while (socket->incoming.pbuf == NULL) {
610             if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
611                 *_errno = MP_ETIMEDOUT;
612                 return -1;
613             }
614             poll_sockets();
615         }
616     }
617 
618     if (ip != NULL) {
619         memcpy(ip, &socket->peer, sizeof(socket->peer));
620         *port = socket->peer_port;
621     }
622 
623     struct pbuf *p = socket->incoming.pbuf;
624 
625     MICROPY_PY_LWIP_ENTER
626 
627     u16_t result = pbuf_copy_partial(p, buf, ((p->tot_len > len) ? len : p->tot_len), 0);
628     pbuf_free(p);
629     socket->incoming.pbuf = NULL;
630 
631     MICROPY_PY_LWIP_EXIT
632 
633     return (mp_uint_t)result;
634 }
635 
636 // For use in stream virtual methods
637 #define STREAM_ERROR_CHECK(socket) \
638     if (socket->state < 0) { \
639         *_errno = error_lookup_table[-socket->state]; \
640         return MP_STREAM_ERROR; \
641     } \
642     assert(socket->pcb.tcp);
643 
644 // Version of above for use when lock is held
645 #define STREAM_ERROR_CHECK_WITH_LOCK(socket) \
646     if (socket->state < 0) { \
647         *_errno = error_lookup_table[-socket->state]; \
648         MICROPY_PY_LWIP_EXIT \
649         return MP_STREAM_ERROR; \
650     } \
651     assert(socket->pcb.tcp);
652 
653 
654 // Helper function for send/sendto to handle TCP packets
lwip_tcp_send(lwip_socket_obj_t * socket,const byte * buf,mp_uint_t len,int * _errno)655 STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
656     // Check for any pending errors
657     STREAM_ERROR_CHECK(socket);
658 
659     MICROPY_PY_LWIP_ENTER
660 
661     u16_t available = tcp_sndbuf(socket->pcb.tcp);
662 
663     if (available == 0) {
664         // Non-blocking socket
665         if (socket->timeout == 0) {
666             MICROPY_PY_LWIP_EXIT
667             *_errno = MP_EAGAIN;
668             return MP_STREAM_ERROR;
669         }
670 
671         mp_uint_t start = mp_hal_ticks_ms();
672         // Assume that STATE_PEER_CLOSED may mean half-closed connection, where peer closed it
673         // sending direction, but not receiving. Consequently, check for both STATE_CONNECTED
674         // and STATE_PEER_CLOSED as normal conditions and still waiting for buffers to be sent.
675         // If peer fully closed socket, we would have socket->state set to ERR_RST (connection
676         // reset) by error callback.
677         // Avoid sending too small packets, so wait until at least 16 bytes available
678         while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) {
679             MICROPY_PY_LWIP_EXIT
680             if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
681                 *_errno = MP_ETIMEDOUT;
682                 return MP_STREAM_ERROR;
683             }
684             poll_sockets();
685             MICROPY_PY_LWIP_REENTER
686         }
687 
688         // While we waited, something could happen
689         STREAM_ERROR_CHECK_WITH_LOCK(socket);
690     }
691 
692     u16_t write_len = MIN(available, len);
693 
694     // If tcp_write returns ERR_MEM then there's currently not enough memory to
695     // queue the write, so wait and keep trying until it succeeds (with 10s limit).
696     // Note: if the socket is non-blocking then this code will actually block until
697     // there's enough memory to do the write, but by this stage we have already
698     // committed to being able to write the data.
699     err_t err;
700     for (int i = 0; i < 200; ++i) {
701         err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY);
702         if (err != ERR_MEM) {
703             break;
704         }
705         err = tcp_output(socket->pcb.tcp);
706         if (err != ERR_OK) {
707             break;
708         }
709         MICROPY_PY_LWIP_EXIT
710         mp_hal_delay_ms(50);
711         MICROPY_PY_LWIP_REENTER
712     }
713 
714     // If the output buffer is getting full then send the data to the lower layers
715     if (err == ERR_OK && tcp_sndbuf(socket->pcb.tcp) < TCP_SND_BUF / 4) {
716         err = tcp_output(socket->pcb.tcp);
717     }
718 
719     MICROPY_PY_LWIP_EXIT
720 
721     if (err != ERR_OK) {
722         *_errno = error_lookup_table[-err];
723         return MP_STREAM_ERROR;
724     }
725 
726     return write_len;
727 }
728 
729 // Helper function for recv/recvfrom to handle TCP packets
lwip_tcp_receive(lwip_socket_obj_t * socket,byte * buf,mp_uint_t len,int * _errno)730 STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
731     // Check for any pending errors
732     STREAM_ERROR_CHECK(socket);
733 
734     if (socket->incoming.pbuf == NULL) {
735 
736         // Non-blocking socket
737         if (socket->timeout == 0) {
738             if (socket->state == STATE_PEER_CLOSED) {
739                 return 0;
740             }
741             *_errno = MP_EAGAIN;
742             return -1;
743         }
744 
745         mp_uint_t start = mp_hal_ticks_ms();
746         while (socket->state == STATE_CONNECTED && socket->incoming.pbuf == NULL) {
747             if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
748                 *_errno = MP_ETIMEDOUT;
749                 return -1;
750             }
751             poll_sockets();
752         }
753 
754         if (socket->state == STATE_PEER_CLOSED) {
755             if (socket->incoming.pbuf == NULL) {
756                 // socket closed and no data left in buffer
757                 return 0;
758             }
759         } else if (socket->state != STATE_CONNECTED) {
760             if (socket->state >= STATE_NEW) {
761                 *_errno = MP_ENOTCONN;
762             } else {
763                 *_errno = error_lookup_table[-socket->state];
764             }
765             return -1;
766         }
767     }
768 
769     MICROPY_PY_LWIP_ENTER
770 
771     assert(socket->pcb.tcp != NULL);
772 
773     struct pbuf *p = socket->incoming.pbuf;
774 
775     mp_uint_t remaining = p->len - socket->recv_offset;
776     if (len > remaining) {
777         len = remaining;
778     }
779 
780     memcpy(buf, (byte *)p->payload + socket->recv_offset, len);
781 
782     remaining -= len;
783     if (remaining == 0) {
784         socket->incoming.pbuf = p->next;
785         // If we don't ref here, free() will free the entire chain,
786         // if we ref, it does what we need: frees 1st buf, and decrements
787         // next buf's refcount back to 1.
788         pbuf_ref(p->next);
789         pbuf_free(p);
790         socket->recv_offset = 0;
791     } else {
792         socket->recv_offset += len;
793     }
794     tcp_recved(socket->pcb.tcp, len);
795 
796     MICROPY_PY_LWIP_EXIT
797 
798     return len;
799 }
800 
801 /*******************************************************************************/
802 // The socket functions provided by lwip.socket.
803 
804 STATIC const mp_obj_type_t lwip_socket_type;
805 
lwip_socket_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)806 STATIC void lwip_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
807     lwip_socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
808     mp_printf(print, "<socket state=%d timeout=%d incoming=%p off=%d>", self->state, self->timeout,
809         self->incoming.pbuf, self->recv_offset);
810 }
811 
812 // FIXME: Only supports two arguments at present
lwip_socket_make_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * args)813 STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
814     mp_arg_check_num(n_args, n_kw, 0, 4, false);
815 
816     lwip_socket_obj_t *socket = m_new_obj_with_finaliser(lwip_socket_obj_t);
817     socket->base.type = &lwip_socket_type;
818     socket->timeout = -1;
819     socket->recv_offset = 0;
820     socket->domain = MOD_NETWORK_AF_INET;
821     socket->type = MOD_NETWORK_SOCK_STREAM;
822     socket->callback = MP_OBJ_NULL;
823     socket->state = STATE_NEW;
824 
825     if (n_args >= 1) {
826         socket->domain = mp_obj_get_int(args[0]);
827         if (n_args >= 2) {
828             socket->type = mp_obj_get_int(args[1]);
829         }
830     }
831 
832     switch (socket->type) {
833         case MOD_NETWORK_SOCK_STREAM:
834             socket->pcb.tcp = tcp_new();
835             socket->incoming.connection.alloc = 0;
836             socket->incoming.connection.tcp.item = NULL;
837             break;
838         case MOD_NETWORK_SOCK_DGRAM:
839             socket->pcb.udp = udp_new();
840             socket->incoming.pbuf = NULL;
841             break;
842         #if MICROPY_PY_LWIP_SOCK_RAW
843         case MOD_NETWORK_SOCK_RAW: {
844             mp_int_t proto = n_args <= 2 ? 0 : mp_obj_get_int(args[2]);
845             socket->pcb.raw = raw_new(proto);
846             break;
847         }
848         #endif
849         default:
850             mp_raise_OSError(MP_EINVAL);
851     }
852 
853     if (socket->pcb.tcp == NULL) {
854         mp_raise_OSError(MP_ENOMEM);
855     }
856 
857     switch (socket->type) {
858         case MOD_NETWORK_SOCK_STREAM: {
859             // Register the socket object as our callback argument.
860             tcp_arg(socket->pcb.tcp, (void *)socket);
861             // Register our error callback.
862             tcp_err(socket->pcb.tcp, _lwip_tcp_error);
863             break;
864         }
865         case MOD_NETWORK_SOCK_DGRAM: {
866             socket->state = STATE_ACTIVE_UDP;
867             // Register our receive callback now. Since UDP sockets don't require binding or connection
868             // before use, there's no other good time to do it.
869             udp_recv(socket->pcb.udp, _lwip_udp_incoming, (void *)socket);
870             break;
871         }
872         #if MICROPY_PY_LWIP_SOCK_RAW
873         case MOD_NETWORK_SOCK_RAW: {
874             // Register our receive callback now. Since raw sockets don't require binding or connection
875             // before use, there's no other good time to do it.
876             raw_recv(socket->pcb.raw, _lwip_raw_incoming, (void *)socket);
877             break;
878         }
879         #endif
880     }
881 
882     return MP_OBJ_FROM_PTR(socket);
883 }
884 
lwip_socket_bind(mp_obj_t self_in,mp_obj_t addr_in)885 STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
886     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
887 
888     uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
889     mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
890 
891     ip_addr_t bind_addr;
892     IP4_ADDR(&bind_addr, ip[0], ip[1], ip[2], ip[3]);
893 
894     err_t err = ERR_ARG;
895     switch (socket->type) {
896         case MOD_NETWORK_SOCK_STREAM: {
897             err = tcp_bind(socket->pcb.tcp, &bind_addr, port);
898             break;
899         }
900         case MOD_NETWORK_SOCK_DGRAM: {
901             err = udp_bind(socket->pcb.udp, &bind_addr, port);
902             break;
903         }
904     }
905 
906     if (err != ERR_OK) {
907         mp_raise_OSError(error_lookup_table[-err]);
908     }
909 
910     return mp_const_none;
911 }
912 STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_bind_obj, lwip_socket_bind);
913 
lwip_socket_listen(mp_obj_t self_in,mp_obj_t backlog_in)914 STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) {
915     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
916     mp_int_t backlog = mp_obj_get_int(backlog_in);
917 
918     if (socket->pcb.tcp == NULL) {
919         mp_raise_OSError(MP_EBADF);
920     }
921     if (socket->type != MOD_NETWORK_SOCK_STREAM) {
922         mp_raise_OSError(MP_EOPNOTSUPP);
923     }
924 
925     struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog);
926     if (new_pcb == NULL) {
927         mp_raise_OSError(MP_ENOMEM);
928     }
929     socket->pcb.tcp = new_pcb;
930 
931     // Allocate memory for the backlog of connections
932     if (backlog <= 1) {
933         socket->incoming.connection.alloc = 0;
934         socket->incoming.connection.tcp.item = NULL;
935     } else {
936         socket->incoming.connection.alloc = backlog;
937         socket->incoming.connection.tcp.array = m_new0(struct tcp_pcb *, backlog);
938     }
939     socket->incoming.connection.iget = 0;
940     socket->incoming.connection.iput = 0;
941 
942     tcp_accept(new_pcb, _lwip_tcp_accept);
943 
944     // Socket is no longer considered "new" for purposes of polling
945     socket->state = STATE_LISTENING;
946 
947     return mp_const_none;
948 }
949 STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen);
950 
lwip_socket_accept(mp_obj_t self_in)951 STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
952     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
953 
954     if (socket->type != MOD_NETWORK_SOCK_STREAM) {
955         mp_raise_OSError(MP_EOPNOTSUPP);
956     }
957 
958     // Create new socket object, do it here because we must not raise an out-of-memory
959     // exception when the LWIP concurrency lock is held
960     lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t);
961     socket2->base.type = &lwip_socket_type;
962 
963     MICROPY_PY_LWIP_ENTER
964 
965     if (socket->pcb.tcp == NULL) {
966         MICROPY_PY_LWIP_EXIT
967         m_del_obj(lwip_socket_obj_t, socket2);
968         mp_raise_OSError(MP_EBADF);
969     }
970 
971     // I need to do this because "tcp_accepted", later, is a macro.
972     struct tcp_pcb *listener = socket->pcb.tcp;
973     if (listener->state != LISTEN) {
974         MICROPY_PY_LWIP_EXIT
975         m_del_obj(lwip_socket_obj_t, socket2);
976         mp_raise_OSError(MP_EINVAL);
977     }
978 
979     // accept incoming connection
980     struct tcp_pcb *volatile *incoming_connection = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iget];
981     if (*incoming_connection == NULL) {
982         if (socket->timeout == 0) {
983             MICROPY_PY_LWIP_EXIT
984             m_del_obj(lwip_socket_obj_t, socket2);
985             mp_raise_OSError(MP_EAGAIN);
986         } else if (socket->timeout != -1) {
987             mp_uint_t retries = socket->timeout / 100;
988             while (*incoming_connection == NULL) {
989                 MICROPY_PY_LWIP_EXIT
990                 if (retries-- == 0) {
991                     m_del_obj(lwip_socket_obj_t, socket2);
992                     mp_raise_OSError(MP_ETIMEDOUT);
993                 }
994                 mp_hal_delay_ms(100);
995                 MICROPY_PY_LWIP_REENTER
996             }
997         } else {
998             while (*incoming_connection == NULL) {
999                 MICROPY_PY_LWIP_EXIT
1000                 poll_sockets();
1001                 MICROPY_PY_LWIP_REENTER
1002             }
1003         }
1004     }
1005 
1006     // We get a new pcb handle...
1007     socket2->pcb.tcp = *incoming_connection;
1008     if (++socket->incoming.connection.iget >= socket->incoming.connection.alloc) {
1009         socket->incoming.connection.iget = 0;
1010     }
1011     *incoming_connection = NULL;
1012 
1013     // ...and set up the new socket for it.
1014     socket2->domain = MOD_NETWORK_AF_INET;
1015     socket2->type = MOD_NETWORK_SOCK_STREAM;
1016     socket2->incoming.pbuf = NULL;
1017     socket2->timeout = socket->timeout;
1018     socket2->state = STATE_CONNECTED;
1019     socket2->recv_offset = 0;
1020     socket2->callback = MP_OBJ_NULL;
1021     tcp_arg(socket2->pcb.tcp, (void *)socket2);
1022     tcp_err(socket2->pcb.tcp, _lwip_tcp_error);
1023     tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv);
1024 
1025     tcp_accepted(listener);
1026 
1027     MICROPY_PY_LWIP_EXIT
1028 
1029     // make the return value
1030     uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
1031     memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip));
1032     mp_uint_t port = (mp_uint_t)socket2->pcb.tcp->remote_port;
1033     mp_obj_tuple_t *client = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
1034     client->items[0] = MP_OBJ_FROM_PTR(socket2);
1035     client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
1036 
1037     return MP_OBJ_FROM_PTR(client);
1038 }
1039 STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_socket_accept_obj, lwip_socket_accept);
1040 
lwip_socket_connect(mp_obj_t self_in,mp_obj_t addr_in)1041 STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
1042     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1043 
1044     if (socket->pcb.tcp == NULL) {
1045         mp_raise_OSError(MP_EBADF);
1046     }
1047 
1048     // get address
1049     uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
1050     mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
1051 
1052     ip_addr_t dest;
1053     IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]);
1054 
1055     err_t err = ERR_ARG;
1056     switch (socket->type) {
1057         case MOD_NETWORK_SOCK_STREAM: {
1058             if (socket->state != STATE_NEW) {
1059                 if (socket->state == STATE_CONNECTED) {
1060                     mp_raise_OSError(MP_EISCONN);
1061                 } else {
1062                     mp_raise_OSError(MP_EALREADY);
1063                 }
1064             }
1065 
1066             // Register our receive callback.
1067             MICROPY_PY_LWIP_ENTER
1068             tcp_recv(socket->pcb.tcp, _lwip_tcp_recv);
1069             socket->state = STATE_CONNECTING;
1070             err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected);
1071             if (err != ERR_OK) {
1072                 MICROPY_PY_LWIP_EXIT
1073                 socket->state = STATE_NEW;
1074                 mp_raise_OSError(error_lookup_table[-err]);
1075             }
1076             socket->peer_port = (mp_uint_t)port;
1077             memcpy(socket->peer, &dest, sizeof(socket->peer));
1078             MICROPY_PY_LWIP_EXIT
1079 
1080             // And now we wait...
1081             if (socket->timeout != -1) {
1082                 for (mp_uint_t retries = socket->timeout / 100; retries--;) {
1083                     mp_hal_delay_ms(100);
1084                     if (socket->state != STATE_CONNECTING) {
1085                         break;
1086                     }
1087                 }
1088                 if (socket->state == STATE_CONNECTING) {
1089                     mp_raise_OSError(MP_EINPROGRESS);
1090                 }
1091             } else {
1092                 while (socket->state == STATE_CONNECTING) {
1093                     poll_sockets();
1094                 }
1095             }
1096             if (socket->state == STATE_CONNECTED) {
1097                 err = ERR_OK;
1098             } else {
1099                 err = socket->state;
1100             }
1101             break;
1102         }
1103         case MOD_NETWORK_SOCK_DGRAM: {
1104             err = udp_connect(socket->pcb.udp, &dest, port);
1105             break;
1106         }
1107         #if MICROPY_PY_LWIP_SOCK_RAW
1108         case MOD_NETWORK_SOCK_RAW: {
1109             err = raw_connect(socket->pcb.raw, &dest);
1110             break;
1111         }
1112         #endif
1113     }
1114 
1115     if (err != ERR_OK) {
1116         mp_raise_OSError(error_lookup_table[-err]);
1117     }
1118 
1119     return mp_const_none;
1120 }
1121 STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_connect_obj, lwip_socket_connect);
1122 
lwip_socket_check_connected(lwip_socket_obj_t * socket)1123 STATIC void lwip_socket_check_connected(lwip_socket_obj_t *socket) {
1124     if (socket->pcb.tcp == NULL) {
1125         // not connected
1126         int _errno = error_lookup_table[-socket->state];
1127         socket->state = _ERR_BADF;
1128         mp_raise_OSError(_errno);
1129     }
1130 }
1131 
lwip_socket_send(mp_obj_t self_in,mp_obj_t buf_in)1132 STATIC mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
1133     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1134     int _errno;
1135 
1136     lwip_socket_check_connected(socket);
1137 
1138     mp_buffer_info_t bufinfo;
1139     mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
1140 
1141     mp_uint_t ret = 0;
1142     switch (socket->type) {
1143         case MOD_NETWORK_SOCK_STREAM: {
1144             ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno);
1145             break;
1146         }
1147         case MOD_NETWORK_SOCK_DGRAM:
1148         #if MICROPY_PY_LWIP_SOCK_RAW
1149         case MOD_NETWORK_SOCK_RAW:
1150         #endif
1151             ret = lwip_raw_udp_send(socket, bufinfo.buf, bufinfo.len, NULL, 0, &_errno);
1152             break;
1153     }
1154     if (ret == -1) {
1155         mp_raise_OSError(_errno);
1156     }
1157 
1158     return mp_obj_new_int_from_uint(ret);
1159 }
1160 STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_send_obj, lwip_socket_send);
1161 
lwip_socket_recv(mp_obj_t self_in,mp_obj_t len_in)1162 STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
1163     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1164     int _errno;
1165 
1166     lwip_socket_check_connected(socket);
1167 
1168     mp_int_t len = mp_obj_get_int(len_in);
1169     vstr_t vstr;
1170     vstr_init_len(&vstr, len);
1171 
1172     mp_uint_t ret = 0;
1173     switch (socket->type) {
1174         case MOD_NETWORK_SOCK_STREAM: {
1175             ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, &_errno);
1176             break;
1177         }
1178         case MOD_NETWORK_SOCK_DGRAM:
1179         #if MICROPY_PY_LWIP_SOCK_RAW
1180         case MOD_NETWORK_SOCK_RAW:
1181         #endif
1182             ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, NULL, NULL, &_errno);
1183             break;
1184     }
1185     if (ret == -1) {
1186         mp_raise_OSError(_errno);
1187     }
1188 
1189     if (ret == 0) {
1190         return mp_const_empty_bytes;
1191     }
1192     vstr.len = ret;
1193     return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
1194 }
1195 STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recv_obj, lwip_socket_recv);
1196 
lwip_socket_sendto(mp_obj_t self_in,mp_obj_t data_in,mp_obj_t addr_in)1197 STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
1198     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1199     int _errno;
1200 
1201     lwip_socket_check_connected(socket);
1202 
1203     mp_buffer_info_t bufinfo;
1204     mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
1205 
1206     uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
1207     mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
1208 
1209     mp_uint_t ret = 0;
1210     switch (socket->type) {
1211         case MOD_NETWORK_SOCK_STREAM: {
1212             ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno);
1213             break;
1214         }
1215         case MOD_NETWORK_SOCK_DGRAM:
1216         #if MICROPY_PY_LWIP_SOCK_RAW
1217         case MOD_NETWORK_SOCK_RAW:
1218         #endif
1219             ret = lwip_raw_udp_send(socket, bufinfo.buf, bufinfo.len, ip, port, &_errno);
1220             break;
1221     }
1222     if (ret == -1) {
1223         mp_raise_OSError(_errno);
1224     }
1225 
1226     return mp_obj_new_int_from_uint(ret);
1227 }
1228 STATIC MP_DEFINE_CONST_FUN_OBJ_3(lwip_socket_sendto_obj, lwip_socket_sendto);
1229 
lwip_socket_recvfrom(mp_obj_t self_in,mp_obj_t len_in)1230 STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
1231     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1232     int _errno;
1233 
1234     lwip_socket_check_connected(socket);
1235 
1236     mp_int_t len = mp_obj_get_int(len_in);
1237     vstr_t vstr;
1238     vstr_init_len(&vstr, len);
1239     byte ip[4];
1240     mp_uint_t port;
1241 
1242     mp_uint_t ret = 0;
1243     switch (socket->type) {
1244         case MOD_NETWORK_SOCK_STREAM: {
1245             memcpy(ip, &socket->peer, sizeof(socket->peer));
1246             port = (mp_uint_t)socket->peer_port;
1247             ret = lwip_tcp_receive(socket, (byte *)vstr.buf, len, &_errno);
1248             break;
1249         }
1250         case MOD_NETWORK_SOCK_DGRAM:
1251         #if MICROPY_PY_LWIP_SOCK_RAW
1252         case MOD_NETWORK_SOCK_RAW:
1253         #endif
1254             ret = lwip_raw_udp_receive(socket, (byte *)vstr.buf, len, ip, &port, &_errno);
1255             break;
1256     }
1257     if (ret == -1) {
1258         mp_raise_OSError(_errno);
1259     }
1260 
1261     mp_obj_t tuple[2];
1262     if (ret == 0) {
1263         tuple[0] = mp_const_empty_bytes;
1264     } else {
1265         vstr.len = ret;
1266         tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
1267     }
1268     tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
1269     return mp_obj_new_tuple(2, tuple);
1270 }
1271 STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recvfrom_obj, lwip_socket_recvfrom);
1272 
lwip_socket_sendall(mp_obj_t self_in,mp_obj_t buf_in)1273 STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
1274     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1275     lwip_socket_check_connected(socket);
1276 
1277     int _errno;
1278     mp_buffer_info_t bufinfo;
1279     mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
1280 
1281     mp_uint_t ret = 0;
1282     switch (socket->type) {
1283         case MOD_NETWORK_SOCK_STREAM: {
1284             if (socket->timeout == 0) {
1285                 // Behavior of sendall() for non-blocking sockets isn't explicitly specified.
1286                 // But it's specified that "On error, an exception is raised, there is no
1287                 // way to determine how much data, if any, was successfully sent." Then, the
1288                 // most useful behavior is: check whether we will be able to send all of input
1289                 // data without EAGAIN, and if won't be, raise it without sending any.
1290                 if (bufinfo.len > tcp_sndbuf(socket->pcb.tcp)) {
1291                     mp_raise_OSError(MP_EAGAIN);
1292                 }
1293             }
1294             // TODO: In CPython3.5, socket timeout should apply to the
1295             // entire sendall() operation, not to individual send() chunks.
1296             while (bufinfo.len != 0) {
1297                 ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno);
1298                 if (ret == -1) {
1299                     mp_raise_OSError(_errno);
1300                 }
1301                 bufinfo.len -= ret;
1302                 bufinfo.buf = (char *)bufinfo.buf + ret;
1303             }
1304             break;
1305         }
1306         case MOD_NETWORK_SOCK_DGRAM:
1307             mp_raise_NotImplementedError(NULL);
1308             break;
1309     }
1310 
1311     return mp_const_none;
1312 }
1313 STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_sendall_obj, lwip_socket_sendall);
1314 
lwip_socket_settimeout(mp_obj_t self_in,mp_obj_t timeout_in)1315 STATIC mp_obj_t lwip_socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
1316     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1317     mp_uint_t timeout;
1318     if (timeout_in == mp_const_none) {
1319         timeout = -1;
1320     } else {
1321         #if MICROPY_PY_BUILTINS_FLOAT
1322         timeout = (mp_uint_t)(MICROPY_FLOAT_CONST(1000.0) * mp_obj_get_float(timeout_in));
1323         #else
1324         timeout = 1000 * mp_obj_get_int(timeout_in);
1325         #endif
1326     }
1327     socket->timeout = timeout;
1328     return mp_const_none;
1329 }
1330 STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_settimeout_obj, lwip_socket_settimeout);
1331 
lwip_socket_setblocking(mp_obj_t self_in,mp_obj_t flag_in)1332 STATIC mp_obj_t lwip_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
1333     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1334     bool val = mp_obj_is_true(flag_in);
1335     if (val) {
1336         socket->timeout = -1;
1337     } else {
1338         socket->timeout = 0;
1339     }
1340     return mp_const_none;
1341 }
1342 STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_setblocking_obj, lwip_socket_setblocking);
1343 
lwip_socket_setsockopt(size_t n_args,const mp_obj_t * args)1344 STATIC mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) {
1345     (void)n_args; // always 4
1346     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(args[0]);
1347 
1348     int opt = mp_obj_get_int(args[2]);
1349     if (opt == 20) {
1350         if (args[3] == mp_const_none) {
1351             socket->callback = MP_OBJ_NULL;
1352         } else {
1353             socket->callback = args[3];
1354         }
1355         return mp_const_none;
1356     }
1357 
1358     switch (opt) {
1359         // level: SOL_SOCKET
1360         case SOF_REUSEADDR: {
1361             mp_int_t val = mp_obj_get_int(args[3]);
1362             // Options are common for UDP and TCP pcb's.
1363             if (val) {
1364                 ip_set_option(socket->pcb.tcp, SOF_REUSEADDR);
1365             } else {
1366                 ip_reset_option(socket->pcb.tcp, SOF_REUSEADDR);
1367             }
1368             break;
1369         }
1370 
1371         // level: IPPROTO_IP
1372         case IP_ADD_MEMBERSHIP: {
1373             mp_buffer_info_t bufinfo;
1374             mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
1375             if (bufinfo.len != sizeof(ip_addr_t) * 2) {
1376                 mp_raise_ValueError(NULL);
1377             }
1378 
1379             // POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa
1380             err_t err = igmp_joingroup((ip_addr_t *)bufinfo.buf + 1, bufinfo.buf);
1381             if (err != ERR_OK) {
1382                 mp_raise_OSError(error_lookup_table[-err]);
1383             }
1384             break;
1385         }
1386 
1387         default:
1388             printf("Warning: lwip.setsockopt() not implemented\n");
1389     }
1390     return mp_const_none;
1391 }
1392 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_setsockopt_obj, 4, 4, lwip_socket_setsockopt);
1393 
lwip_socket_makefile(size_t n_args,const mp_obj_t * args)1394 STATIC mp_obj_t lwip_socket_makefile(size_t n_args, const mp_obj_t *args) {
1395     (void)n_args;
1396     return args[0];
1397 }
1398 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_makefile_obj, 1, 3, lwip_socket_makefile);
1399 
lwip_socket_read(mp_obj_t self_in,void * buf,mp_uint_t size,int * errcode)1400 STATIC mp_uint_t lwip_socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
1401     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1402 
1403     switch (socket->type) {
1404         case MOD_NETWORK_SOCK_STREAM:
1405             return lwip_tcp_receive(socket, buf, size, errcode);
1406         case MOD_NETWORK_SOCK_DGRAM:
1407         #if MICROPY_PY_LWIP_SOCK_RAW
1408         case MOD_NETWORK_SOCK_RAW:
1409         #endif
1410             return lwip_raw_udp_receive(socket, buf, size, NULL, NULL, errcode);
1411     }
1412     // Unreachable
1413     return MP_STREAM_ERROR;
1414 }
1415 
lwip_socket_write(mp_obj_t self_in,const void * buf,mp_uint_t size,int * errcode)1416 STATIC mp_uint_t lwip_socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
1417     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1418 
1419     switch (socket->type) {
1420         case MOD_NETWORK_SOCK_STREAM:
1421             return lwip_tcp_send(socket, buf, size, errcode);
1422         case MOD_NETWORK_SOCK_DGRAM:
1423         #if MICROPY_PY_LWIP_SOCK_RAW
1424         case MOD_NETWORK_SOCK_RAW:
1425         #endif
1426             return lwip_raw_udp_send(socket, buf, size, NULL, 0, errcode);
1427     }
1428     // Unreachable
1429     return MP_STREAM_ERROR;
1430 }
1431 
_lwip_tcp_close_poll(void * arg,struct tcp_pcb * pcb)1432 STATIC err_t _lwip_tcp_close_poll(void *arg, struct tcp_pcb *pcb) {
1433     // Connection has not been cleanly closed so just abort it to free up memory
1434     tcp_poll(pcb, NULL, 0);
1435     tcp_abort(pcb);
1436     return ERR_OK;
1437 }
1438 
lwip_socket_ioctl(mp_obj_t self_in,mp_uint_t request,uintptr_t arg,int * errcode)1439 STATIC mp_uint_t lwip_socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
1440     lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
1441     mp_uint_t ret;
1442 
1443     MICROPY_PY_LWIP_ENTER
1444 
1445     if (request == MP_STREAM_POLL) {
1446         uintptr_t flags = arg;
1447         ret = 0;
1448 
1449         if (flags & MP_STREAM_POLL_RD) {
1450             if (socket->state == STATE_LISTENING) {
1451                 // Listening TCP socket may have one or multiple connections waiting
1452                 if (lwip_socket_incoming_array(socket)[socket->incoming.connection.iget] != NULL) {
1453                     ret |= MP_STREAM_POLL_RD;
1454                 }
1455             } else {
1456                 // Otherwise there is just one slot for incoming data
1457                 if (socket->incoming.pbuf != NULL) {
1458                     ret |= MP_STREAM_POLL_RD;
1459                 }
1460             }
1461         }
1462 
1463         if (flags & MP_STREAM_POLL_WR) {
1464             if (socket->type == MOD_NETWORK_SOCK_DGRAM && socket->pcb.udp != NULL) {
1465                 // UDP socket is writable
1466                 ret |= MP_STREAM_POLL_WR;
1467             #if MICROPY_PY_LWIP_SOCK_RAW
1468             } else if (socket->type == MOD_NETWORK_SOCK_RAW && socket->pcb.raw != NULL) {
1469                 // raw socket is writable
1470                 ret |= MP_STREAM_POLL_WR;
1471             #endif
1472             } else if (socket->pcb.tcp != NULL && tcp_sndbuf(socket->pcb.tcp) > 0) {
1473                 // TCP socket is writable
1474                 // Note: pcb.tcp==NULL if state<0, and in this case we can't call tcp_sndbuf
1475                 ret |= MP_STREAM_POLL_WR;
1476             }
1477         }
1478 
1479         if (socket->state == STATE_NEW) {
1480             // New sockets are not connected so set HUP
1481             ret |= MP_STREAM_POLL_HUP;
1482         } else if (socket->state == STATE_PEER_CLOSED) {
1483             // Peer-closed socket is both readable and writable: read will
1484             // return EOF, write - error. Without this poll will hang on a
1485             // socket which was closed by peer.
1486             ret |= flags & (MP_STREAM_POLL_RD | MP_STREAM_POLL_WR);
1487         } else if (socket->state == ERR_RST) {
1488             // Socket was reset by peer, a write will return an error
1489             ret |= flags & MP_STREAM_POLL_WR;
1490             ret |= MP_STREAM_POLL_HUP;
1491         } else if (socket->state == _ERR_BADF) {
1492             ret |= MP_STREAM_POLL_NVAL;
1493         } else if (socket->state < 0) {
1494             // Socket in some other error state, use catch-all ERR flag
1495             // TODO: may need to set other return flags here
1496             ret |= MP_STREAM_POLL_ERR;
1497         }
1498 
1499     } else if (request == MP_STREAM_CLOSE) {
1500         if (socket->pcb.tcp == NULL) {
1501             MICROPY_PY_LWIP_EXIT
1502             return 0;
1503         }
1504 
1505         // Free any incoming buffers or connections that are stored
1506         lwip_socket_free_incoming(socket);
1507 
1508         switch (socket->type) {
1509             case MOD_NETWORK_SOCK_STREAM: {
1510                 // Deregister callback (pcb.tcp is set to NULL below so must deregister now)
1511                 tcp_arg(socket->pcb.tcp, NULL);
1512                 tcp_err(socket->pcb.tcp, NULL);
1513                 tcp_recv(socket->pcb.tcp, NULL);
1514 
1515                 if (socket->pcb.tcp->state != LISTEN) {
1516                     // Schedule a callback to abort the connection if it's not cleanly closed after
1517                     // the given timeout.  The callback must be set before calling tcp_close since
1518                     // the latter may free the pcb; if it doesn't then the callback will be active.
1519                     tcp_poll(socket->pcb.tcp, _lwip_tcp_close_poll, MICROPY_PY_LWIP_TCP_CLOSE_TIMEOUT_MS / 500);
1520                 }
1521                 if (tcp_close(socket->pcb.tcp) != ERR_OK) {
1522                     DEBUG_printf("lwip_close: had to call tcp_abort()\n");
1523                     tcp_abort(socket->pcb.tcp);
1524                 }
1525                 break;
1526             }
1527             case MOD_NETWORK_SOCK_DGRAM:
1528                 udp_recv(socket->pcb.udp, NULL, NULL);
1529                 udp_remove(socket->pcb.udp);
1530                 break;
1531             #if MICROPY_PY_LWIP_SOCK_RAW
1532             case MOD_NETWORK_SOCK_RAW:
1533                 raw_recv(socket->pcb.raw, NULL, NULL);
1534                 raw_remove(socket->pcb.raw);
1535                 break;
1536             #endif
1537         }
1538 
1539         socket->pcb.tcp = NULL;
1540         socket->state = _ERR_BADF;
1541         ret = 0;
1542 
1543     } else {
1544         *errcode = MP_EINVAL;
1545         ret = MP_STREAM_ERROR;
1546     }
1547 
1548     MICROPY_PY_LWIP_EXIT
1549 
1550     return ret;
1551 }
1552 
1553 STATIC const mp_rom_map_elem_t lwip_socket_locals_dict_table[] = {
1554     { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
1555     { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
1556     { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&lwip_socket_bind_obj) },
1557     { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&lwip_socket_listen_obj) },
1558     { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&lwip_socket_accept_obj) },
1559     { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&lwip_socket_connect_obj) },
1560     { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&lwip_socket_send_obj) },
1561     { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&lwip_socket_recv_obj) },
1562     { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&lwip_socket_sendto_obj) },
1563     { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&lwip_socket_recvfrom_obj) },
1564     { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&lwip_socket_sendall_obj) },
1565     { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&lwip_socket_settimeout_obj) },
1566     { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&lwip_socket_setblocking_obj) },
1567     { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&lwip_socket_setsockopt_obj) },
1568     { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&lwip_socket_makefile_obj) },
1569 
1570     { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
1571     { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
1572     { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
1573     { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
1574 };
1575 STATIC MP_DEFINE_CONST_DICT(lwip_socket_locals_dict, lwip_socket_locals_dict_table);
1576 
1577 STATIC const mp_stream_p_t lwip_socket_stream_p = {
1578     .read = lwip_socket_read,
1579     .write = lwip_socket_write,
1580     .ioctl = lwip_socket_ioctl,
1581 };
1582 
1583 STATIC const mp_obj_type_t lwip_socket_type = {
1584     { &mp_type_type },
1585     .name = MP_QSTR_socket,
1586     .print = lwip_socket_print,
1587     .make_new = lwip_socket_make_new,
1588     .protocol = &lwip_socket_stream_p,
1589     .locals_dict = (mp_obj_dict_t *)&lwip_socket_locals_dict,
1590 };
1591 
1592 /******************************************************************************/
1593 // Support functions for memory protection. lwIP has its own memory management
1594 // routines for its internal structures, and since they might be called in
1595 // interrupt handlers, they need some protection.
sys_arch_protect()1596 sys_prot_t sys_arch_protect() {
1597     return (sys_prot_t)MICROPY_BEGIN_ATOMIC_SECTION();
1598 }
1599 
sys_arch_unprotect(sys_prot_t state)1600 void sys_arch_unprotect(sys_prot_t state) {
1601     MICROPY_END_ATOMIC_SECTION((mp_uint_t)state);
1602 }
1603 
1604 /******************************************************************************/
1605 // Polling callbacks for the interfaces connected to lwIP. Right now it calls
1606 // itself a "list" but isn't; we only support a single interface.
1607 
1608 typedef struct nic_poll {
1609     void (*poll)(void *arg);
1610     void *poll_arg;
1611 } nic_poll_t;
1612 
1613 STATIC nic_poll_t lwip_poll_list;
1614 
mod_lwip_register_poll(void (* poll)(void * arg),void * poll_arg)1615 void mod_lwip_register_poll(void (*poll)(void *arg), void *poll_arg) {
1616     lwip_poll_list.poll = poll;
1617     lwip_poll_list.poll_arg = poll_arg;
1618 }
1619 
mod_lwip_deregister_poll(void (* poll)(void * arg),void * poll_arg)1620 void mod_lwip_deregister_poll(void (*poll)(void *arg), void *poll_arg) {
1621     lwip_poll_list.poll = NULL;
1622 }
1623 
1624 /******************************************************************************/
1625 // The lwip global functions.
1626 
mod_lwip_reset()1627 STATIC mp_obj_t mod_lwip_reset() {
1628     lwip_init();
1629     lwip_poll_list.poll = NULL;
1630     return mp_const_none;
1631 }
1632 MP_DEFINE_CONST_FUN_OBJ_0(mod_lwip_reset_obj, mod_lwip_reset);
1633 
mod_lwip_callback()1634 STATIC mp_obj_t mod_lwip_callback() {
1635     if (lwip_poll_list.poll != NULL) {
1636         lwip_poll_list.poll(lwip_poll_list.poll_arg);
1637     }
1638     sys_check_timeouts();
1639     return mp_const_none;
1640 }
1641 MP_DEFINE_CONST_FUN_OBJ_0(mod_lwip_callback_obj, mod_lwip_callback);
1642 
1643 typedef struct _getaddrinfo_state_t {
1644     volatile int status;
1645     volatile ip_addr_t ipaddr;
1646 } getaddrinfo_state_t;
1647 
1648 // Callback for incoming DNS requests.
1649 #if LWIP_VERSION_MAJOR < 2
lwip_getaddrinfo_cb(const char * name,ip_addr_t * ipaddr,void * arg)1650 STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg)
1651 #else
1652 STATIC void lwip_getaddrinfo_cb(const char *name, const ip_addr_t *ipaddr, void *arg)
1653 #endif
1654 {
1655     getaddrinfo_state_t *state = arg;
1656     if (ipaddr != NULL) {
1657         state->status = 1;
1658         state->ipaddr = *ipaddr;
1659     } else {
1660         // error
1661         state->status = -2;
1662     }
1663 }
1664 
1665 // lwip.getaddrinfo
lwip_getaddrinfo(size_t n_args,const mp_obj_t * args)1666 STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) {
1667     mp_obj_t host_in = args[0], port_in = args[1];
1668     const char *host = mp_obj_str_get_str(host_in);
1669     mp_int_t port = mp_obj_get_int(port_in);
1670 
1671     // If constraints were passed then check they are compatible with the supported params
1672     if (n_args > 2) {
1673         mp_int_t family = mp_obj_get_int(args[2]);
1674         mp_int_t type = 0;
1675         mp_int_t proto = 0;
1676         mp_int_t flags = 0;
1677         if (n_args > 3) {
1678             type = mp_obj_get_int(args[3]);
1679             if (n_args > 4) {
1680                 proto = mp_obj_get_int(args[4]);
1681                 if (n_args > 5) {
1682                     flags = mp_obj_get_int(args[5]);
1683                 }
1684             }
1685         }
1686         if (!((family == 0 || family == MOD_NETWORK_AF_INET)
1687               && (type == 0 || type == MOD_NETWORK_SOCK_STREAM)
1688               && proto == 0
1689               && flags == 0)) {
1690             mp_warning(MP_WARN_CAT(RuntimeWarning), "unsupported getaddrinfo constraints");
1691         }
1692     }
1693 
1694     getaddrinfo_state_t state;
1695     state.status = 0;
1696 
1697     MICROPY_PY_LWIP_ENTER
1698     err_t ret = dns_gethostbyname(host, (ip_addr_t *)&state.ipaddr, lwip_getaddrinfo_cb, &state);
1699     MICROPY_PY_LWIP_EXIT
1700 
1701     switch (ret) {
1702         case ERR_OK:
1703             // cached
1704             state.status = 1;
1705             break;
1706         case ERR_INPROGRESS:
1707             while (state.status == 0) {
1708                 poll_sockets();
1709             }
1710             break;
1711         default:
1712             state.status = ret;
1713     }
1714 
1715     if (state.status < 0) {
1716         // TODO: CPython raises gaierror, we raise with native lwIP negative error
1717         // values, to differentiate from normal errno's at least in such way.
1718         mp_raise_OSError(state.status);
1719     }
1720 
1721     mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL));
1722     tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);
1723     tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);
1724     tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
1725     tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
1726     tuple->items[4] = netutils_format_inet_addr((uint8_t *)&state.ipaddr, port, NETUTILS_BIG);
1727     return mp_obj_new_list(1, (mp_obj_t *)&tuple);
1728 }
1729 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo);
1730 
1731 // Debug functions
1732 
lwip_print_pcbs()1733 STATIC mp_obj_t lwip_print_pcbs() {
1734     tcp_debug_print_pcbs();
1735     return mp_const_none;
1736 }
1737 MP_DEFINE_CONST_FUN_OBJ_0(lwip_print_pcbs_obj, lwip_print_pcbs);
1738 
1739 #if MICROPY_PY_LWIP
1740 
1741 STATIC const mp_rom_map_elem_t mp_module_lwip_globals_table[] = {
1742     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_lwip) },
1743     { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&mod_lwip_reset_obj) },
1744     { MP_ROM_QSTR(MP_QSTR_callback), MP_ROM_PTR(&mod_lwip_callback_obj) },
1745     { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&lwip_getaddrinfo_obj) },
1746     { MP_ROM_QSTR(MP_QSTR_print_pcbs), MP_ROM_PTR(&lwip_print_pcbs_obj) },
1747     // objects
1748     { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&lwip_socket_type) },
1749     #ifdef MICROPY_PY_LWIP_SLIP
1750     { MP_ROM_QSTR(MP_QSTR_slip), MP_ROM_PTR(&lwip_slip_type) },
1751     #endif
1752     // class constants
1753     { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(MOD_NETWORK_AF_INET) },
1754     { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(MOD_NETWORK_AF_INET6) },
1755 
1756     { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(MOD_NETWORK_SOCK_STREAM) },
1757     { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(MOD_NETWORK_SOCK_DGRAM) },
1758     #if MICROPY_PY_LWIP_SOCK_RAW
1759     { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(MOD_NETWORK_SOCK_RAW) },
1760     #endif
1761 
1762     { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(1) },
1763     { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SOF_REUSEADDR) },
1764 
1765     { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(0) },
1766     { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) },
1767 };
1768 
1769 STATIC MP_DEFINE_CONST_DICT(mp_module_lwip_globals, mp_module_lwip_globals_table);
1770 
1771 const mp_obj_module_t mp_module_lwip = {
1772     .base = { &mp_type_module },
1773     .globals = (mp_obj_dict_t *)&mp_module_lwip_globals,
1774 };
1775 
1776 #endif // MICROPY_PY_LWIP
1777