Implement DNS resolution

```
>>> s = socketpool.SocketPool(wifi.radio)
>>> s.getaddrinfo("google.com", 80)
[(0, 0, 0, '', ('142.250.81.206', 80))]
```
This commit is contained in:
Jeff Epler 2022-09-17 09:01:31 -05:00
parent 6c3cdceb45
commit a7a1bd7880
No known key found for this signature in database
GPG Key ID: D5BF15AB975AB4DE
12 changed files with 446 additions and 12 deletions

View File

@ -79,6 +79,7 @@ SRC_SDK_CYW43 := \
src/rp2_common/pico_lwip/random.c \
SRC_LWIP := \
shared/netutils/netutils.c \
$(wildcard sdk/lib/lwip/src/core/*.c) \
$(wildcard sdk/lib/lwip/src/core/ipv4/*.c) \
sdk/lib/lwip/src/netif/ethernet.c \

View File

@ -15,7 +15,7 @@ CIRCUITPY_SSL = 0
CIRCUITPY_HASHLIB = 0
CIRCUITPY_WEB_WORKFLOW = 0
CIRCUITPY_MDNS = 0
CIRCUITPY_SOCKETPOOL = 0
CIRCUITPY_SOCKETPOOL = 1
CIRCUITPY_WIFI = 1
CFLAGS += -DCYW43_PIN_WL_HOST_WAKE=24 -DCYW43_PIN_WL_REG_ON=23 -DCYW43_WL_GPIO_COUNT=3 -DCYW43_WL_GPIO_LED_PIN=0

View File

@ -0,0 +1,165 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Lucian Copeland for Adafruit Industries
*
* 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 "shared-bindings/socketpool/Socket.h"
#include "shared/runtime/interrupt_char.h"
#include "py/mperrno.h"
#include "py/runtime.h"
#include "shared-bindings/socketpool/SocketPool.h"
#include "supervisor/port.h"
#include "supervisor/shared/tick.h"
#include "supervisor/workflow.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#define MAX_SOCKETS (8)
STATIC mp_obj_t open_socket_objs[MAX_SOCKETS];
STATIC bool user_socket[MAX_SOCKETS];
void socket_user_reset(void) {
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_objs); i++) {
if (open_socket_objs[i] && user_socket[i]) {
// shut 'er down
}
}
}
// The writes below send an event to the socket select task so that it redoes the
// select with the new open socket set.
STATIC bool register_open_socket(mp_obj_t obj) {
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_objs); i++) {
if (!open_socket_objs[i]) {
open_socket_objs[i] = obj;
user_socket[i] = false;
return true;
}
}
return false;
}
STATIC void unregister_open_socket(mp_obj_t obj) {
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_objs); i++) {
if (open_socket_objs[i] == obj) {
open_socket_objs[i] = NULL;
user_socket[i] = false;
}
}
}
STATIC void mark_user_socket(mp_obj_t obj) {
for (size_t i = 0; i < MP_ARRAY_SIZE(open_socket_objs); i++) {
if (open_socket_objs[i] == obj) {
user_socket[i] = true;
return;
}
}
}
bool socketpool_socket(socketpool_socketpool_obj_t *self,
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type,
socketpool_socket_obj_t *sock) {
mp_raise_NotImplementedError(NULL);
}
socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_t *self,
socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type) {
mp_raise_NotImplementedError(NULL);
}
int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_t *port) {
mp_raise_NotImplementedError(NULL);
}
socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *self,
uint8_t *ip, uint32_t *port) {
mp_raise_NotImplementedError(NULL);
}
bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self,
const char *host, size_t hostlen, uint32_t port) {
mp_raise_NotImplementedError(NULL);
}
void socketpool_socket_close(socketpool_socket_obj_t *self) {
mp_raise_NotImplementedError(NULL);
}
void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self) {
mp_raise_NotImplementedError(NULL);
}
void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self,
const char *host, size_t hostlen, uint32_t port) {
mp_raise_NotImplementedError(NULL);
}
bool common_hal_socketpool_socket_get_closed(socketpool_socket_obj_t *self) {
mp_raise_NotImplementedError(NULL);
}
bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t *self) {
mp_raise_NotImplementedError(NULL);
}
bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *self, int backlog) {
mp_raise_NotImplementedError(NULL);
}
mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *self,
uint8_t *buf, uint32_t len, uint8_t *ip, uint32_t *port) {
mp_raise_NotImplementedError(NULL);
}
int socketpool_socket_recv_into(socketpool_socket_obj_t *self,
const uint8_t *buf, uint32_t len) {
mp_raise_NotImplementedError(NULL);
}
mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t *self, const uint8_t *buf, uint32_t len) {
mp_raise_NotImplementedError(NULL);
}
int socketpool_socket_send(socketpool_socket_obj_t *self, const uint8_t *buf, uint32_t len) {
mp_raise_NotImplementedError(NULL);
}
mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t *self, const uint8_t *buf, uint32_t len) {
mp_raise_NotImplementedError(NULL);
}
mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t *self,
const char *host, size_t hostlen, uint32_t port, const uint8_t *buf, uint32_t len) {
mp_raise_NotImplementedError(NULL);
}
void common_hal_socketpool_socket_settimeout(socketpool_socket_obj_t *self, uint32_t timeout_ms) {
mp_raise_NotImplementedError(NULL);
}

View File

@ -0,0 +1,77 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2013-2019 Damien P. George
* Copyright (c) 2015 Galen Hazelwood
* Copyright (c) 2015-2017 Paul Sokolovsky
* Copyright (c) 2022 Jeff Epler for Adafruit Industries
*
* 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.
*/
#pragma once
#include "py/obj.h"
#include "common-hal/socketpool/SocketPool.h"
typedef struct _lwip_socket_obj_t {
mp_obj_base_t base;
volatile union {
struct tcp_pcb *tcp;
struct udp_pcb *udp;
struct raw_pcb *raw;
} pcb;
volatile union {
struct pbuf *pbuf;
struct {
uint8_t alloc;
uint8_t iget;
uint8_t iput;
union {
struct tcp_pcb *item; // if alloc == 0
struct tcp_pcb **array; // if alloc != 0
} tcp;
} connection;
} incoming;
mp_obj_t callback;
byte peer[4];
mp_uint_t peer_port;
mp_uint_t timeout;
uint16_t recv_offset;
uint8_t domain;
uint8_t type;
#define STATE_NEW 0
#define STATE_LISTENING 1
#define STATE_CONNECTING 2
#define STATE_CONNECTED 3
#define STATE_PEER_CLOSED 4
#define STATE_ACTIVE_UDP 5
// Negative value is lwIP error
int8_t state;
socketpool_socketpool_obj_t *pool;
} socketpool_socket_obj_t;
void socket_user_reset(void);

View File

@ -0,0 +1,97 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
*
* 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 "shared-bindings/socketpool/SocketPool.h"
#include "common-hal/socketpool/Socket.h"
#include "shared/runtime/interrupt_char.h"
#include "py/runtime.h"
#include "shared-bindings/wifi/__init__.h"
#include "lwip/dns.h"
#include "lwip/inet.h"
void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *self, mp_obj_t radio) {
if (radio != MP_OBJ_FROM_PTR(&common_hal_wifi_radio_obj)) {
mp_raise_ValueError(translate("SocketPool can only be used with wifi.radio"));
}
}
// common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking.
typedef struct _getaddrinfo_state_t {
volatile int status;
volatile ip_addr_t ipaddr;
} getaddrinfo_state_t;
STATIC void lwip_getaddrinfo_cb(const char *name, const 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;
}
}
mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self,
const char *host) {
getaddrinfo_state_t state;
state.status = 0;
MICROPY_PY_LWIP_ENTER
err_t ret = dns_gethostbyname(host, (ip_addr_t *)&state.ipaddr, lwip_getaddrinfo_cb, &state);
MICROPY_PY_LWIP_EXIT
switch (ret) {
case ERR_OK:
// cached
state.status = 1;
break;
case ERR_INPROGRESS:
while (state.status == 0) {
RUN_BACKGROUND_TASKS;
if (mp_hal_is_interrupted()) {
break;
}
}
break;
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.
mp_raise_OSError(state.status);
}
char ip_str[IP4ADDR_STRLEN_MAX];
inet_ntoa_r(state.ipaddr, ip_str, IP4ADDR_STRLEN_MAX);
mp_obj_t ip_obj = mp_obj_new_str(ip_str, strlen(ip_str));
return ip_obj;
}

