modlwip.c 45.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
 * Copyright (c) 2015 Galen Hazelwood
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <string.h>
29
#include <stdio.h>
30
31
32
33

#include "py/nlr.h"
#include "py/objlist.h"
#include "py/runtime.h"
34
#include "py/stream.h"
35
#include "py/mperrno.h"
36
#include "py/mphal.h"
37
38
39
40
41
42
43
44
45

#include "netutils.h"

#include "lwip/init.h"
#include "lwip/timers.h"
#include "lwip/tcp.h"
#include "lwip/udp.h"
//#include "lwip/raw.h"
#include "lwip/dns.h"
46
#include "lwip/tcp_impl.h"
47

48
49
50
51
52
53
#if 0 // print debugging info
#define DEBUG_printf DEBUG_printf
#else // don't print debugging info
#define DEBUG_printf(...) (void)0
#endif

54
55
56
57
// For compatibilily with older lwIP versions.
#ifndef ip_set_option
#define ip_set_option(pcb, opt)   ((pcb)->so_options |= (opt))
#endif
58
59
60
#ifndef ip_reset_option
#define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt))
#endif
61

62
63
#ifdef MICROPY_PY_LWIP_SLIP
#include "netif/slipif.h"
64
#include "lwip/sio.h"
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#endif

#ifdef MICROPY_PY_LWIP_SLIP
/******************************************************************************/
// Slip object for modlwip. Requires a serial driver for the port that supports
// the lwip serial callback functions.

typedef struct _lwip_slip_obj_t {
    mp_obj_base_t base;
    struct netif lwip_netif;
} lwip_slip_obj_t;

// Slip object is unique for now. Possibly can fix this later. FIXME
STATIC lwip_slip_obj_t lwip_slip_obj;

// Declare these early.
81
82
void mod_lwip_register_poll(void (*poll)(void *arg), void *poll_arg);
void mod_lwip_deregister_poll(void (*poll)(void *arg), void *poll_arg);
83
84

STATIC void slip_lwip_poll(void *netif) {
85
    slipif_poll((struct netif*)netif);
86
87
88
89
}

STATIC const mp_obj_type_t lwip_slip_type;

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// lwIP SLIP callback functions
sio_fd_t sio_open(u8_t dvnum) {
    // We support singleton SLIP interface, so just return any truish value.
    return (sio_fd_t)1;
}

void sio_send(u8_t c, sio_fd_t fd) {
    mp_obj_type_t *type = mp_obj_get_type(MP_STATE_VM(lwip_slip_stream));
    int error;
    type->stream_p->write(MP_STATE_VM(lwip_slip_stream), &c, 1, &error);
}

u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len) {
    mp_obj_type_t *type = mp_obj_get_type(MP_STATE_VM(lwip_slip_stream));
    int error;
    mp_uint_t out_sz = type->stream_p->read(MP_STATE_VM(lwip_slip_stream), data, len, &error);
    if (out_sz == MP_STREAM_ERROR) {
        if (mp_is_nonblocking_error(error)) {
            return 0;
        }
        // Can't do much else, can we?
        return 0;
    }
    return out_sz;
}

116
117
118
119
120
121
// constructor lwip.slip(device=integer, iplocal=string, ipremote=string)
STATIC mp_obj_t lwip_slip_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
    mp_arg_check_num(n_args, n_kw, 3, 3, false);

    lwip_slip_obj.base.type = &lwip_slip_type;

122
    MP_STATE_VM(lwip_slip_stream) = args[0];
123
124
125
126
127
128
129
130
131

    ip_addr_t iplocal, ipremote;
    if (!ipaddr_aton(mp_obj_str_get_str(args[1]), &iplocal)) {
        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "not a valid local IP"));
    }
    if (!ipaddr_aton(mp_obj_str_get_str(args[2]), &ipremote)) {
        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "not a valid remote IP"));
    }

132
    struct netif *n = &lwip_slip_obj.lwip_netif;
133
    if (netif_add(n, &iplocal, IP_ADDR_BROADCAST, &ipremote, NULL, slipif_init, ip_input) == NULL) {
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
       nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "out of memory"));
    }
    netif_set_up(n);
    netif_set_default(n);
    mod_lwip_register_poll(slip_lwip_poll, n);

    return (mp_obj_t)&lwip_slip_obj;
}

STATIC mp_obj_t lwip_slip_status(mp_obj_t self_in) {
    // Null function for now.
    return mp_const_none;
}

STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_slip_status_obj, lwip_slip_status);

STATIC const mp_map_elem_t lwip_slip_locals_dict_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR_status), (mp_obj_t)&lwip_slip_status_obj },
};

STATIC MP_DEFINE_CONST_DICT(lwip_slip_locals_dict, lwip_slip_locals_dict_table);

STATIC const mp_obj_type_t lwip_slip_type = {
    { &mp_type_type },
    .name = MP_QSTR_slip,
    .make_new = lwip_slip_make_new,
    .locals_dict = (mp_obj_t)&lwip_slip_locals_dict,
};

#endif // MICROPY_PY_LWIP_SLIP

/******************************************************************************/
// Table to convert lwIP err_t codes to socket errno codes, from the lwIP
// socket API.

