diff --git a/docs/shared_bindings_matrix.py b/docs/shared_bindings_matrix.py index 0f98a5e16755..33dfad01e986 100644 --- a/docs/shared_bindings_matrix.py +++ b/docs/shared_bindings_matrix.py @@ -85,6 +85,7 @@ "sys": "CIRCUITPY_SYS", "terminalio": "CIRCUITPY_DISPLAYIO", "usb": "CIRCUITPY_PYUSB", + "socketpool.socketpool.AF_INET6": "CIRCUITPY_SOCKETPOOL_IPV6", } MODULES_NOT_IN_BINDINGS = ["binascii", "errno", "json", "re", "ulab"] diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 40fd2e2d5b4d..ed8975e5c0b8 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1562,7 +1562,6 @@ msgstr "" msgid "Only IPv4 addresses supported" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c #: ports/raspberrypi/common-hal/socketpool/Socket.c msgid "Only IPv4 sockets supported" msgstr "" @@ -2224,6 +2223,10 @@ msgstr "" msgid "Unsupported hash algorithm" msgstr "" +#: ports/espressif/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" +msgstr "" + #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/espressif/common-hal/dualbank/__init__.c msgid "Update failed" diff --git a/ports/espressif/boards/lolin_c3_pico/mpconfigboard.mk b/ports/espressif/boards/lolin_c3_pico/mpconfigboard.mk index 51b1adfe5a1d..25027d4c97b8 100644 --- a/ports/espressif/boards/lolin_c3_pico/mpconfigboard.mk +++ b/ports/espressif/boards/lolin_c3_pico/mpconfigboard.mk @@ -11,5 +11,8 @@ CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 +# Not enough flash +CIRCUITPY_SOCKETPOOL_IPV6 = 0 + # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel diff --git a/ports/espressif/boards/lolin_c3_pico/sdkconfig b/ports/espressif/boards/lolin_c3_pico/sdkconfig index 00134fd0f29e..ba2885933e79 100644 --- a/ports/espressif/boards/lolin_c3_pico/sdkconfig +++ b/ports/espressif/boards/lolin_c3_pico/sdkconfig @@ -7,6 +7,7 @@ # # LWIP # +# CONFIG_LWIP_IPV6 is not set CONFIG_LWIP_LOCAL_HOSTNAME="lolin-c3-pico" # end of LWIP diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.mk index 334e3159c87c..836ab1b903bd 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.mk +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.mk @@ -12,3 +12,6 @@ CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESP_PSRAM_SIZE = 2MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 80m + +# Not enough flash +CIRCUITPY_SOCKETPOOL_IPV6 = 0 diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_tiny/sdkconfig index a491b9f5f019..19f833ad74ce 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_tiny/sdkconfig +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny/sdkconfig @@ -7,6 +7,7 @@ # # LWIP # +# CONFIG_LWIP_IPV6 is not set CONFIG_LWIP_LOCAL_HOSTNAME="waveshare-esp32-s3-tiny" # end of LWIP diff --git a/ports/espressif/common-hal/socketpool/Socket.c b/ports/espressif/common-hal/socketpool/Socket.c index 7a4634af495a..9fc04728a4d4 100644 --- a/ports/espressif/common-hal/socketpool/Socket.c +++ b/ports/espressif/common-hal/socketpool/Socket.c @@ -11,6 +11,8 @@ #include "py/mperrno.h" #include "py/runtime.h" #include "shared-bindings/socketpool/SocketPool.h" +#include "common-hal/socketpool/__init__.h" +#include "common-hal/wifi/__init__.h" #if CIRCUITPY_SSL #include "shared-bindings/ssl/SSLSocket.h" #include "shared-module/ssl/SSLSocket.h" @@ -25,6 +27,24 @@ #include "components/lwip/lwip/src/include/lwip/netdb.h" #include "components/vfs/include/esp_vfs_eventfd.h" +void socketpool_resolve_host_or_throw(int family, int type, const char *hostname, struct sockaddr_storage *addr, int port) { + struct addrinfo *result_i; + const struct addrinfo hints = { + .ai_family = family, + .ai_socktype = type, + }; + int error = socketpool_getaddrinfo_common(hostname, port, &hints, &result_i); + if (error != 0 || result_i == NULL) { + common_hal_socketpool_socketpool_raise_gaierror_noname(); + } + memcpy(addr, result_i->ai_addr, sizeof(struct sockaddr_storage)); + lwip_freeaddrinfo(result_i); +} + +static void resolve_host_or_throw(socketpool_socket_obj_t *self, const char *hostname, struct sockaddr_storage *addr, int port) { + socketpool_resolve_host_or_throw(self->family, self->type, hostname, addr, port); +} + StackType_t socket_select_stack[2 * configMINIMAL_STACK_SIZE]; /* Socket state table: @@ -175,7 +195,7 @@ static bool _socketpool_socket(socketpool_socketpool_obj_t *self, if (family == SOCKETPOOL_AF_INET) { addr_family = AF_INET; ipproto = IPPROTO_IP; - #if LWIP_IPV6 + #if CIRCUITPY_SOCKETPOOL_IPV6 } else { // INET6 addr_family = AF_INET6; ipproto = IPPROTO_IPV6; @@ -230,8 +250,14 @@ bool socketpool_socket(socketpool_socketpool_obj_t *self, socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_t *self, socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type, int proto) { - if (family != SOCKETPOOL_AF_INET) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("Only IPv4 sockets supported")); + switch (family) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + case SOCKETPOOL_AF_INET6: + #endif + case SOCKETPOOL_AF_INET: + break; + default: + mp_raise_NotImplementedError(MP_ERROR_TEXT("Unsupported socket type")); } socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t); @@ -244,9 +270,9 @@ socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_ return sock; } -int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_t *port, socketpool_socket_obj_t *accepted) { - struct sockaddr_in accept_addr; - socklen_t socklen = sizeof(accept_addr); +int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, socketpool_socket_obj_t *accepted) { + struct sockaddr_storage peer_addr; + socklen_t socklen = sizeof(peer_addr); int newsoc = -1; bool timed_out = false; uint64_t start_ticks = supervisor_ticks_ms64(); @@ -257,20 +283,17 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_ timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; } RUN_BACKGROUND_TASKS; - newsoc = lwip_accept(self->num, (struct sockaddr *)&accept_addr, &socklen); + newsoc = lwip_accept(self->num, (struct sockaddr *)&peer_addr, &socklen); // In non-blocking mode, fail instead of timing out if (newsoc == -1 && (self->timeout_ms == 0 || mp_hal_is_interrupted())) { return -MP_EAGAIN; } } - if (!timed_out) { - // harmless on failure but avoiding memcpy is faster - memcpy((void *)ip, (void *)&accept_addr.sin_addr.s_addr, sizeof(accept_addr.sin_addr.s_addr)); - *port = accept_addr.sin_port; - } else { + if (timed_out) { return -ETIMEDOUT; } + if (newsoc < 0) { return -MP_EBADF; } @@ -295,13 +318,16 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_ accepted->type = self->type; } + if (peer_out) { + *peer_out = sockaddr_to_tuple(&peer_addr); + } + return newsoc; } -socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *self, - uint8_t *ip, uint32_t *port) { +socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out) { socketpool_socket_obj_t *sock = m_new_obj_with_finaliser(socketpool_socket_obj_t); - int newsoc = socketpool_socket_accept(self, ip, port, NULL); + int newsoc = socketpool_socket_accept(self, peer_out, NULL); if (newsoc > 0) { // Create the socket @@ -321,20 +347,35 @@ socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_o size_t common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port) { - struct sockaddr_in bind_addr; + struct sockaddr_storage bind_addr; const char *broadcast = ""; - uint32_t ip; - if (hostlen == 0) { - ip = IPADDR_ANY; - } else if (hostlen == strlen(broadcast) && - memcmp(host, broadcast, strlen(broadcast)) == 0) { - ip = IPADDR_BROADCAST; - } else { - ip = inet_addr(host); + + bind_addr.ss_family = self->family; + + #if CIRCUITPY_SOCKETPOOL_IPV6 + if (self->family == AF_INET6) { + struct sockaddr_in6 *addr6 = (void *)&bind_addr; + addr6->sin6_port = htons(port); + // no ipv6 broadcast + if (hostlen == 0) { + memset(&addr6->sin6_addr, 0, sizeof(addr6->sin6_addr)); + } else { + socketpool_resolve_host_or_throw(self->family, self->type, host, &bind_addr, port); + } + } else + #endif + { + struct sockaddr_in *addr4 = (void *)&bind_addr; + addr4->sin_port = htons(port); + if (hostlen == 0) { + addr4->sin_addr.s_addr = IPADDR_ANY; + } else if (hostlen == strlen(broadcast) && + memcmp(host, broadcast, strlen(broadcast)) == 0) { + addr4->sin_addr.s_addr = IPADDR_BROADCAST; + } else { + socketpool_resolve_host_or_throw(self->family, self->type, host, &bind_addr, port); + } } - bind_addr.sin_addr.s_addr = ip; - bind_addr.sin_family = AF_INET; - bind_addr.sin_port = htons(port); int result = lwip_bind(self->num, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); if (result == 0) { @@ -376,26 +417,8 @@ void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self) { void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port) { - const struct addrinfo hints = { - .ai_family = AF_INET, - .ai_socktype = SOCK_STREAM, - }; - struct addrinfo *result_i; - int error = lwip_getaddrinfo(host, NULL, &hints, &result_i); - if (error != 0 || result_i == NULL) { - common_hal_socketpool_socketpool_raise_gaierror_noname(); - } - - // Set parameters - struct sockaddr_in dest_addr; - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - dest_addr.sin_addr.s_addr = ((struct sockaddr_in *)result_i->ai_addr)->sin_addr.s_addr; - #pragma GCC diagnostic pop - lwip_freeaddrinfo(result_i); - - dest_addr.sin_family = AF_INET; - dest_addr.sin_port = htons(port); + struct sockaddr_storage addr; + resolve_host_or_throw(self, host, &addr, port); // Replace above with function call ----- @@ -403,7 +426,7 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, // All our sockets are non-blocking, so we check the timeout ourselves. int result = -1; - result = lwip_connect(self->num, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in)); + result = lwip_connect(self->num, (struct sockaddr *)&addr, addr.s2_len); if (result == 0) { // Connected immediately. @@ -483,9 +506,9 @@ bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *self, int back } 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) { + uint8_t *buf, uint32_t len, mp_obj_t *source_out) { - struct sockaddr_in source_addr; + struct sockaddr_storage source_addr; socklen_t socklen = sizeof(source_addr); // LWIP Socket @@ -507,10 +530,7 @@ mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *se } } - if (!timed_out) { - memcpy((void *)ip, (void *)&source_addr.sin_addr.s_addr, sizeof(source_addr.sin_addr.s_addr)); - *port = htons(source_addr.sin_port); - } else { + if (timed_out) { mp_raise_OSError(ETIMEDOUT); } @@ -519,6 +539,10 @@ mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *se return 0; } + if (source_out) { + *source_out = sockaddr_to_tuple(&source_addr); + } + return received; } @@ -605,29 +629,10 @@ mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t *self, const 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) { - // Set parameters - const struct addrinfo hints = { - .ai_family = AF_INET, - .ai_socktype = SOCK_STREAM, - }; - struct addrinfo *result_i; - int error = lwip_getaddrinfo(host, NULL, &hints, &result_i); - if (error != 0 || result_i == NULL) { - common_hal_socketpool_socketpool_raise_gaierror_noname(); - } - - // Set parameters - struct sockaddr_in dest_addr; - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - dest_addr.sin_addr.s_addr = ((struct sockaddr_in *)result_i->ai_addr)->sin_addr.s_addr; - #pragma GCC diagnostic pop - lwip_freeaddrinfo(result_i); - - dest_addr.sin_family = AF_INET; - dest_addr.sin_port = htons(port); + struct sockaddr_storage addr; + resolve_host_or_throw(self, host, &addr, port); - int bytes_sent = lwip_sendto(self->num, buf, len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); + int bytes_sent = lwip_sendto(self->num, buf, len, 0, (struct sockaddr *)&addr, addr.s2_len); if (bytes_sent < 0) { mp_raise_BrokenPipeError(); return 0; diff --git a/ports/espressif/common-hal/socketpool/SocketPool.c b/ports/espressif/common-hal/socketpool/SocketPool.c index 1c5adf81aad4..aa7461d3ffe8 100644 --- a/ports/espressif/common-hal/socketpool/SocketPool.c +++ b/ports/espressif/common-hal/socketpool/SocketPool.c @@ -9,6 +9,7 @@ #include "py/runtime.h" #include "shared-bindings/wifi/__init__.h" +#include "common-hal/socketpool/__init__.h" #include "components/lwip/lwip/src/include/lwip/netdb.h" @@ -22,37 +23,102 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel // common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking. -mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self, - const char *host) { - +int socketpool_getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res) { // As of 2022, the version of lwip in esp-idf does not handle the // trailing-dot syntax of domain names, so emulate it. // Remove this once https://github.com/espressif/esp-idf/issues/10013 has // been implemented - size_t strlen_host = strlen(host); - if (strlen_host && host[strlen_host - 1] == '.') { - mp_obj_t nodot = mp_obj_new_str(host, strlen_host - 1); - host = mp_obj_str_get_str(nodot); + if (host) { + size_t strlen_host = strlen(host); + if (strlen_host && host[strlen_host - 1] == '.') { + mp_obj_t nodot = mp_obj_new_str(host, strlen_host - 1); + host = mp_obj_str_get_str(nodot); + } + } + + char service_buf[6]; + snprintf(service_buf, sizeof(service_buf), "%d", service); + + return lwip_getaddrinfo(host, service_buf, hints, res); +} + +static mp_obj_t format_address(const struct sockaddr *addr, int family) { + char ip_str[IPADDR_STRLEN_MAX]; // big enough for any supported address type + const struct sockaddr_in *a = (void *)addr; + + switch (family) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + case AF_INET6: + inet_ntop(family, &((const struct sockaddr_in6 *)a)->sin6_addr, ip_str, sizeof(ip_str)); + break; + #endif + default: + case AF_INET: + inet_ntop(family, &((const struct sockaddr_in *)a)->sin_addr, ip_str, sizeof(ip_str)); + break; + } + return mp_obj_new_str(ip_str, strlen(ip_str)); +} + +static mp_obj_t convert_sockaddr(const struct addrinfo *ai, int port) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + mp_int_t n_tuple = ai->ai_family == AF_INET6 ? 4 : 2; + #else + mp_int_t n_tuple = 2; + #endif + mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_tuple, NULL)); + result->items[0] = format_address(ai->ai_addr, ai->ai_family); + result->items[1] = MP_OBJ_NEW_SMALL_INT(port); + #if CIRCUITPY_SOCKETPOOL_IPV6 + if (ai->ai_family == AF_INET6) { + const struct sockaddr_in6 *ai6 = (void *)ai->ai_addr; + result->items[2] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_flowinfo); + result->items[3] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_scope_id); } + #endif + return result; +} + +static mp_obj_t convert_addrinfo(const struct addrinfo *ai, int port) { + MP_STATIC_ASSERT(AF_INET == SOCKETPOOL_AF_INET); + #if CIRCUITPY_SOCKETPOOL_IPV6 + MP_STATIC_ASSERT(AF_INET6 == SOCKETPOOL_AF_INET6); + #endif + // MP_STATIC_ASSERT(AF_UNSPEC == SOCKETPOOL_AF_UNSPEC); + mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); + result->items[0] = MP_OBJ_NEW_SMALL_INT(ai->ai_family); + result->items[1] = MP_OBJ_NEW_SMALL_INT(ai->ai_socktype); + result->items[2] = MP_OBJ_NEW_SMALL_INT(ai->ai_protocol); + result->items[3] = ai->ai_canonname ? mp_obj_new_str(ai->ai_canonname, strlen(ai->ai_canonname)) : MP_OBJ_NEW_QSTR(MP_QSTR_); + result->items[4] = convert_sockaddr(ai, port); + return result; +} +mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *self, const char *host, int port, int family, int type, int proto, int flags) { const struct addrinfo hints = { - .ai_family = AF_INET, - .ai_socktype = SOCK_STREAM, + .ai_flags = flags, + .ai_family = family, + .ai_protocol = proto, + .ai_socktype = type, }; - struct addrinfo *res; - int err = lwip_getaddrinfo(host, NULL, &hints, &res); + + struct addrinfo *res = NULL; + int err = socketpool_getaddrinfo_common(host, port, &hints, &res); if (err != 0 || res == NULL) { - return mp_const_none; + common_hal_socketpool_socketpool_raise_gaierror_noname(); } - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - struct in_addr *addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr; - #pragma GCC diagnostic pop - char ip_str[IP4ADDR_STRLEN_MAX]; - inet_ntoa_r(*addr, ip_str, IP4ADDR_STRLEN_MAX); - mp_obj_t ip_obj = mp_obj_new_str(ip_str, strlen(ip_str)); - lwip_freeaddrinfo(res); - - return ip_obj; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t result = mp_obj_new_list(0, NULL); + for (struct addrinfo *ai = res; ai; ai = ai->ai_next) { + mp_obj_list_append(result, convert_addrinfo(ai, port)); + } + nlr_pop(); + lwip_freeaddrinfo(res); + return result; + } else { + lwip_freeaddrinfo(res); + nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); + } } diff --git a/ports/espressif/common-hal/socketpool/__init__.h b/ports/espressif/common-hal/socketpool/__init__.h index fd356b87050f..48773954fe59 100644 --- a/ports/espressif/common-hal/socketpool/__init__.h +++ b/ports/espressif/common-hal/socketpool/__init__.h @@ -6,8 +6,7 @@ #pragma once -#ifndef MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL___INIT___H -#define MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL___INIT___H +struct addrinfo; - -#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL___INIT___H +int socketpool_getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res); +void socketpool_resolve_host_or_throw(int family, int type, const char *hostname, struct sockaddr_storage *addr, int port); diff --git a/ports/espressif/common-hal/wifi/Radio.c b/ports/espressif/common-hal/wifi/Radio.c index c46630f92e7f..a6f3c320b922 100644 --- a/ports/espressif/common-hal/wifi/Radio.c +++ b/ports/espressif/common-hal/wifi/Radio.c @@ -13,15 +13,23 @@ #include "common-hal/wifi/__init__.h" #include "shared/runtime/interrupt_char.h" #include "py/gc.h" +#include "py/obj.h" #include "py/runtime.h" #include "shared-bindings/ipaddress/IPv4Address.h" #include "shared-bindings/wifi/ScannedNetworks.h" #include "shared-bindings/wifi/AuthMode.h" #include "shared-bindings/time/__init__.h" #include "shared-module/ipaddress/__init__.h" +#include "common-hal/socketpool/__init__.h" +#include "components/esp_netif/include/esp_netif_net_stack.h" #include "components/esp_wifi/include/esp_wifi.h" #include "components/lwip/include/apps/ping/ping_sock.h" +#include "lwip/sockets.h" + +#if LWIP_IPV6_DHCP6 +#include "lwip/dhcp6.h" +#endif #if CIRCUITPY_MDNS #include "common-hal/mdns/Server.h" @@ -445,6 +453,44 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_subnet_ap(wifi_radio_obj_t *self) { return common_hal_ipaddress_new_ipv4address(self->ap_ip_info.netmask.addr); } +static mp_obj_t common_hal_wifi_radio_get_addresses_netif(wifi_radio_obj_t *self, esp_netif_t *netif) { + if (!esp_netif_is_netif_up(netif)) { + return mp_const_empty_tuple; + } + esp_netif_ip_info_t ip_info; + esp_netif_get_ip_info(netif, &ip_info); + int n_addresses4 = ip_info.ip.addr != INADDR_NONE; + + #if CIRCUITPY_SOCKETPOOL_IPV6 + esp_ip6_addr_t addresses[LWIP_IPV6_NUM_ADDRESSES]; + int n_addresses6 = esp_netif_get_all_ip6(netif, &addresses[0]); + #else + int n_addresses6 = 0; + #endif + int n_addresses = n_addresses4 + n_addresses6; + mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_addresses, NULL)); + + #if CIRCUITPY_SOCKETPOOL_IPV6 + for (int i = 0; i < n_addresses6; i++) { + result->items[i] = espaddr6_to_str(&addresses[i]); + } + #endif + + if (n_addresses4) { + result->items[n_addresses6] = espaddr4_to_str(&ip_info.ip); + } + + return MP_OBJ_FROM_PTR(result); +} + +mp_obj_t common_hal_wifi_radio_get_addresses(wifi_radio_obj_t *self) { + return common_hal_wifi_radio_get_addresses_netif(self, self->netif); +} + +mp_obj_t common_hal_wifi_radio_get_addresses_ap(wifi_radio_obj_t *self) { + return common_hal_wifi_radio_get_addresses_netif(self, self->ap_netif); +} + uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { if (!esp_netif_is_netif_up(self->netif)) { return 0; @@ -476,6 +522,9 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_dns(wifi_radio_obj_t *self) { esp_netif_get_dns_info(self->netif, ESP_NETIF_DNS_MAIN, &self->dns_info); + if (self->dns_info.ip.type != ESP_IPADDR_TYPE_V4) { + return mp_const_none; + } // dns_info is of type esp_netif_dns_info_t, which is just ever so slightly // different than esp_netif_ip_info_t used for // common_hal_wifi_radio_get_ipv4_address (includes both ipv4 and 6), @@ -489,12 +538,31 @@ void common_hal_wifi_radio_set_ipv4_dns(wifi_radio_obj_t *self, mp_obj_t ipv4_dn esp_netif_set_dns_info(self->netif, ESP_NETIF_DNS_MAIN, &dns_addr); } -void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self) { - esp_netif_dhcpc_start(self->netif); +void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self, bool ipv4, bool ipv6) { + if (ipv4) { + esp_netif_dhcpc_start(self->netif); + } else { + esp_netif_dhcpc_stop(self->netif); + } + #if LWIP_IPV6_DHCP6 + if (ipv6) { + esp_netif_create_ip6_linklocal(self->netif); + dhcp6_enable_stateless(esp_netif_get_netif_impl(self->netif)); + } else { + dhcp6_disable(esp_netif_get_netif_impl(self->netif)); + } + #else + if (ipv6) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_ipv6); + } + #endif } void common_hal_wifi_radio_stop_dhcp_client(wifi_radio_obj_t *self) { esp_netif_dhcpc_stop(self->netif); + #if LWIP_IPV6_DHCP6 + dhcp6_disable(esp_netif_get_netif_impl(self->netif)); + #endif } void common_hal_wifi_radio_start_dhcp_server(wifi_radio_obj_t *self) { @@ -568,11 +636,11 @@ mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, CHECK_ESP_RESULT(esp_ping_new_session(&ping_config, &ping_callbacks, &ping)); } - esp_ping_start(ping); - // Use all ones as a flag that the elapsed time was not set (ping failed or timed out). self->ping_elapsed_time = (uint32_t)(-1); + esp_ping_start(ping); + uint32_t start_time = common_hal_time_monotonic_ms(); while ((self->ping_elapsed_time == (uint32_t)(-1)) && (common_hal_time_monotonic_ms() - start_time < timeout_ms) && @@ -589,3 +657,38 @@ void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self) { // Only bother to scan the actual object references. gc_collect_ptr(self->current_scan); } + +mp_obj_t common_hal_wifi_radio_get_dns(wifi_radio_obj_t *self) { + if (!esp_netif_is_netif_up(self->netif)) { + return mp_const_empty_tuple; + } + + esp_netif_get_dns_info(self->netif, ESP_NETIF_DNS_MAIN, &self->dns_info); + + if (self->dns_info.ip.type == ESP_IPADDR_TYPE_V4 && self->dns_info.ip.u_addr.ip4.addr == INADDR_NONE) { + return mp_const_empty_tuple; + } + + mp_obj_t args[] = { + espaddr_to_str(&self->dns_info.ip), + }; + + return mp_obj_new_tuple(1, args); +} + +void common_hal_wifi_radio_set_dns(wifi_radio_obj_t *self, mp_obj_t dns_addrs_obj) { + mp_int_t len = mp_obj_get_int(mp_obj_len(dns_addrs_obj)); + mp_arg_validate_length_max(len, 1, MP_QSTR_dns); + esp_netif_dns_info_t dns_info; + if (len == 0) { + // clear DNS server + dns_info.ip.type = ESP_IPADDR_TYPE_V4; + dns_info.ip.u_addr.ip4.addr = INADDR_NONE; + } else { + mp_obj_t dns_addr_obj = mp_obj_subscr(dns_addrs_obj, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL); + struct sockaddr_storage addr_storage; + socketpool_resolve_host_or_throw(AF_UNSPEC, SOCK_STREAM, mp_obj_str_get_str(dns_addr_obj), &addr_storage, 1); + sockaddr_to_espaddr(&addr_storage, &dns_info.ip); + } + esp_netif_set_dns_info(self->netif, ESP_NETIF_DNS_MAIN, &dns_info); +} diff --git a/ports/espressif/common-hal/wifi/__init__.c b/ports/espressif/common-hal/wifi/__init__.c index ddebc41a9738..c2a63ceede72 100644 --- a/ports/espressif/common-hal/wifi/__init__.c +++ b/ports/espressif/common-hal/wifi/__init__.c @@ -11,6 +11,7 @@ #include "shared-bindings/ipaddress/IPv4Address.h" #include "shared-bindings/wifi/Monitor.h" #include "shared-bindings/wifi/Radio.h" +#include "common-hal/socketpool/__init__.h" #include "py/gc.h" #include "py/mpstate.h" @@ -27,6 +28,8 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #include "supervisor/port.h" #include "supervisor/workflow.h" +#include "lwip/sockets.h" + #if CIRCUITPY_STATUS_BAR #include "supervisor/shared/status_bar.h" #endif @@ -232,14 +235,16 @@ void wifi_reset(void) { } void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t *esp_ip_address) { - if (!mp_obj_is_type(ip_address, &ipaddress_ipv4address_type)) { - mp_raise_ValueError(MP_ERROR_TEXT("Only IPv4 addresses supported")); + if (mp_obj_is_type(ip_address, &ipaddress_ipv4address_type)) { + ipaddress_ipaddress_to_esp_idf_ip4(ip_address, (esp_ip4_addr_t *)esp_ip_address); + #if LWIP_IPV6 + esp_ip_address->type = IPADDR_TYPE_V4; + #endif + } else { + struct sockaddr_storage addr_storage; + socketpool_resolve_host_or_throw(AF_UNSPEC, SOCK_STREAM, mp_obj_str_get_str(ip_address), &addr_storage, 1); + sockaddr_to_espaddr(&addr_storage, (esp_ip_addr_t *)esp_ip_address); } - mp_obj_t packed = common_hal_ipaddress_ipv4address_get_packed(ip_address); - size_t len; - const char *bytes = mp_obj_str_get_data(packed, &len); - - IP_ADDR4(esp_ip_address, bytes[0], bytes[1], bytes[2], bytes[3]); } void ipaddress_ipaddress_to_esp_idf_ip4(mp_obj_t ip_address, esp_ip4_addr_t *esp_ip_address) { @@ -255,3 +260,94 @@ void ipaddress_ipaddress_to_esp_idf_ip4(mp_obj_t ip_address, esp_ip4_addr_t *esp void common_hal_wifi_gc_collect(void) { common_hal_wifi_radio_gc_collect(&common_hal_wifi_radio_obj); } + +static mp_obj_t espaddrx_to_str(const void *espaddr, uint8_t esptype) { + char buf[IPADDR_STRLEN_MAX]; + inet_ntop(esptype == ESP_IPADDR_TYPE_V6 ? AF_INET6 : AF_INET, espaddr, buf, sizeof(buf)); + return mp_obj_new_str(buf, strlen(buf)); +} + +mp_obj_t espaddr_to_str(const esp_ip_addr_t *espaddr) { + return espaddrx_to_str(espaddr, espaddr->type); +} + +mp_obj_t espaddr4_to_str(const esp_ip4_addr_t *espaddr) { + return espaddrx_to_str(espaddr, ESP_IPADDR_TYPE_V4); +} + +mp_obj_t espaddr6_to_str(const esp_ip6_addr_t *espaddr) { + return espaddrx_to_str(espaddr, ESP_IPADDR_TYPE_V6); +} + +mp_obj_t sockaddr_to_str(const struct sockaddr_storage *sockaddr) { + char buf[IPADDR_STRLEN_MAX]; + #if CIRCUITPY_SOCKETPOOL_IPV6 + if (sockaddr->ss_family == AF_INET6) { + const struct sockaddr_in6 *addr6 = (const void *)sockaddr; + inet_ntop(AF_INET6, &addr6->sin6_addr, buf, sizeof(buf)); + } else + #endif + { + const struct sockaddr_in *addr = (const void *)sockaddr; + inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)); + } + return mp_obj_new_str(buf, strlen(buf)); +} + +mp_obj_t sockaddr_to_tuple(const struct sockaddr_storage *sockaddr) { + mp_obj_t args[4] = { + sockaddr_to_str(sockaddr), + }; + int n = 2; + #if CIRCUITPY_SOCKETPOOL_IPV6 + if (sockaddr->ss_family == AF_INET6) { + const struct sockaddr_in6 *addr6 = (const void *)sockaddr; + args[1] = MP_OBJ_NEW_SMALL_INT(htons(addr6->sin6_port)); + args[2] = MP_OBJ_NEW_SMALL_INT(addr6->sin6_flowinfo); + args[3] = MP_OBJ_NEW_SMALL_INT(addr6->sin6_scope_id); + n = 4; + } else + #endif + { + const struct sockaddr_in *addr = (const void *)sockaddr; + args[1] = MP_OBJ_NEW_SMALL_INT(htons(addr->sin_port)); + } + return mp_obj_new_tuple(n, args); +} + +void sockaddr_to_espaddr(const struct sockaddr_storage *sockaddr, esp_ip_addr_t *espaddr) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + MP_STATIC_ASSERT(IPADDR_TYPE_V4 == ESP_IPADDR_TYPE_V4); + MP_STATIC_ASSERT(IPADDR_TYPE_V6 == ESP_IPADDR_TYPE_V6); + MP_STATIC_ASSERT(sizeof(ip_addr_t) == sizeof(esp_ip_addr_t)); + MP_STATIC_ASSERT(offsetof(ip_addr_t, u_addr) == offsetof(esp_ip_addr_t, u_addr)); + MP_STATIC_ASSERT(offsetof(ip_addr_t, type) == offsetof(esp_ip_addr_t, type)); + if (sockaddr->ss_family == AF_INET6) { + const struct sockaddr_in6 *addr6 = (const void *)sockaddr; + MP_STATIC_ASSERT(sizeof(espaddr->u_addr.ip6.addr) == sizeof(addr6->sin6_addr)); + memcpy(&espaddr->u_addr.ip6.addr, &addr6->sin6_addr, sizeof(espaddr->u_addr.ip6.addr)); + espaddr->u_addr.ip6.zone = addr6->sin6_scope_id; + espaddr->type = ESP_IPADDR_TYPE_V6; + } else + #endif + { + const struct sockaddr_in *addr = (const void *)sockaddr; + MP_STATIC_ASSERT(sizeof(espaddr->u_addr.ip4.addr) == sizeof(addr->sin_addr)); + memcpy(&espaddr->u_addr.ip4.addr, &addr->sin_addr, sizeof(espaddr->u_addr.ip4.addr)); + espaddr->type = ESP_IPADDR_TYPE_V4; + } +} + +void espaddr_to_sockaddr(const esp_ip_addr_t *espaddr, struct sockaddr_storage *sockaddr, int port) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + if (espaddr->type == ESP_IPADDR_TYPE_V6) { + struct sockaddr_in6 *addr6 = (void *)sockaddr; + memcpy(&addr6->sin6_addr, &espaddr->u_addr.ip6.addr, sizeof(espaddr->u_addr.ip6.addr)); + addr6->sin6_scope_id = espaddr->u_addr.ip6.zone; + } else + #endif + { + struct sockaddr_in *addr = (void *)sockaddr; + memcpy(&addr->sin_addr, &espaddr->u_addr.ip4.addr, sizeof(espaddr->u_addr.ip4.addr)); + } +} diff --git a/ports/espressif/common-hal/wifi/__init__.h b/ports/espressif/common-hal/wifi/__init__.h index 55a7fddbf448..cbd3c000a179 100644 --- a/ports/espressif/common-hal/wifi/__init__.h +++ b/ports/espressif/common-hal/wifi/__init__.h @@ -11,7 +11,17 @@ #include "lwip/api.h" #include "components/esp_wifi/include/esp_wifi.h" +struct sockaddr_storage; + void wifi_reset(void); void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t *esp_ip_address); void ipaddress_ipaddress_to_esp_idf_ip4(mp_obj_t ip_address, esp_ip4_addr_t *esp_ip_address); + +mp_obj_t sockaddr_to_str(const struct sockaddr_storage *addr); +mp_obj_t sockaddr_to_tuple(const struct sockaddr_storage *addr); +mp_obj_t espaddr_to_str(const esp_ip_addr_t *espaddr); +mp_obj_t espaddr4_to_str(const esp_ip4_addr_t *espaddr); +mp_obj_t espaddr6_to_str(const esp_ip6_addr_t *espaddr); +void sockaddr_to_espaddr(const struct sockaddr_storage *sockaddr, esp_ip_addr_t *espaddr); +void espaddr_to_sockaddr(const esp_ip_addr_t *espaddr, struct sockaddr_storage *sockaddr, int port); diff --git a/ports/espressif/esp-idf-config/sdkconfig.defaults b/ports/espressif/esp-idf-config/sdkconfig.defaults index 3bf498bc6930..c11591b3cf92 100644 --- a/ports/espressif/esp-idf-config/sdkconfig.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig.defaults @@ -64,6 +64,12 @@ CONFIG_FREERTOS_HZ=1000 CONFIG_LWIP_MAX_SOCKETS=8 CONFIG_LWIP_SO_RCVBUF=y # +# IPv6 +# +CONFIG_LWIP_IPV6_AUTOCONFIG=y +CONFIG_LWIP_IPV6_RDNSS_MAX_DNS_SERVERS=2 +CONFIG_LWIP_IPV6_DHCP6=y +# # TCP # CONFIG_LWIP_MAX_ACTIVE_TCP=4 diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 14c3b83250f1..d431501129f6 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -49,6 +49,7 @@ CIRCUITPY_SYNTHIO_MAX_CHANNELS ?= 12 CIRCUITPY_TOUCHIO_USE_NATIVE ?= 1 CIRCUITPY_WATCHDOG ?= 1 CIRCUITPY_WIFI ?= 1 +CIRCUITPY_SOCKETPOOL_IPV6 ?= 1 # Enable _eve module CIRCUITPY__EVE ?= 1 diff --git a/ports/raspberrypi/common-hal/socketpool/Socket.c b/ports/raspberrypi/common-hal/socketpool/Socket.c index b71d519b14c2..d2626456f950 100644 --- a/ports/raspberrypi/common-hal/socketpool/Socket.c +++ b/ports/raspberrypi/common-hal/socketpool/Socket.c @@ -21,6 +21,7 @@ #include "supervisor/port.h" #include "supervisor/shared/tick.h" #include "supervisor/workflow.h" +#include "common-hal/socketpool/__init__.h" #include "lwip/dns.h" #include "lwip/err.h" @@ -36,6 +37,36 @@ #include "sdk/src/rp2_common/pico_cyw43_arch/include/pico/cyw43_arch.h" +mp_obj_t socketpool_ip_addr_to_str(const ip_addr_t *addr) { + char ip_str[IPADDR_STRLEN_MAX]; // big enough for any supported address type + switch (IP_GET_TYPE(addr)) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + case IPADDR_TYPE_V6: + ip6addr_ntoa_r(ip_2_ip6(addr), ip_str, sizeof(ip_str)); + break; + #endif + default: + ip4addr_ntoa_r(ip_2_ip4(addr), ip_str, sizeof(ip_str)); + } + return mp_obj_new_str(ip_str, strlen(ip_str)); +} + +static mp_obj_t socketpool_ip_addr_and_port_to_tuple(const ip_addr_t *addr, int port) { + mp_obj_t args[CIRCUITPY_SOCKETPOOL_IPV6 ? 4 : 2] = { + socketpool_ip_addr_to_str(addr), + MP_OBJ_NEW_SMALL_INT(port), + }; + int n = 2; + #if CIRCUITPY_SOCKETPOOL_IPV6 + if (IP_GET_TYPE(addr) == IPADDR_TYPE_V6) { + items[2] = MP_OBJ_NEW_SMALL_INT(0); // sin6_flowinfo + items[3] = MP_OBJ_NEW_SMALL_INT(ip_2_ip6(addr)->zone); + n = 4; + } + #endif + return mp_obj_new_tuple(n, args); +} + #define MICROPY_PY_LWIP_SOCK_RAW (1) #if 0 // print debugging info @@ -380,7 +411,7 @@ static mp_uint_t lwip_raw_udp_send(socketpool_socket_obj_t *socket, const byte * } // Helper function for recv/recvfrom to handle raw/UDP packets -static mp_uint_t lwip_raw_udp_receive(socketpool_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, uint32_t *port, int *_errno) { +static mp_uint_t lwip_raw_udp_receive(socketpool_socket_obj_t *socket, byte *buf, mp_uint_t len, mp_obj_t *peer_out, int *_errno) { if (socket->incoming.pbuf == NULL) { if (socket->timeout == 0) { @@ -400,9 +431,8 @@ static mp_uint_t lwip_raw_udp_receive(socketpool_socket_obj_t *socket, byte *buf } } - if (ip != NULL) { - memcpy(ip, &socket->peer, sizeof(socket->peer)); - *port = socket->peer_port; + if (peer_out != NULL) { + *peer_out = socketpool_ip_addr_and_port_to_tuple(&socket->peer, socket->peer_port); } struct pbuf *p = socket->incoming.pbuf; @@ -726,7 +756,7 @@ socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_ return socket; } -int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_t *port, socketpool_socket_obj_t *accepted) { +int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, socketpool_socket_obj_t *accepted) { if (self->type != MOD_NETWORK_SOCK_STREAM) { return -MP_EOPNOTSUPP; } @@ -808,20 +838,21 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_ MICROPY_PY_LWIP_EXIT // output values - memcpy(ip, &(accepted->pcb.tcp->remote_ip), NETUTILS_IPV4ADDR_BUFSIZE); - *port = (mp_uint_t)accepted->pcb.tcp->remote_port; + if (peer_out) { + *peer_out = socketpool_ip_addr_and_port_to_tuple(&accepted->pcb.tcp->remote_ip, accepted->pcb.tcp->remote_port); + } return 1; } socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *socket, - uint8_t *ip, uint32_t *port) { + mp_obj_t *peer_out) { // Create new socket object, do it here because we must not raise an out-of-memory // exception when the LWIP concurrency lock is held socketpool_socket_obj_t *accepted = m_new_ll_obj_with_finaliser(socketpool_socket_obj_t); socketpool_socket_reset(accepted); - int ret = socketpool_socket_accept(socket, ip, port, accepted); + int ret = socketpool_socket_accept(socket, peer_out, accepted); if (ret <= 0) { m_del_obj(socketpool_socket_obj_t, accepted); @@ -852,7 +883,7 @@ size_t common_hal_socketpool_socket_bind(socketpool_socket_obj_t *socket, ip_addr_t bind_addr; const ip_addr_t *bind_addr_ptr = &bind_addr; if (hostlen > 0) { - socketpool_resolve_host_raise(socket->pool, host, &bind_addr); + socketpool_resolve_host_raise(host, &bind_addr); } else { bind_addr_ptr = IP_ANY_TYPE; } @@ -941,7 +972,7 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *socket, // get address ip_addr_t dest; - socketpool_resolve_host_raise(socket->pool, host, &dest); + socketpool_resolve_host_raise(host, &dest); err_t err = ERR_ARG; switch (socket->type) { @@ -966,7 +997,7 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *socket, mp_raise_OSError(error_lookup_table[-err]); } socket->peer_port = (mp_uint_t)port; - memcpy(socket->peer, &dest, sizeof(socket->peer)); + memcpy(&socket->peer, &dest, sizeof(socket->peer)); MICROPY_PY_LWIP_EXIT // And now we wait... @@ -1054,14 +1085,17 @@ bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *socket, int ba } mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *socket, - uint8_t *buf, uint32_t len, uint8_t *ip, uint32_t *port) { + uint8_t *buf, uint32_t len, mp_obj_t *peer_out) { int _errno; mp_uint_t ret = 0; switch (socket->type) { case SOCKETPOOL_SOCK_STREAM: { - memcpy(ip, &socket->peer, sizeof(socket->peer)); - *port = (mp_uint_t)socket->peer_port; + // output values + if (peer_out) { + *peer_out = socketpool_ip_addr_and_port_to_tuple(&socket->peer, socket->peer_port); + } + ret = lwip_tcp_receive(socket, (byte *)buf, len, &_errno); break; } @@ -1069,7 +1103,7 @@ mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *so #if MICROPY_PY_LWIP_SOCK_RAW case SOCKETPOOL_SOCK_RAW: #endif - ret = lwip_raw_udp_receive(socket, (byte *)buf, len, ip, port, &_errno); + ret = lwip_raw_udp_receive(socket, (byte *)buf, len, peer_out, &_errno); break; } if (ret == (unsigned)-1) { @@ -1092,7 +1126,7 @@ int socketpool_socket_recv_into(socketpool_socket_obj_t *socket, #if MICROPY_PY_LWIP_SOCK_RAW case SOCKETPOOL_SOCK_RAW: #endif - ret = lwip_raw_udp_receive(socket, (byte *)buf, len, NULL, NULL, &_errno); + ret = lwip_raw_udp_receive(socket, (byte *)buf, len, NULL, &_errno); break; } if (ret == (unsigned)-1) { @@ -1143,7 +1177,7 @@ mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t *socket, const char *host, size_t hostlen, uint32_t port, const uint8_t *buf, uint32_t len) { int _errno; ip_addr_t ip; - socketpool_resolve_host_raise(socket->pool, host, &ip); + socketpool_resolve_host_raise(host, &ip); mp_uint_t ret = 0; switch (socket->type) { diff --git a/ports/raspberrypi/common-hal/socketpool/Socket.h b/ports/raspberrypi/common-hal/socketpool/Socket.h index 62754a012115..d78987777448 100644 --- a/ports/raspberrypi/common-hal/socketpool/Socket.h +++ b/ports/raspberrypi/common-hal/socketpool/Socket.h @@ -35,7 +35,7 @@ typedef struct _lwip_socket_obj_t { } connection; } incoming; mp_obj_t callback; - byte peer[4]; + ip_addr_t peer; mp_uint_t peer_port; mp_uint_t timeout; uint16_t recv_offset; diff --git a/ports/raspberrypi/common-hal/socketpool/SocketPool.c b/ports/raspberrypi/common-hal/socketpool/SocketPool.c index cf92a622a1c7..394b97799338 100644 --- a/ports/raspberrypi/common-hal/socketpool/SocketPool.c +++ b/ports/raspberrypi/common-hal/socketpool/SocketPool.c @@ -5,10 +5,12 @@ // SPDX-License-Identifier: MIT #include "shared-bindings/socketpool/SocketPool.h" +#include "common-hal/socketpool/__init__.h" #include "common-hal/socketpool/Socket.h" #include "shared/runtime/interrupt_char.h" #include "py/runtime.h" #include "shared-bindings/wifi/__init__.h" +#include "shared-bindings/ipaddress/__init__.h" #include "lwip/dns.h" #include "lwip/inet.h" @@ -21,72 +23,10 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel // 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; - } -} - -static int socketpool_resolve_host(socketpool_socketpool_obj_t *self, const char *host, ip_addr_t *addr) { - - 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) { - return state.status; - // 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); - } - - *addr = state.ipaddr; - return 0; -} - -void socketpool_resolve_host_raise(socketpool_socketpool_obj_t *self, const char *host, ip_addr_t *addr) { - int result = socketpool_resolve_host(self, host, addr); - if (result < 0) { - printf("socket_resolve_host() returned %d\n", result); - common_hal_socketpool_socketpool_raise_gaierror_noname(); - mp_raise_OSError(-result); - } -} - -mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self, const char *host) { +static mp_obj_t common_hal_socketpool_socketpool_gethostbyname_raise(socketpool_socketpool_obj_t *self, const char *host) { ip_addr_t addr; - socketpool_resolve_host_raise(self, host, &addr); + socketpool_resolve_host_raise(host, &addr); char ip_str[IP4ADDR_STRLEN_MAX]; inet_ntoa_r(addr, ip_str, IP4ADDR_STRLEN_MAX); @@ -94,6 +34,23 @@ mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_ob return ip_obj; } -mp_obj_t common_hal_socketpool_socketpool_gethostbyname_raise(socketpool_socketpool_obj_t *self, const char *host) { - return common_hal_socketpool_socketpool_gethostbyname(self, host); +mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *self, const char *host, int port, int family, int type, int proto, int flags) { + mp_obj_t ip_str; + + if (strlen(host) > 0 && ipaddress_parse_ipv4address(host, strlen(host), NULL)) { + ip_str = mp_obj_new_str(host, strlen(host)); + } else { + ip_str = common_hal_socketpool_socketpool_gethostbyname_raise(self, host); + } + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(SOCKETPOOL_AF_INET); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SOCKETPOOL_SOCK_STREAM); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); + tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); + mp_obj_tuple_t *sockaddr = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + sockaddr->items[0] = ip_str; + sockaddr->items[1] = MP_OBJ_NEW_SMALL_INT(port); + tuple->items[4] = MP_OBJ_FROM_PTR(sockaddr); + return mp_obj_new_list(1, (mp_obj_t *)&tuple); } diff --git a/ports/raspberrypi/common-hal/socketpool/SocketPool.h b/ports/raspberrypi/common-hal/socketpool/SocketPool.h index 1c60d5109635..864a52b32830 100644 --- a/ports/raspberrypi/common-hal/socketpool/SocketPool.h +++ b/ports/raspberrypi/common-hal/socketpool/SocketPool.h @@ -13,5 +13,3 @@ typedef struct { mp_obj_base_t base; } socketpool_socketpool_obj_t; - -void socketpool_resolve_host_raise(socketpool_socketpool_obj_t *self, const char *host, ip_addr_t *addr); diff --git a/ports/raspberrypi/common-hal/socketpool/__init__.c b/ports/raspberrypi/common-hal/socketpool/__init__.c index c8558f9b80a3..84a5309ae112 100644 --- a/ports/raspberrypi/common-hal/socketpool/__init__.c +++ b/ports/raspberrypi/common-hal/socketpool/__init__.c @@ -4,10 +4,78 @@ // // SPDX-License-Identifier: MIT +#include "py/runtime.h" +#include "shared/runtime/interrupt_char.h" + #include "shared-bindings/socketpool/__init__.h" +#include "shared-bindings/socketpool/SocketPool.h" +#include "shared-bindings/wifi/__init__.h" +#include "common-hal/socketpool/__init__.h" + +#include "lwip/dns.h" +#include "lwip/inet.h" -#include "common-hal/socketpool/Socket.h" void socketpool_user_reset(void) { socket_user_reset(); } + +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; + } +} + + +static int socketpool_resolve_host(const char *host, ip_addr_t *addr) { + + 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) { + return state.status; + } + + *addr = state.ipaddr; + return 0; +} + +void socketpool_resolve_host_raise(const char *host, ip_addr_t *addr) { + int result = socketpool_resolve_host(host, addr); + if (result < 0) { + printf("socket_resolve_host() returned %d\n", result); + common_hal_socketpool_socketpool_raise_gaierror_noname(); + mp_raise_OSError(-result); + } +} diff --git a/ports/raspberrypi/common-hal/socketpool/__init__.h b/ports/raspberrypi/common-hal/socketpool/__init__.h index f7ccde7f3678..d55e720b373b 100644 --- a/ports/raspberrypi/common-hal/socketpool/__init__.h +++ b/ports/raspberrypi/common-hal/socketpool/__init__.h @@ -5,3 +5,8 @@ // SPDX-License-Identifier: MIT #pragma once + +#include "lwip/ip_addr.h" + +mp_obj_t socketpool_ip_addr_to_str(const ip_addr_t *addr); +void socketpool_resolve_host_raise(const char *host, ip_addr_t *addr); diff --git a/ports/raspberrypi/common-hal/wifi/Radio.c b/ports/raspberrypi/common-hal/wifi/Radio.c index 41eec00357db..3250ed4d7c7f 100644 --- a/ports/raspberrypi/common-hal/wifi/Radio.c +++ b/ports/raspberrypi/common-hal/wifi/Radio.c @@ -21,6 +21,7 @@ #include "shared-bindings/wifi/AuthMode.h" #include "shared-bindings/time/__init__.h" #include "shared-module/ipaddress/__init__.h" +#include "common-hal/socketpool/__init__.h" #include "lwip/sys.h" #include "lwip/dns.h" @@ -405,8 +406,15 @@ void common_hal_wifi_radio_set_ipv4_dns(wifi_radio_obj_t *self, mp_obj_t ipv4_dn dns_setserver(0, &addr); } -void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self) { - dhcp_start(NETIF_STA); +void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self, bool ipv4, bool ipv6) { + if (ipv4) { + dhcp_start(NETIF_STA); + } else { + dhcp_stop(NETIF_STA); + } + if (ipv6) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_ipv6); + } } void common_hal_wifi_radio_stop_dhcp_client(wifi_radio_obj_t *self) { @@ -481,7 +489,11 @@ ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, mp_float_t timeout) { ping_time = sys_now(); ip_addr_t ping_addr; - ipaddress_ipaddress_to_lwip(ip_address, &ping_addr); + if (mp_obj_is_str(ip_address)) { + socketpool_resolve_host_raise(mp_obj_str_get_str(ip_address), &ping_addr); + } else { + ipaddress_ipaddress_to_lwip(ip_address, &ping_addr); + } struct raw_pcb *ping_pcb; MICROPY_PY_LWIP_ENTER @@ -522,3 +534,47 @@ void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self) { // Only bother to scan the actual object references. gc_collect_ptr(self->current_scan); } + +mp_obj_t common_hal_wifi_radio_get_addresses(wifi_radio_obj_t *self) { + if (cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA) != CYW43_LINK_UP) { + return mp_const_empty_tuple; + } + mp_obj_t args[] = { + socketpool_ip_addr_to_str(&NETIF_STA->ip_addr), + }; + return mp_obj_new_tuple(1, args); +} + +mp_obj_t common_hal_wifi_radio_get_addresses_ap(wifi_radio_obj_t *self) { + if (cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_AP) != CYW43_LINK_UP) { + return mp_const_empty_tuple; + } + mp_obj_t args[] = { + socketpool_ip_addr_to_str(&NETIF_AP->ip_addr), + }; + return mp_obj_new_tuple(MP_ARRAY_SIZE(args), args); +} + +mp_obj_t common_hal_wifi_radio_get_dns(wifi_radio_obj_t *self) { + const ip_addr_t *dns_addr = dns_getserver(0); + if (cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA) != CYW43_LINK_UP || dns_addr->addr == 0) { + return mp_const_empty_tuple; + } + mp_obj_t args[] = { + socketpool_ip_addr_to_str(dns_addr), + }; + return mp_obj_new_tuple(MP_ARRAY_SIZE(args), args); +} + +void common_hal_wifi_radio_set_dns(wifi_radio_obj_t *self, mp_obj_t dns_addrs_obj) { + mp_int_t len = mp_obj_get_int(mp_obj_len(dns_addrs_obj)); + mp_arg_validate_length_max(len, 1, MP_QSTR_dns); + ip_addr_t addr; + if (len == 0) { + addr.addr = IPADDR_NONE; + } else { + mp_obj_t dns_addr_obj = mp_obj_subscr(dns_addrs_obj, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_SENTINEL); + socketpool_resolve_host_raise(dns_addr_obj, &addr); + } + dns_setserver(0, &addr); +} diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 5c0ba355ad74..e7900ce0696d 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -496,6 +496,9 @@ CFLAGS += -DCIRCUITPY_SKIP_SAFE_MODE_WAIT=$(CIRCUITPY_SKIP_SAFE_MODE_WAIT) CIRCUITPY_SOCKETPOOL ?= $(CIRCUITPY_WIFI) CFLAGS += -DCIRCUITPY_SOCKETPOOL=$(CIRCUITPY_SOCKETPOOL) +CIRCUITPY_SOCKETPOOL_IPV6 ?= 0 +CFLAGS += -DCIRCUITPY_SOCKETPOOL_IPV6=$(CIRCUITPY_SOCKETPOOL_IPV6) + CIRCUITPY_SSL ?= $(CIRCUITPY_WIFI) CFLAGS += -DCIRCUITPY_SSL=$(CIRCUITPY_SSL) diff --git a/shared-bindings/socketpool/Socket.c b/shared-bindings/socketpool/Socket.c index dfc3c98f4374..25d10c294827 100644 --- a/shared-bindings/socketpool/Socket.c +++ b/shared-bindings/socketpool/Socket.c @@ -57,14 +57,10 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socketpool_socket___exit___obj, 4, 4, //| Returns a tuple of (new_socket, remote_address)""" static mp_obj_t _socketpool_socket_accept(mp_obj_t self_in) { socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint8_t ip[4]; - uint32_t port; - - socketpool_socket_obj_t *sock = common_hal_socketpool_socket_accept(self, ip, &port); mp_obj_t tuple_contents[2]; - tuple_contents[0] = MP_OBJ_FROM_PTR(sock); - tuple_contents[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + tuple_contents[0] = MP_OBJ_FROM_PTR(common_hal_socketpool_socket_accept(self, &tuple_contents[1])); + return mp_obj_new_tuple(2, tuple_contents); } static MP_DEFINE_CONST_FUN_OBJ_1(socketpool_socket_accept_obj, _socketpool_socket_accept); @@ -158,13 +154,9 @@ static mp_obj_t socketpool_socket_recvfrom_into(mp_obj_t self_in, mp_obj_t data_ mp_buffer_info_t bufinfo; mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_WRITE); - byte ip[4]; - 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]; - tuple_contents[0] = mp_obj_new_int_from_uint(ret); - tuple_contents[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + tuple_contents[0] = mp_obj_new_int_from_uint(common_hal_socketpool_socket_recvfrom_into(self, + (byte *)bufinfo.buf, bufinfo.len, &tuple_contents[1])); return mp_obj_new_tuple(2, tuple_contents); } static MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_recvfrom_into_obj, socketpool_socket_recvfrom_into); diff --git a/shared-bindings/socketpool/Socket.h b/shared-bindings/socketpool/Socket.h index 25ba7ecff558..a883ebd50546 100644 --- a/shared-bindings/socketpool/Socket.h +++ b/shared-bindings/socketpool/Socket.h @@ -10,7 +10,7 @@ extern const mp_obj_type_t socketpool_socket_type; -socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_t *port); +socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out); size_t common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port); void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self); void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port); @@ -20,7 +20,7 @@ mp_uint_t common_hal_socketpool_socket_get_timeout(socketpool_socket_obj_t *self mp_int_t common_hal_socketpool_socket_get_type(socketpool_socket_obj_t *self); bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *self, int backlog); 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); + uint8_t *buf, uint32_t len, mp_obj_t *peer_out); mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t *self, const uint8_t *buf, uint32_t len); mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t *self, const uint8_t *buf, uint32_t len); mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t *self, @@ -31,7 +31,7 @@ bool common_hal_socketpool_readable(socketpool_socket_obj_t *self); bool common_hal_socketpool_writable(socketpool_socket_obj_t *self); // Non-allocating versions for internal use. -int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_t *port, socketpool_socket_obj_t *accepted); +int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, socketpool_socket_obj_t *accepted); void socketpool_socket_close(socketpool_socket_obj_t *self); int socketpool_socket_send(socketpool_socket_obj_t *self, const uint8_t *buf, uint32_t len); int socketpool_socket_recv_into(socketpool_socket_obj_t *self, diff --git a/shared-bindings/socketpool/SocketPool.c b/shared-bindings/socketpool/SocketPool.c index 2b4623323fa8..ada850ad17d4 100644 --- a/shared-bindings/socketpool/SocketPool.c +++ b/shared-bindings/socketpool/SocketPool.c @@ -142,28 +142,14 @@ static mp_obj_t socketpool_socketpool_getaddrinfo(size_t n_args, const mp_obj_t mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - const char *host = mp_obj_str_get_str(args[ARG_host].u_obj); - mp_int_t port = args[ARG_port].u_int; - mp_obj_t ip_str = mp_const_none; - - if (strlen(host) > 0 && ipaddress_parse_ipv4address(host, strlen(host), NULL)) { - ip_str = args[ARG_host].u_obj; - } - - if (ip_str == mp_const_none) { - ip_str = common_hal_socketpool_socketpool_gethostbyname_raise(self, host); - } - - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(SOCKETPOOL_AF_INET); - tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SOCKETPOOL_SOCK_STREAM); - tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); - tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); - mp_obj_tuple_t *sockaddr = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); - sockaddr->items[0] = ip_str; - sockaddr->items[1] = MP_OBJ_NEW_SMALL_INT(port); - tuple->items[4] = MP_OBJ_FROM_PTR(sockaddr); - return mp_obj_new_list(1, (mp_obj_t *)&tuple); + return common_hal_socketpool_getaddrinfo_raise( + self, + mp_obj_str_get_str(args[ARG_host].u_obj), + args[ARG_port].u_int, + args[ARG_family].u_int, + args[ARG_type].u_int, + args[ARG_proto].u_int, + args[ARG_flags].u_int); } static MP_DEFINE_CONST_FUN_OBJ_KW(socketpool_socketpool_getaddrinfo_obj, 1, socketpool_socketpool_getaddrinfo); @@ -207,15 +193,6 @@ MP_DEFINE_CONST_OBJ_TYPE( locals_dict, &socketpool_socketpool_locals_dict ); -MP_WEAK -mp_obj_t common_hal_socketpool_socketpool_gethostbyname_raise(socketpool_socketpool_obj_t *self, const char *host) { - mp_obj_t ip_str = common_hal_socketpool_socketpool_gethostbyname(self, host); - if (ip_str == mp_const_none) { - common_hal_socketpool_socketpool_raise_gaierror_noname(); - } - return ip_str; -} - MP_WEAK NORETURN void common_hal_socketpool_socketpool_raise_gaierror_noname(void) { vstr_t vstr; diff --git a/shared-bindings/socketpool/SocketPool.h b/shared-bindings/socketpool/SocketPool.h index 7088961477f7..36035ed00e11 100644 --- a/shared-bindings/socketpool/SocketPool.h +++ b/shared-bindings/socketpool/SocketPool.h @@ -19,12 +19,6 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_t *self, socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type, int proto); -mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_obj_t *self, - const char *host); -// raises an exception instead of returning mp_const_none in the case of error -mp_obj_t common_hal_socketpool_socketpool_gethostbyname_raise(socketpool_socketpool_obj_t *self, - const char *host); - // Non-allocating version for internal use. These sockets are not registered and, therefore, not // closed automatically. bool socketpool_socket(socketpool_socketpool_obj_t *self, @@ -32,3 +26,5 @@ bool socketpool_socket(socketpool_socketpool_obj_t *self, int proto, socketpool_socket_obj_t *sock); NORETURN void common_hal_socketpool_socketpool_raise_gaierror_noname(void); + +mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *self, const char *host, int port, int family, int type, int proto, int flags); diff --git a/shared-bindings/socketpool/__init__.c b/shared-bindings/socketpool/__init__.c index 59d55bf3f836..e3e3f035ce72 100644 --- a/shared-bindings/socketpool/__init__.c +++ b/shared-bindings/socketpool/__init__.c @@ -18,6 +18,21 @@ //| //| For more information about the `socket` module, see the CPython documentation: //| https://docs.python.org/3/library/socket.html +//| +//| .. jinja +//| +//| .. raw:: html +//| +//|