View File

@ -0,0 +1,33 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
*
* 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.
*/
#pragma once
#include "py/obj.h"
typedef struct {
mp_obj_base_t base;
} socketpool_socketpool_obj_t;

View File

@ -0,0 +1,33 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
*
* 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 "shared-bindings/socketpool/__init__.h"
#include "common-hal/socketpool/Socket.h"
void socketpool_user_reset(void) {
socket_user_reset();
}

View File

@ -0,0 +1,27 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Scott Shawcroft for Adafruit Industries
*
* 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.
*/
#pragma once

View File

@ -271,17 +271,17 @@ mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address,
ipaddress_ipaddress_to_lwip(ip_address, &ping_addr);
struct raw_pcb *ping_pcb;
MICROPY_PY_LWIP_ENTER();
ping_pcb = raw_new(IP_PROTO_ICMP);
MICROPY_PY_LWIP_ENTER
ping_pcb = raw_new(IP_PROTO_ICMP);
if (!ping_pcb) {
MICROPY_PY_LWIP_EXIT();
MICROPY_PY_LWIP_EXIT
return -1;
}
raw_recv(ping_pcb, ping_recv, NULL);
raw_bind(ping_pcb, IP_ADDR_ANY);
MICROPY_PY_LWIP_EXIT();
MICROPY_PY_LWIP_EXIT
ping_received = false;
ping_received = false;
ping_send(ping_pcb, &ping_addr);
size_t timeout_ms = (size_t)MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000);
uint64_t start = port_get_raw_ticks(NULL);
@ -298,9 +298,9 @@ mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address,
result = now - start;
}
MICROPY_PY_LWIP_ENTER();
MICROPY_PY_LWIP_ENTER;
raw_remove(ping_pcb);
MICROPY_PY_LWIP_EXIT();
MICROPY_PY_LWIP_EXIT;
return result;
}