169
170
// Extension to lwIP error codes
#define _ERR_BADF -16
171
172
173
// TODO: We just know that change happened somewhere between 1.4.0 and 1.4.1,
// investigate in more detail.
#if LWIP_VERSION < 0x01040100
174
static const int error_lookup_table[] = {
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
    0,                /* ERR_OK          0      No error, everything OK. */
    MP_ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */
    MP_ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */
    MP_EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */
    MP_EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */
    MP_EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
    MP_EINVAL,        /* ERR_VAL        -6      Illegal value.           */
    MP_EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */

    MP_ECONNABORTED,  /* ERR_ABRT       -8      Connection aborted.      */
    MP_ECONNRESET,    /* ERR_RST        -9      Connection reset.        */
    MP_ENOTCONN,      /* ERR_CLSD       -10     Connection closed.       */
    MP_ENOTCONN,      /* ERR_CONN       -11     Not connected.           */
    MP_EIO,           /* ERR_ARG        -12     Illegal argument.        */
    MP_EADDRINUSE,    /* ERR_USE        -13     Address in use.          */
    -1,               /* ERR_IF         -14     Low-level netif error    */
    MP_EALREADY,      /* ERR_ISCONN     -15     Already connected.       */
    MP_EBADF,         /* _ERR_BADF      -16     Closed socket (null pcb) */
193
194
195
};
#else
static const int error_lookup_table[] = {
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
    0,                /* ERR_OK          0      No error, everything OK. */
    MP_ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */
    MP_ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */
    MP_EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */
    MP_EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */
    MP_EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
    MP_EINVAL,        /* ERR_VAL        -6      Illegal value.           */
    MP_EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */

    MP_EADDRINUSE,    /* ERR_USE        -8      Address in use.          */
    MP_EALREADY,      /* ERR_ISCONN     -9      Already connected.       */
    MP_ECONNABORTED,  /* ERR_ABRT       -10     Connection aborted.      */
    MP_ECONNRESET,    /* ERR_RST        -11     Connection reset.        */
    MP_ENOTCONN,      /* ERR_CLSD       -12     Connection closed.       */
    MP_ENOTCONN,      /* ERR_CONN       -13     Not connected.           */
    MP_EIO,           /* ERR_ARG        -14     Illegal argument.        */
    -1,               /* ERR_IF         -15     Low-level netif error    */
    MP_EBADF,         /* _ERR_BADF      -16     Closed socket (null pcb) */
214
};
215
#endif
216
217
218
219
220
221
222
223
224
225
226
227
228
229

/*******************************************************************************/
// The socket object provided by lwip.socket.

#define MOD_NETWORK_AF_INET (2)
#define MOD_NETWORK_AF_INET6 (10)

#define MOD_NETWORK_SOCK_STREAM (1)
#define MOD_NETWORK_SOCK_DGRAM (2)
#define MOD_NETWORK_SOCK_RAW (3)

typedef struct _lwip_socket_obj_t {
    mp_obj_base_t base;

230
    volatile union {
231
232
233
        struct tcp_pcb *tcp;
        struct udp_pcb *udp;
    } pcb;
234
    volatile union {
235
236
237
        struct pbuf *pbuf;
        struct tcp_pcb *connection;
    } incoming;
238
    mp_obj_t callback;
239
240
241
    byte peer[4];
    mp_uint_t peer_port;
    mp_uint_t timeout;
242
    uint16_t recv_offset;
243
244
245
246

    uint8_t domain;
    uint8_t type;

247
248
249
250
251
252
    #define STATE_NEW 0
    #define STATE_CONNECTING 1
    #define STATE_CONNECTED 2
    #define STATE_PEER_CLOSED 3
    // Negative value is lwIP error
    int8_t state;
253
254
} lwip_socket_obj_t;

255
static inline void poll_sockets(void) {
256
257
258
#ifdef MICROPY_EVENT_POLL_HOOK
    MICROPY_EVENT_POLL_HOOK;
#else
259
    mp_hal_delay_ms(1);
260
#endif
261
262
}

263
264
265
/*******************************************************************************/
// Callback functions for the lwIP raw API.

266
267
static inline void exec_user_callback(lwip_socket_obj_t *socket) {
    if (socket->callback != MP_OBJ_NULL) {
268
        mp_call_function_1_protected(socket->callback, socket);
269
270
271
    }
}

272
273
274
// Callback for incoming UDP packets. We simply stash the packet and the source address,
// in case we need it for recvfrom.
STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) {
275
    lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
276

277
    if (socket->incoming.pbuf != NULL) {
278
279
280
        // That's why they call it "unreliable". No room in the inn, drop the packet.
        pbuf_free(p);
    } else {
281
        socket->incoming.pbuf = p;
282
        socket->peer_port = (mp_uint_t)port;
283
        memcpy(&socket->peer, addr, sizeof(socket->peer));
284
285
286
287
288
    }
}

// Callback for general tcp errors.
STATIC void _lwip_tcp_error(void *arg, err_t err) {
289
    lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
290
291

    // Pass the error code back via the connection variable.
292
    socket->state = err;
293
    // If we got here, the lwIP stack either has deallocated or will deallocate the pcb.
294
    socket->pcb.tcp = NULL;
295
296
297
298
}

// Callback for tcp connection requests. Error code err is unused. (See tcp.h)
STATIC err_t _lwip_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) {
299
    lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
300

301
    socket->state = STATE_CONNECTED;
302
303
304
    return ERR_OK;
}

