From 6128f4e5afbfd2e85d35f381644269ee1350ec25 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Oct 2022 17:23:05 -0500 Subject: [PATCH 1/7] picow: add resolution of ".local" names --- ports/raspberrypi/lwip_inc/lwipopts.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/raspberrypi/lwip_inc/lwipopts.h b/ports/raspberrypi/lwip_inc/lwipopts.h index ac4dd1564b..09676f8d20 100644 --- a/ports/raspberrypi/lwip_inc/lwipopts.h +++ b/ports/raspberrypi/lwip_inc/lwipopts.h @@ -47,6 +47,7 @@ #define LWIP_TCP 1 #define LWIP_UDP 1 #define LWIP_DNS 1 +#define LWIP_DNS_SUPPORT_MDNS_QUERIES 1 #define LWIP_TCP_KEEPALIVE 1 #define LWIP_NETIF_TX_SINGLE_PBUF 1 #define DHCP_DOES_ARP_CHECK 0 From 1975742d9fd041d92eff0d077adbc3f1fc57a95d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Oct 2022 17:23:24 -0500 Subject: [PATCH 2/7] picow: fix formatting numbers in lwip debug output --- ports/raspberrypi/lwip_inc/lwipopts.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ports/raspberrypi/lwip_inc/lwipopts.h b/ports/raspberrypi/lwip_inc/lwipopts.h index 09676f8d20..936a141602 100644 --- a/ports/raspberrypi/lwip_inc/lwipopts.h +++ b/ports/raspberrypi/lwip_inc/lwipopts.h @@ -92,4 +92,13 @@ #define LWIP_NO_CTYPE_H 1 +#define X8_F "02x" +#define U16_F "u" +#define U32_F "lu" +#define S32_F "ld" +#define X32_F "lx" + +#define S16_F "d" +#define X16_F "x" +#define SZT_F "u" #endif /* __LWIPOPTS_H__ */ From 861b22730e4506a87a0673eb9aa84134b0e30641 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Oct 2022 17:25:40 -0500 Subject: [PATCH 3/7] picow: if initial write fails, write at most 1 TCP MSS of data --- ports/raspberrypi/common-hal/socketpool/Socket.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/raspberrypi/common-hal/socketpool/Socket.c b/ports/raspberrypi/common-hal/socketpool/Socket.c index 37c37445de..1c1c95caf2 100644 --- a/ports/raspberrypi/common-hal/socketpool/Socket.c +++ b/ports/raspberrypi/common-hal/socketpool/Socket.c @@ -504,6 +504,11 @@ STATIC mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf, if (err != ERR_MEM) { break; } + if (err == ERR_MEM && write_len > TCP_MSS) { + // Try writing just one MSS worth of data + write_len = TCP_MSS; + continue; + } err = tcp_output(socket->pcb.tcp); if (err != ERR_OK) { break; From 57756863ef3aee594744bee390ce21c1dee40b02 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Oct 2022 19:09:28 -0500 Subject: [PATCH 4/7] picow: depending on memory pressure, may only be able to write 1 MSS Foamyguy discovered that trying to send >2920 bytes at once consistently failed. I further discovered that sometimes trying to send >1460 bytes would fail too. By "fail", I mean that it would take a very long time (around 200 * 50ms) before erroneously reporting that all bytes were written. In my testing, this change causes larger writes to successfully send either 2920 or 1460 bytes (possibly after doing some 50ms waits for a previous packet to clear). The documentation of socket.send always stated that it COULD send fewer bytes than requested, but adafruit_httpserver assumed that the number of requested bytes were always sent, so after this change alone, adafruit_httpserver will still not work properly. Closes: #7077 (albeit fixes are needed in adafruit_httpserver too) --- ports/raspberrypi/common-hal/socketpool/Socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/common-hal/socketpool/Socket.c b/ports/raspberrypi/common-hal/socketpool/Socket.c index 1c1c95caf2..71a31379ad 100644 --- a/ports/raspberrypi/common-hal/socketpool/Socket.c +++ b/ports/raspberrypi/common-hal/socketpool/Socket.c @@ -505,8 +505,8 @@ STATIC mp_uint_t lwip_tcp_send(socketpool_socket_obj_t *socket, const byte *buf, break; } if (err == ERR_MEM && write_len > TCP_MSS) { - // Try writing just one MSS worth of data - write_len = TCP_MSS; + // Decreasing the amount sent to the next lower number of MSS + write_len = (write_len - 1) / TCP_MSS * TCP_MSS; continue; } err = tcp_output(socket->pcb.tcp); From 508c80da8d5429678a613f5b8452684ec2505d50 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Oct 2022 19:11:21 -0500 Subject: [PATCH 5/7] socketpool: add sendall The standard Python 'fix' for 'send()' returning prematurely is to use the 'sendall()' method instead. However, this method was not available. adafruit_httpserver will probably need to code a version of it for older versions or for Airlift, but when it's available this code works (Tested on picow sending 8192 bytes) and may be more efficient. (implementing 'sendall' in python should take care to slice a memoryview rather than the original buffer) --- shared-bindings/socketpool/Socket.c | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/shared-bindings/socketpool/Socket.c b/shared-bindings/socketpool/Socket.c index 7f0d870771..e154502707 100644 --- a/shared-bindings/socketpool/Socket.c +++ b/shared-bindings/socketpool/Socket.c @@ -255,6 +255,39 @@ STATIC mp_obj_t _socketpool_socket_send(mp_obj_t self_in, mp_obj_t buf_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_send_obj, _socketpool_socket_send); +//| def sendall(self, bytes: ReadableBuffer) -> None: +//| """Send some bytes to the connected remote address. +//| Suits sockets of type SOCK_STREAM +//| +//| This calls send() repeatedly until all the data is sent or an error +//| occurs. If an error occurs, it's impossible to tell how much data +//| has been sent. +//| +//| :param ~bytes bytes: some bytes to send""" +//| ... +STATIC mp_obj_t _socketpool_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) { + socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (common_hal_socketpool_socket_get_closed(self)) { + // Bad file number. + mp_raise_OSError(MP_EBADF); + } + if (!common_hal_socketpool_socket_get_connected(self)) { + mp_raise_BrokenPipeError(); + } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + while (bufinfo.len > 0) { + mp_int_t ret = common_hal_socketpool_socket_send(self, bufinfo.buf, bufinfo.len); + if (ret == -1) { + mp_raise_BrokenPipeError(); + } + bufinfo.len -= ret; + bufinfo.buf += ret; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socketpool_socket_sendall_obj, _socketpool_socket_sendall); + //| def sendto(self, bytes: ReadableBuffer, address: Tuple[str, int]) -> int: //| """Send some bytes to a specific address. //| Suits sockets of type SOCK_DGRAM @@ -372,6 +405,7 @@ STATIC const mp_rom_map_elem_t socketpool_socket_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_recvfrom_into), MP_ROM_PTR(&socketpool_socket_recvfrom_into_obj) }, { MP_ROM_QSTR(MP_QSTR_recv_into), MP_ROM_PTR(&socketpool_socket_recv_into_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socketpool_socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socketpool_socket_sendall_obj) }, { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socketpool_socket_sendto_obj) }, { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socketpool_socket_setblocking_obj) }, // { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socketpool_socket_setsockopt_obj) }, From 3b7feccd9b6f74d3cae583213e08fdf120cefbd3 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Oct 2022 19:14:20 -0500 Subject: [PATCH 6/7] picow: Implement stop_station Weirdly we have to stop the AP too (which we never started), or cyw43_tcpip_link_status still reports that STA is connected. As long as AP mode isn't implemented, this doesn't matter and we can just do it. --- ports/raspberrypi/common-hal/wifi/Radio.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/raspberrypi/common-hal/wifi/Radio.c b/ports/raspberrypi/common-hal/wifi/Radio.c index 98116d8f9a..7a15c7280b 100644 --- a/ports/raspberrypi/common-hal/wifi/Radio.c +++ b/ports/raspberrypi/common-hal/wifi/Radio.c @@ -158,6 +158,13 @@ void common_hal_wifi_radio_start_station(wifi_radio_obj_t *self) { } void common_hal_wifi_radio_stop_station(wifi_radio_obj_t *self) { + cyw43_wifi_leave(&cyw43_state, CYW43_ITF_STA); + // This is wrong, but without this call the state of ITF_STA is still + // reported as CYW43_LINK_JOIN (by wifi_link_status) and CYW43_LINK_UP + // (by tcpip_link_status). Until AP support is added, we can ignore the + // problem. + cyw43_wifi_leave(&cyw43_state, CYW43_ITF_AP); + bindings_cyw43_wifi_enforce_pm(); } void common_hal_wifi_radio_start_ap(wifi_radio_obj_t *self, uint8_t *ssid, size_t ssid_len, uint8_t *password, size_t password_len, uint8_t channel, uint8_t authmode, uint8_t max_connections) { From de0dda989d650c85aa5251f55f9efdd1240342bd Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 19 Oct 2022 09:22:32 -0500 Subject: [PATCH 7/7] Ensure background tasks are serviced during a lengthy sendall --- shared-bindings/socketpool/Socket.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/shared-bindings/socketpool/Socket.c b/shared-bindings/socketpool/Socket.c index e154502707..89b23125c5 100644 --- a/shared-bindings/socketpool/Socket.c +++ b/shared-bindings/socketpool/Socket.c @@ -37,6 +37,7 @@ #include "py/mperrno.h" #include "shared/netutils/netutils.h" +#include "shared/runtime/interrupt_char.h" //| class Socket: //| """TCP, UDP and RAW socket. Cannot be created directly. Instead, call @@ -283,6 +284,13 @@ STATIC mp_obj_t _socketpool_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) { } bufinfo.len -= ret; bufinfo.buf += ret; + if (bufinfo.len > 0) { + RUN_BACKGROUND_TASKS; + // Allow user to break out of sendall with a KeyboardInterrupt. + if (mp_hal_is_interrupted()) { + return 0; + } + } } return mp_const_none; }