View File

@ -89,4 +89,6 @@
#define LWIP_TIMEVAL_PRIVATE 0
#define LWIP_NO_CTYPE_H 1
#endif /* __LWIPOPTS_H__ */

View File

@ -51,10 +51,9 @@
#if CIRCUITPY_CYW43
#include "pico/cyw43_arch.h"
#undef _L // interferes with ulab, indirectly defined in ctype.h, is ulab bug to use identifier _L
#define MICROPY_PY_LWIP_ENTER cyw43_arch_lwip_begin
#define MICROPY_PY_LWIP_ENTER cyw43_arch_lwip_begin();
#define MICROPY_PY_LWIP_REENTER MICROPY_PY_LWIP_ENTER
#define MICROPY_PY_LWIP_EXIT cyw43_arch_lwip_end
#define MICROPY_PY_LWIP_EXIT cyw43_arch_lwip_end();
#endif
#endif // __INCLUDED_MPCONFIGPORT_H

View File

@ -184,7 +184,7 @@ STATIC mp_obj_t socketpool_socket_recvfrom_into(mp_obj_t self_in, mp_obj_t data_
mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_WRITE);
byte ip[4];
mp_uint_t port;
uint32_t port;
mp_int_t ret = common_hal_socketpool_socket_recvfrom_into(self,
(byte *)bufinfo.buf, bufinfo.len, ip, &port);
mp_obj_t tuple_contents[2];