305
306
307
308
309
310
311
312
313
// By default, a child socket of listen socket is created with recv
// handler which discards incoming pbuf's. We don't want to do that,
// so set this handler which requests lwIP to keep pbuf's and deliver
// them later. We cannot cache pbufs in child socket on Python side,
// until it is created in accept().
STATIC err_t _lwip_tcp_recv_unaccepted(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) {
    return ERR_BUF;
}

314
315
316
317
318
319
320
321
322
323
324
// "Poll" (idle) callback to be called ASAP after accept callback
// to execute Python callback function, as it can't be executed
// from accept callback itself.
STATIC err_t _lwip_tcp_accept_finished(void *arg, struct tcp_pcb *pcb)
{
    lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
    tcp_poll(pcb, NULL, 0);
    exec_user_callback(socket);
    return ERR_OK;
}

325
326
// Callback for incoming tcp connections.
STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
327
    lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
328
    tcp_recv(newpcb, _lwip_tcp_recv_unaccepted);
329

330
    if (socket->incoming.connection != NULL) {
331
        DEBUG_printf("_lwip_tcp_accept: Tried to queue >1 pcb waiting for accept\n");
332
333
334
335
        // We need to handle this better. This single-level structure makes the
        // backlog setting kind of pointless. FIXME
        return ERR_BUF;
    } else {
336
        socket->incoming.connection = newpcb;
337
338
339
340
341
342
        if (socket->callback != MP_OBJ_NULL) {
            // Schedule accept callback to be called when lwIP is done
            // with processing this incoming connection on its side and
            // is idle.
            tcp_poll(newpcb, _lwip_tcp_accept_finished, 1);
        }
343
344
345
346
347
348
        return ERR_OK;
    }
}

// Callback for inbound tcp packets.
STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err_t err) {
349
    lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
350
351
352

    if (p == NULL) {
        // Other side has closed connection.
353
        DEBUG_printf("_lwip_tcp_recv[%p]: other side closed connection\n", socket);
354
        socket->state = STATE_PEER_CLOSED;
355
        exec_user_callback(socket);
356
        return ERR_OK;
357
358
359
360
361
362
    }

    if (socket->incoming.pbuf == NULL) {
        socket->incoming.pbuf = p;
    } else {
        #ifdef SOCKET_SINGLE_PBUF
363
        return ERR_BUF;
364
365
366
        #else
        pbuf_cat(socket->incoming.pbuf, p);
        #endif
367
    }
368
369
370

    exec_user_callback(socket);

371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
    return ERR_OK;
}

/*******************************************************************************/
// Functions for socket send/recieve operations. Socket send/recv and friends call
// these to do the work.

// Helper function for send/sendto to handle UDP packets.
STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
    if (len > 0xffff) {
        // Any packet that big is probably going to fail the pbuf_alloc anyway, but may as well try
        len = 0xffff;
    }

    // FIXME: maybe PBUF_ROM?
    struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
    if (p == NULL) {
388
        *_errno = MP_ENOMEM;
389
390
391
392
393
394
395
        return -1;
    }

    memcpy(p->payload, buf, len);

    err_t err;
    if (ip == NULL) {
396
        err = udp_send(socket->pcb.udp, p);
397
398
399
    } else {
        ip_addr_t dest;
        IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]);
400
        err = udp_sendto(socket->pcb.udp, p, &dest, port);
401
402
403
404
    }

    pbuf_free(p);

405
406
407
408
    // udp_sendto can return 1 on occasion for ESP8266 port.  It's not known why
    // but it seems that the send actually goes through without error in this case.
    // So we treat such cases as a success until further investigation.
    if (err != ERR_OK && err != 1) {
409
410
411
412
413
414
415
416
417
418
        *_errno = error_lookup_table[-err];
        return -1;
    }

    return len;
}

// Helper function for recv/recvfrom to handle UDP packets
STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {

419
    if (socket->incoming.pbuf == NULL) {
420
421
        if (socket->timeout != -1) {
            for (mp_uint_t retries = socket->timeout / 100; retries--;) {
422
                mp_hal_delay_ms(100);
423
                if (socket->incoming.pbuf != NULL) break;
424
            }
425
            if (socket->incoming.pbuf == NULL) {
426
                *_errno = MP_ETIMEDOUT;
427
428
429
                return -1;
            }
        } else {
430
            while (socket->incoming.pbuf == NULL) {
431
                poll_sockets();
432
433
434
435
436
            }
        }
    }

    if (ip != NULL) {
437
        memcpy(ip, &socket->peer, sizeof(socket->peer));
438
439
440
        *port = socket->peer_port;
    }

441
    struct pbuf *p = socket->incoming.pbuf;
442
443
444

    u16_t result = pbuf_copy_partial(p, buf, ((p->tot_len > len) ? len : p->tot_len), 0);
    pbuf_free(p);
445
    socket->incoming.pbuf = NULL;
446
447
448
449

    return (mp_uint_t) result;
}

450
451
452
453
454
455
456
457
458
// For use in stream virtual methods
#define STREAM_ERROR_CHECK(socket) \
        if (socket->state < 0) { \
            *_errno = error_lookup_table[-socket->state]; \
            return MP_STREAM_ERROR; \
        } \
        assert(socket->pcb.tcp);