+//|

+//| AF_INET6 (IPv6) supported on these boards +//| +//|
+//|

//| """ static const mp_rom_map_elem_t socketpool_globals_table[] = { diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index 76ae4345ab2d..f6a35e28c849 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -596,6 +596,26 @@ static mp_obj_t wifi_radio_set_ipv4_address_ap(size_t n_args, const mp_obj_t *po } static MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_set_ipv4_address_ap_obj, 1, wifi_radio_set_ipv4_address_ap); +//| addresses: Sequence[str] +//| """Address(es) of the station when connected to an access point. Empty sequence when not connected. (read-only)""" +static mp_obj_t _wifi_radio_get_addresses(mp_obj_t self) { + return common_hal_wifi_radio_get_addresses(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_addresses_obj, _wifi_radio_get_addresses); + +MP_PROPERTY_GETTER(wifi_radio_addresses_obj, + (mp_obj_t)&wifi_radio_get_addresses_obj); + +//| addresses_ap: Sequence[str] +//| """Address(es) of the access point when enabled. Empty sequence when disabled. (read-only)""" +static mp_obj_t _wifi_radio_get_addresses_ap(mp_obj_t self) { + return common_hal_wifi_radio_get_addresses_ap(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_addresses_ap_obj, _wifi_radio_get_addresses_ap); + +MP_PROPERTY_GETTER(wifi_radio_addresses_ap_obj, + (mp_obj_t)&wifi_radio_get_addresses_ap_obj); + //| ipv4_address: Optional[ipaddress.IPv4Address] //| """IP v4 Address of the station when connected to an access point. None otherwise. (read-only)""" static mp_obj_t _wifi_radio_get_ipv4_address(mp_obj_t self) { @@ -634,6 +654,24 @@ MP_PROPERTY_GETSET(wifi_radio_ipv4_dns_obj, (mp_obj_t)&wifi_radio_get_ipv4_dns_obj, (mp_obj_t)&wifi_radio_set_ipv4_dns_obj); +//| dns: Sequence[str] +//| """Address of the DNS server to be used.""" +static mp_obj_t wifi_radio_get_dns(mp_obj_t self) { + return common_hal_wifi_radio_get_dns(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_dns_obj, wifi_radio_get_dns); + +static mp_obj_t wifi_radio_set_dns(mp_obj_t self, mp_obj_t dns_addr) { + common_hal_wifi_radio_set_dns(self, dns_addr); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(wifi_radio_set_dns_obj, wifi_radio_set_dns); + +MP_PROPERTY_GETSET(wifi_radio_dns_obj, + (mp_obj_t)&wifi_radio_get_dns_obj, + (mp_obj_t)&wifi_radio_set_dns_obj); + //| ap_info: Optional[Network] //| """Network object containing BSSID, SSID, authmode, channel, country and RSSI when connected to an access point. None otherwise.""" static mp_obj_t wifi_radio_get_ap_info(mp_obj_t self) { @@ -655,14 +693,29 @@ MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_stations_ap_obj, wifi_radio_get_station MP_PROPERTY_GETTER(wifi_radio_stations_ap_obj, (mp_obj_t)&wifi_radio_get_stations_ap_obj); -//| def start_dhcp(self) -> None: -//| """Starts the station DHCP client.""" +//| def start_dhcp(self, *, ipv4: bool = True, ipv6: bool = False) -> None: +//| """Starts the station DHCP client. +//| +//| By default, calling this function starts DHCP for IPv4 networks but not +//| IPv6 networks. When the the ``ipv4`` and ``ipv6`` arguments are `False` +//| then the corresponding DHCP client is stopped if it was active. +//| """ //| ... -static mp_obj_t wifi_radio_start_dhcp_client(mp_obj_t self) { - common_hal_wifi_radio_start_dhcp_client(self); +static mp_obj_t wifi_radio_start_dhcp_client(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_ipv4, ARG_ipv6 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ipv4, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = MP_ROM_TRUE } }, + { MP_QSTR_ipv6, MP_ARG_KW_ONLY | MP_ARG_BOOL, { .u_bool = MP_ROM_FALSE } }, + }; + + wifi_radio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + common_hal_wifi_radio_start_dhcp_client(self, args[ARG_ipv4].u_bool, args[ARG_ipv6].u_bool); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_start_dhcp_client_obj, wifi_radio_start_dhcp_client); +static MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_start_dhcp_client_obj, 1, wifi_radio_start_dhcp_client); //| def stop_dhcp(self) -> None: //| """Stops the station DHCP client. Needed to assign a static IP address.""" @@ -772,6 +825,10 @@ static const mp_rom_map_elem_t wifi_radio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_set_ipv4_address), MP_ROM_PTR(&wifi_radio_set_ipv4_address_obj) }, { MP_ROM_QSTR(MP_QSTR_set_ipv4_address_ap), MP_ROM_PTR(&wifi_radio_set_ipv4_address_ap_obj) }, + { MP_ROM_QSTR(MP_QSTR_addresses), MP_ROM_PTR(&wifi_radio_addresses_obj) }, + { MP_ROM_QSTR(MP_QSTR_addresses_ap), MP_ROM_PTR(&wifi_radio_addresses_ap_obj) }, + { MP_ROM_QSTR(MP_QSTR_dns), MP_ROM_PTR(&wifi_radio_dns_obj) }, + { MP_ROM_QSTR(MP_QSTR_ping), MP_ROM_PTR(&wifi_radio_ping_obj) }, }; diff --git a/shared-bindings/wifi/Radio.h b/shared-bindings/wifi/Radio.h index 6c39c5b1861a..8a5391a8ccbe 100644 --- a/shared-bindings/wifi/Radio.h +++ b/shared-bindings/wifi/Radio.h @@ -86,7 +86,7 @@ extern void common_hal_wifi_radio_stop_ap(wifi_radio_obj_t *self); extern bool common_hal_wifi_radio_get_ap_active(wifi_radio_obj_t *self); extern mp_obj_t common_hal_wifi_radio_get_stations_ap(wifi_radio_obj_t *self); -extern void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self); +extern void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self, bool ipv4, bool ipv6); extern void common_hal_wifi_radio_stop_dhcp_client(wifi_radio_obj_t *self); extern void common_hal_wifi_radio_start_dhcp_server(wifi_radio_obj_t *self); extern void common_hal_wifi_radio_stop_dhcp_server(wifi_radio_obj_t *self); @@ -105,6 +105,12 @@ uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self); extern mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self); extern mp_obj_t common_hal_wifi_radio_get_ipv4_address_ap(wifi_radio_obj_t *self); +mp_obj_t common_hal_wifi_radio_get_addresses(wifi_radio_obj_t *self); +mp_obj_t common_hal_wifi_radio_get_addresses_ap(wifi_radio_obj_t *self); + +extern mp_obj_t common_hal_wifi_radio_get_dns(wifi_radio_obj_t *self); +extern void common_hal_wifi_radio_set_dns(wifi_radio_obj_t *self, mp_obj_t dns_addr); + extern void common_hal_wifi_radio_set_ipv4_address(wifi_radio_obj_t *self, mp_obj_t ipv4, mp_obj_t netmask, mp_obj_t gateway, mp_obj_t ipv4_dns_addr); extern void common_hal_wifi_radio_set_ipv4_address_ap(wifi_radio_obj_t *self, mp_obj_t ipv4, mp_obj_t netmask, mp_obj_t gateway); diff --git a/shared-bindings/wifi/__init__.c b/shared-bindings/wifi/__init__.c index 988b07147c2d..3b09255052e0 100644 --- a/shared-bindings/wifi/__init__.c +++ b/shared-bindings/wifi/__init__.c @@ -13,8 +13,9 @@ //| """ //| The `wifi` module provides necessary low-level functionality for managing -//| wifi connections. Use `socketpool` for communicating over the network.""" -//| +//| wifi connections. Use `socketpool` for communicating over the network. +//| """ + //| radio: Radio //| """Wifi radio used to manage both station and AP modes. //| This object is the sole instance of `wifi.Radio`.""" diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index 8cb9237f5af2..45d3c21163ac 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -338,7 +338,11 @@ bool supervisor_start_web_workflow(void) { #endif if (common_hal_socketpool_socket_get_closed(&listening)) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + socketpool_socket(&pool, SOCKETPOOL_AF_INET6, SOCKETPOOL_SOCK_STREAM, 0, &listening); + #else socketpool_socket(&pool, SOCKETPOOL_AF_INET, SOCKETPOOL_SOCK_STREAM, 0, &listening); + #endif common_hal_socketpool_socket_settimeout(&listening, 0); // Bind to any ip. (Not checking for failures) common_hal_socketpool_socket_bind(&listening, "", 0, web_api_port); @@ -1592,12 +1596,10 @@ void supervisor_web_workflow_background(void *data) { if ((!common_hal_socketpool_socket_get_connected(&active) || (!active_request.in_progress && !active_request.new_socket)) && !common_hal_socketpool_socket_get_closed(&listening)) { - uint32_t ip; - uint32_t port; if (!common_hal_socketpool_socket_get_closed(&active)) { common_hal_socketpool_socket_close(&active); } - int newsoc = socketpool_socket_accept(&listening, (uint8_t *)&ip, &port, &active); + int newsoc = socketpool_socket_accept(&listening, NULL, &active); if (newsoc == -EBADF) { common_hal_socketpool_socket_close(&listening); break;