459
// Helper function for send/sendto to handle TCP packets
460
STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
461
462
463
    // Check for any pending errors
    STREAM_ERROR_CHECK(socket);

464
    u16_t available = tcp_sndbuf(socket->pcb.tcp);
465
466
467
468

    if (available == 0) {
        // Non-blocking socket
        if (socket->timeout == 0) {
469
            *_errno = MP_EAGAIN;
470
            return MP_STREAM_ERROR;
471
472
473
474
475
476
477
478
479
480
481
        }

        mp_uint_t start = mp_hal_ticks_ms();
        // Assume that STATE_PEER_CLOSED may mean half-closed connection, where peer closed it
        // sending direction, but not receiving. Consequently, check for both STATE_CONNECTED
        // and STATE_PEER_CLOSED as normal conditions and still waiting for buffers to be sent.
        // If peer fully closed socket, we would have socket->state set to ERR_RST (connection
        // reset) by error callback.
        // Avoid sending too small packets, so wait until at least 16 bytes available
        while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) {
            if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
482
                *_errno = MP_ETIMEDOUT;
483
                return MP_STREAM_ERROR;
484
485
486
487
            }
            poll_sockets();
        }

488
489
        // While we waited, something could happen
        STREAM_ERROR_CHECK(socket);
490
491
    }

492
    u16_t write_len = MIN(available, len);
493

494
    err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY);
495
496
497

    if (err != ERR_OK) {
        *_errno = error_lookup_table[-err];
498
        return MP_STREAM_ERROR;
499
500
    }

501
    return write_len;
502
503
504
505
}

// Helper function for recv/recvfrom to handle TCP packets
STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
506
507
508
    // Check for any pending errors
    STREAM_ERROR_CHECK(socket);

509
    if (socket->incoming.pbuf == NULL) {
510
511
512

        // Non-blocking socket
        if (socket->timeout == 0) {
513
514
515
            if (socket->state == STATE_PEER_CLOSED) {
                return 0;
            }
516
            *_errno = MP_EAGAIN;
517
518
519
            return -1;
        }

520
        mp_uint_t start = mp_hal_ticks_ms();
521
        while (socket->state == STATE_CONNECTED && socket->incoming.pbuf == NULL) {
522
            if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
523
                *_errno = MP_ETIMEDOUT;
524
525
                return -1;
            }
526
            poll_sockets();
527
        }
528

529
        if (socket->state == STATE_PEER_CLOSED) {
530
531
532
533
            if (socket->incoming.pbuf == NULL) {
                // socket closed and no data left in buffer
                return 0;
            }
534
        } else if (socket->state != STATE_CONNECTED) {
535
536
            assert(socket->state < 0);
            *_errno = error_lookup_table[-socket->state];
537
538
            return -1;
        }
539
540
    }

541
542
    assert(socket->pcb.tcp != NULL);

543
    struct pbuf *p = socket->incoming.pbuf;
544

545
546
547
    mp_uint_t remaining = p->len - socket->recv_offset;
    if (len > remaining) {
        len = remaining;
548
549
    }

550
551
552
553
554
555
556
557
558
    memcpy(buf, (byte*)p->payload + socket->recv_offset, len);

    remaining -= len;
    if (remaining == 0) {
        socket->incoming.pbuf = p->next;
        // If we don't ref here, free() will free the entire chain,
        // if we ref, it does what we need: frees 1st buf, and decrements
        // next buf's refcount back to 1.
        pbuf_ref(p->next);
559
        pbuf_free(p);
560
561
562
        socket->recv_offset = 0;
    } else {
        socket->recv_offset += len;
563
    }
564
    tcp_recved(socket->pcb.tcp, len);
565

566
    return len;
567
568
569
570
571
572
573
}

/*******************************************************************************/
// The socket functions provided by lwip.socket.

STATIC const mp_obj_type_t lwip_socket_type;

574
575
STATIC void lwip_socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
    lwip_socket_obj_t *self = self_in;
576
577
    mp_printf(print, "<socket state=%d timeout=%d incoming=%p off=%d>", self->state, self->timeout,
        self->incoming.pbuf, self->recv_offset);
578
579
}

580
// FIXME: Only supports two arguments at present
581
STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args,
582
583
584
585
586
587
588
    mp_uint_t n_kw, const mp_obj_t *args) {
    mp_arg_check_num(n_args, n_kw, 0, 4, false);

    lwip_socket_obj_t *socket = m_new_obj_with_finaliser(lwip_socket_obj_t);
    socket->base.type = (mp_obj_t)&lwip_socket_type;
    socket->domain = MOD_NETWORK_AF_INET;
    socket->type = MOD_NETWORK_SOCK_STREAM;
589
    socket->callback = MP_OBJ_NULL;
590
591
592
593
594
595
596
597
    if (n_args >= 1) {
        socket->domain = mp_obj_get_int(args[0]);
        if (n_args >= 2) {
            socket->type = mp_obj_get_int(args[1]);
        }
    }

    switch (socket->type) {
598
599
600
        case MOD_NETWORK_SOCK_STREAM: socket->pcb.tcp = tcp_new(); break;
        case MOD_NETWORK_SOCK_DGRAM: socket->pcb.udp = udp_new(); break;
        //case MOD_NETWORK_SOCK_RAW: socket->pcb.raw = raw_new(); break;
601
        default: nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL)));
602
603
    }

604
    if (socket->pcb.tcp == NULL) {
605
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM)));
606
607
608
609
610
    }

    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
            // Register the socket object as our callback argument.
611
            tcp_arg(socket->pcb.tcp, (void*)socket);
612
            // Register our error callback.
613
            tcp_err(socket->pcb.tcp, _lwip_tcp_error);
614
615
616
617
618
            break;
        }
        case MOD_NETWORK_SOCK_DGRAM: {
            // Register our receive callback now. Since UDP sockets don't require binding or connection
            // before use, there's no other good time to do it.
619
            udp_recv(socket->pcb.udp, _lwip_udp_incoming, (void*)socket);
620
621
622
623
            break;
        }
    }

624
    socket->incoming.pbuf = NULL;
625
    socket->timeout = -1;
626
    socket->state = STATE_NEW;
627
    socket->recv_offset = 0;
628
629
630
631
632
633
634
    return socket;
}

STATIC mp_obj_t lwip_socket_close(mp_obj_t self_in) {
    lwip_socket_obj_t *socket = self_in;
    bool socket_is_listener = false;

635
    if (socket->pcb.tcp == NULL) {
636
637
638
639
        return mp_const_none;
    }
    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
640
            if (socket->pcb.tcp->state == LISTEN) {
641
642
                socket_is_listener = true;
            }
643
            if (tcp_close(socket->pcb.tcp) != ERR_OK) {
644
                DEBUG_printf("lwip_close: had to call tcp_abort()\n");
645
                tcp_abort(socket->pcb.tcp);
646
647
648
            }
            break;
        }
649
650
        case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break;
        //case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break;
651
    }
652
    socket->pcb.tcp = NULL;
653
    socket->state = _ERR_BADF;
654
    if (socket->incoming.pbuf != NULL) {
655
        if (!socket_is_listener) {
656
            pbuf_free(socket->incoming.pbuf);
657
        } else {
658
            tcp_abort(socket->incoming.connection);
659
        }
660
        socket->incoming.pbuf = NULL;
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
    }

    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_socket_close_obj, lwip_socket_close);

STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
    lwip_socket_obj_t *socket = self_in;

    uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
    mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);

    ip_addr_t bind_addr;
    IP4_ADDR(&bind_addr, ip[0], ip[1], ip[2], ip[3]);

    err_t err = ERR_ARG;
    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
679
            err = tcp_bind(socket->pcb.tcp, &bind_addr, port);
680
681
682
            break;
        }
        case MOD_NETWORK_SOCK_DGRAM: {
683
            err = udp_bind(socket->pcb.udp, &bind_addr, port);
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
            break;
        }
    }

    if (err != ERR_OK) {
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err])));
    }

    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_bind_obj, lwip_socket_bind);

STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) {
    lwip_socket_obj_t *socket = self_in;
    mp_int_t backlog = mp_obj_get_int(backlog_in);

700
    if (socket->pcb.tcp == NULL) {
701
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF)));
702
703
    }
    if (socket->type != MOD_NETWORK_SOCK_STREAM) {
704
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EOPNOTSUPP)));
705
706
    }

707
    struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog);
708
    if (new_pcb == NULL) {
709
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM)));
710
    }
711
    socket->pcb.tcp = new_pcb;
712
713
714
715
716
717
718
719
720
    tcp_accept(new_pcb, _lwip_tcp_accept);

    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen);

STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
    lwip_socket_obj_t *socket = self_in;

721
    if (socket->pcb.tcp == NULL) {
722
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF)));
723
724
    }
    if (socket->type != MOD_NETWORK_SOCK_STREAM) {
725
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EOPNOTSUPP)));
726
727
    }
    // I need to do this because "tcp_accepted", later, is a macro.
728
    struct tcp_pcb *listener = socket->pcb.tcp;
729
    if (listener->state != LISTEN) {
730
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL)));
731
732
733
    }

    // accept incoming connection
734
    if (socket->incoming.connection == NULL) {
735
736
        if (socket->timeout != -1) {
            for (mp_uint_t retries = socket->timeout / 100; retries--;) {
737
                mp_hal_delay_ms(100);
738
                if (socket->incoming.connection != NULL) break;
739
            }
740
            if (socket->incoming.connection == NULL) {
741
                nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT)));
742
743
            }
        } else {
744
            while (socket->incoming.connection == NULL) {
745
                poll_sockets();
746
747
748
749
750
751
752
753
754
            }
        }
    }

    // create new socket object
    lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t);
    socket2->base.type = (mp_obj_t)&lwip_socket_type;

    // We get a new pcb handle...
755
756
    socket2->pcb.tcp = socket->incoming.connection;
    socket->incoming.connection = NULL;
757
758
759
760

    // ...and set up the new socket for it.
    socket2->domain = MOD_NETWORK_AF_INET;
    socket2->type = MOD_NETWORK_SOCK_STREAM;
761
    socket2->incoming.pbuf = NULL;
762
    socket2->timeout = socket->timeout;
763
    socket2->state = STATE_CONNECTED;
764
    socket2->recv_offset = 0;
765
    socket2->callback = MP_OBJ_NULL;
766
767
768
    tcp_arg(socket2->pcb.tcp, (void*)socket2);
    tcp_err(socket2->pcb.tcp, _lwip_tcp_error);
    tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv);
769
770
771
772
773

    tcp_accepted(listener);

    // make the return value
    uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
774
    memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip));
775
    mp_uint_t port = (mp_uint_t)socket2->pcb.tcp->remote_port;
776
777
778
779
780
781
782
783
784
785
786
    mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
    client->items[0] = socket2;
    client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);

    return client;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_socket_accept_obj, lwip_socket_accept);

STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
    lwip_socket_obj_t *socket = self_in;

787
    if (socket->pcb.tcp == NULL) {
788
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EBADF)));
789
790
791
792
793
794
795
796
797
798
799
800
    }

    // get address
    uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
    mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);

    ip_addr_t dest;
    IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]);

    err_t err = ERR_ARG;
    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
801
802
            if (socket->state != STATE_NEW) {
                if (socket->state == STATE_CONNECTED) {
803
                    nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EALREADY)));
804
                } else {
805
                    nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINPROGRESS)));
806
807
808
                }
            }
            // Register our recieve callback.
809
            tcp_recv(socket->pcb.tcp, _lwip_tcp_recv);
810
            socket->state = STATE_CONNECTING;
811
            err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected);
812
            if (err != ERR_OK) {
813
                socket->state = STATE_NEW;
814
815
816
                nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err])));
            }
            socket->peer_port = (mp_uint_t)port;
817
            memcpy(socket->peer, &dest, sizeof(socket->peer));
818
819
820
            // And now we wait...
            if (socket->timeout != -1) {
                for (mp_uint_t retries = socket->timeout / 100; retries--;) {
821
                    mp_hal_delay_ms(100);
822
                    if (socket->state != STATE_CONNECTING) break;
823
                }
824
                if (socket->state == STATE_CONNECTING) {
825
                    nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ETIMEDOUT)));
826
827
                }
            } else {
828
                while (socket->state == STATE_CONNECTING) {
829
                    poll_sockets();
830
831
                }
            }
832
            if (socket->state == STATE_CONNECTED) {
833
834
               err = ERR_OK;
            } else {
835
               err = socket->state;
836
837
838
839
            }
            break;
        }
        case MOD_NETWORK_SOCK_DGRAM: {
840
            err = udp_connect(socket->pcb.udp, &dest, port);
841
842
843
844
845
846
847
848
849
850
851
852
            break;
        }
    }

    if (err != ERR_OK) {
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err])));
    }

    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_connect_obj, lwip_socket_connect);

853
STATIC void lwip_socket_check_connected(lwip_socket_obj_t *socket) {
854
    if (socket->pcb.tcp == NULL) {
855
        // not connected
856
        int _errno = error_lookup_table[-socket->state];
857
        socket->state = _ERR_BADF;
858
859
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
    }
860
861
862
863
864
865
866
}

STATIC mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
    lwip_socket_obj_t *socket = self_in;
    int _errno;

    lwip_socket_check_connected(socket);
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893

    mp_buffer_info_t bufinfo;
    mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);

    mp_uint_t ret = 0;
    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
            ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno);
            break;
        }
        case MOD_NETWORK_SOCK_DGRAM: {
            ret = lwip_udp_send(socket, bufinfo.buf, bufinfo.len, NULL, 0, &_errno);
            break;
        }
    }
    if (ret == -1) {
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
    }

    return mp_obj_new_int_from_uint(ret);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_send_obj, lwip_socket_send);

STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
    lwip_socket_obj_t *socket = self_in;
    int _errno;

894
    lwip_socket_check_connected(socket);
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926

    mp_int_t len = mp_obj_get_int(len_in);
    vstr_t vstr;
    vstr_init_len(&vstr, len);

    mp_uint_t ret = 0;
    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
            ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno);
            break;
        }
        case MOD_NETWORK_SOCK_DGRAM: {
            ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, NULL, NULL, &_errno);
            break;
        }
    }
    if (ret == -1) {
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
    }

    if (ret == 0) {
        return mp_const_empty_bytes;
    }
    vstr.len = ret;
    return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recv_obj, lwip_socket_recv);

STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
    lwip_socket_obj_t *socket = self_in;
    int _errno;

927
    lwip_socket_check_connected(socket);
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957

    mp_buffer_info_t bufinfo;
    mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);

    uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
    mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);

    mp_uint_t ret = 0;
    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
            ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno);
            break;
        }
        case MOD_NETWORK_SOCK_DGRAM: {
            ret = lwip_udp_send(socket, bufinfo.buf, bufinfo.len, ip, port, &_errno);
            break;
        }
    }
    if (ret == -1) {
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
    }

    return mp_obj_new_int_from_uint(ret);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(lwip_socket_sendto_obj, lwip_socket_sendto);

STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
    lwip_socket_obj_t *socket = self_in;
    int _errno;

958
    lwip_socket_check_connected(socket);
959
960
961
962
963
964
965
966
967
968

    mp_int_t len = mp_obj_get_int(len_in);
    vstr_t vstr;
    vstr_init_len(&vstr, len);
    byte ip[4];
    mp_uint_t port;

    mp_uint_t ret = 0;
    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
969
            memcpy(ip, &socket->peer, sizeof(socket->peer));
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
            port = (mp_uint_t) socket->peer_port;
            ret = lwip_tcp_receive(socket, (byte*)vstr.buf, len, &_errno);
            break;
        }
        case MOD_NETWORK_SOCK_DGRAM: {
            ret = lwip_udp_receive(socket, (byte*)vstr.buf, len, ip, &port, &_errno);
            break;
        }
    }
    if (ret == -1) {
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
    }

    mp_obj_t tuple[2];
    if (ret == 0) {
        tuple[0] = mp_const_empty_bytes;
    } else {
        vstr.len = ret;
        tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
    }
    tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
    return mp_obj_new_tuple(2, tuple);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recvfrom_obj, lwip_socket_recvfrom);

995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
    lwip_socket_obj_t *socket = self_in;
    lwip_socket_check_connected(socket);

    int _errno;
    mp_buffer_info_t bufinfo;
    mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);

    mp_uint_t ret = 0;
    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
            if (socket->timeout == 0) {
                // Behavior of sendall() for non-blocking sockets isn't explicitly specified.
                // But it's specified that "On error, an exception is raised, there is no
                // way to determine how much data, if any, was successfully sent." Then, the
                // most useful behavior is: check whether we will be able to send all of input
                // data without EAGAIN, and if won't be, raise it without sending any.
                if (bufinfo.len > tcp_sndbuf(socket->pcb.tcp)) {
1013
                    nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EAGAIN)));
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
                }
            }
            // TODO: In CPython3.5, socket timeout should apply to the
            // entire sendall() operation, not to individual send() chunks.
            while (bufinfo.len != 0) {
                ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno);
                if (ret == -1) {
                    nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
                }
                bufinfo.len -= ret;
                bufinfo.buf = (char*)bufinfo.buf + ret;
            }
            break;
        }
        case MOD_NETWORK_SOCK_DGRAM:
            mp_not_implemented("");
            break;
    }

    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_sendall_obj, lwip_socket_sendall);

1037
1038
1039
1040
1041
1042
STATIC mp_obj_t lwip_socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
    lwip_socket_obj_t *socket = self_in;
    mp_uint_t timeout;
    if (timeout_in == mp_const_none) {
        timeout = -1;
    } else {
1043
        #if MICROPY_PY_BUILTINS_FLOAT
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
        timeout = 1000 * mp_obj_get_float(timeout_in);
        #else
        timeout = 1000 * mp_obj_get_int(timeout_in);
        #endif
    }
    socket->timeout = timeout;
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_settimeout_obj, lwip_socket_settimeout);

1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
STATIC mp_obj_t lwip_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
    lwip_socket_obj_t *socket = self_in;
    bool val = mp_obj_is_true(flag_in);
    if (val) {
        socket->timeout = -1;
    } else {
        socket->timeout = 0;
    }
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_setblocking_obj, lwip_socket_setblocking);

1066
1067
STATIC mp_obj_t lwip_socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) {
    (void)n_args; // always 4
1068
    lwip_socket_obj_t *socket = args[0];
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080

    int opt = mp_obj_get_int(args[2]);
    if (opt == 20) {
        if (args[3] == mp_const_none) {
            socket->callback = MP_OBJ_NULL;
        } else {
            socket->callback = args[3];
        }
        return mp_const_none;
    }

    // Integer options
1081
    mp_int_t val = mp_obj_get_int(args[3]);
1082
    switch (opt) {
1083
1084
        case SOF_REUSEADDR:
            // Options are common for UDP and TCP pcb's.
1085
1086
1087
1088
1089
            if (val) {
                ip_set_option(socket->pcb.tcp, SOF_REUSEADDR);
            } else {
                ip_reset_option(socket->pcb.tcp, SOF_REUSEADDR);
            }
1090
1091
1092
1093
            break;
        default:
            printf("Warning: lwip.setsockopt() not implemented\n");
    }
1094
1095
1096
1097
    return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_setsockopt_obj, 4, 4, lwip_socket_setsockopt);

1098
1099
1100
1101
1102
1103
STATIC mp_obj_t lwip_socket_makefile(mp_uint_t n_args, const mp_obj_t *args) {
    (void)n_args;
    return args[0];
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_makefile_obj, 1, 3, lwip_socket_makefile);

1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
STATIC mp_uint_t lwip_socket_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
    lwip_socket_obj_t *socket = self_in;

    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM:
            return lwip_tcp_receive(socket, buf, size, errcode);
        case MOD_NETWORK_SOCK_DGRAM:
            return lwip_udp_receive(socket, buf, size, NULL, NULL, errcode);
    }
    // Unreachable
    return MP_STREAM_ERROR;
}

1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
STATIC mp_uint_t lwip_socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
    lwip_socket_obj_t *socket = self_in;

    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM:
            return lwip_tcp_send(socket, buf, size, errcode);
        case MOD_NETWORK_SOCK_DGRAM:
            return lwip_udp_send(socket, buf, size, NULL, 0, errcode);
    }
    // Unreachable
    return MP_STREAM_ERROR;
}

1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
STATIC const mp_map_elem_t lwip_socket_locals_dict_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&lwip_socket_close_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&lwip_socket_close_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&lwip_socket_bind_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&lwip_socket_listen_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&lwip_socket_accept_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&lwip_socket_connect_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&lwip_socket_send_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&lwip_socket_recv_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&lwip_socket_sendto_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&lwip_socket_recvfrom_obj },
1141
    { MP_OBJ_NEW_QSTR(MP_QSTR_sendall), (mp_obj_t)&lwip_socket_sendall_obj },
1142
    { MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&lwip_socket_settimeout_obj },
1143
    { MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&lwip_socket_setblocking_obj },
1144
    { MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&lwip_socket_setsockopt_obj },
1145
    { MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&lwip_socket_makefile_obj },
1146
1147
1148

    { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj},
1149
    { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj },
1150
1151
1152
};
STATIC MP_DEFINE_CONST_DICT(lwip_socket_locals_dict, lwip_socket_locals_dict_table);

1153
1154
STATIC const mp_stream_p_t lwip_socket_stream_p = {
    .read = lwip_socket_read,
1155
    .write = lwip_socket_write,
1156
1157
};

1158
1159
1160
STATIC const mp_obj_type_t lwip_socket_type = {
    { &mp_type_type },
    .name = MP_QSTR_socket,
1161
    .print = lwip_socket_print,
1162
    .make_new = lwip_socket_make_new,
1163
    .protocol = &lwip_socket_stream_p,
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
    .locals_dict = (mp_obj_t)&lwip_socket_locals_dict,
};

/******************************************************************************/
// Support functions for memory protection. lwIP has its own memory management
// routines for its internal structures, and since they might be called in
// interrupt handlers, they need some protection.
sys_prot_t sys_arch_protect() {
    return (sys_prot_t)MICROPY_BEGIN_ATOMIC_SECTION();
}

void sys_arch_unprotect(sys_prot_t state) {
    MICROPY_END_ATOMIC_SECTION((mp_uint_t)state);
}

/******************************************************************************/
// Polling callbacks for the interfaces connected to lwIP. Right now it calls
// itself a "list" but isn't; we only support a single interface.

typedef struct nic_poll {
    void (* poll)(void *arg);
    void *poll_arg;
} nic_poll_t;

STATIC nic_poll_t lwip_poll_list;

void mod_lwip_register_poll(void (* poll)(void *arg), void *poll_arg) {
    lwip_poll_list.poll = poll;
    lwip_poll_list.poll_arg = poll_arg;
}

void mod_lwip_deregister_poll(void (* poll)(void *arg), void *poll_arg) {
    lwip_poll_list.poll = NULL;
}

/******************************************************************************/
// The lwip global functions.

STATIC mp_obj_t mod_lwip_reset() {
    lwip_init();
    lwip_poll_list.poll = NULL;
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(mod_lwip_reset_obj, mod_lwip_reset);

STATIC mp_obj_t mod_lwip_callback() {
    if (lwip_poll_list.poll != NULL) {
        lwip_poll_list.poll(lwip_poll_list.poll_arg);
    }
    sys_check_timeouts();
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(mod_lwip_callback_obj, mod_lwip_callback);

1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
typedef struct _getaddrinfo_state_t {
    volatile int status;
    volatile ip_addr_t ipaddr;
} getaddrinfo_state_t;

// Callback for incoming DNS requests.
STATIC void lwip_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) {
    getaddrinfo_state_t *state = arg;
    if (ipaddr != NULL) {
        state->status = 1;
        state->ipaddr = *ipaddr;
    } else {
        // error
        state->status = -2;
    }
}

1235
1236
1237
1238
1239
1240
// lwip.getaddrinfo
STATIC mp_obj_t lwip_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) {
    mp_uint_t hlen;
    const char *host = mp_obj_str_get_data(host_in, &hlen);
    mp_int_t port = mp_obj_get_int(port_in);

1241
1242
    getaddrinfo_state_t state;
    state.status = 0;
1243

1244
1245
1246
1247
1248
1249
1250
1251
    err_t ret = dns_gethostbyname(host, (ip_addr_t*)&state.ipaddr, lwip_getaddrinfo_cb, &state);
    switch (ret) {
        case ERR_OK:
            // cached
            state.status = 1;
            break;
        case ERR_INPROGRESS:
            while (state.status == 0) {
1252
                poll_sockets();
1253
1254
            }
            break;
1255
1256
1257
1258
1259
1260
1261
1262
        default:
            state.status = ret;
    }

    if (state.status < 0) {
        // TODO: CPython raises gaierror, we raise with native lwIP negative error
        // values, to differentiate from normal errno's at least in such way.
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(state.status)));
1263
1264
1265
1266
1267
1268
1269
    }

    mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
    tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);
    tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);
    tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
    tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
1270
    tuple->items[4] = netutils_format_inet_addr((uint8_t*)&state.ipaddr, port, NETUTILS_BIG);
1271
1272
1273
1274
    return mp_obj_new_list(1, (mp_obj_t*)&tuple);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_getaddrinfo_obj, lwip_getaddrinfo);

1275
1276
1277
1278
1279
1280
1281
1282
// Debug functions

STATIC mp_obj_t lwip_print_pcbs() {
    tcp_debug_print_pcbs();
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_0(lwip_print_pcbs_obj, lwip_print_pcbs);

1283
1284
1285
1286
1287
1288
1289
#ifdef MICROPY_PY_LWIP

STATIC const mp_map_elem_t mp_module_lwip_globals_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_lwip) },
    { MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&mod_lwip_reset_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&mod_lwip_callback_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&lwip_getaddrinfo_obj },