Skip to content

Commit

Permalink
Merge pull request #9436 from jepler/veesix
Browse files Browse the repository at this point in the history
Add IPv6 support for Espressif
  • Loading branch information
tannewt authored Jul 23, 2024
2 parents 3865456 + 21a5c93 commit bffdf3b
Show file tree
Hide file tree
Showing 31 changed files with 733 additions and 268 deletions.
1 change: 1 addition & 0 deletions docs/shared_bindings_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
5 changes: 4 additions & 1 deletion locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""
Expand Down Expand Up @@ -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"
Expand Down
3 changes: 3 additions & 0 deletions ports/espressif/boards/lolin_c3_pico/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions ports/espressif/boards/lolin_c3_pico/sdkconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#
# LWIP
#
# CONFIG_LWIP_IPV6 is not set
CONFIG_LWIP_LOCAL_HOSTNAME="lolin-c3-pico"
# end of LWIP

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions ports/espressif/boards/waveshare_esp32_s3_tiny/sdkconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#
# LWIP
#
# CONFIG_LWIP_IPV6 is not set
CONFIG_LWIP_LOCAL_HOSTNAME="waveshare-esp32-s3-tiny"
# end of LWIP

Expand Down
157 changes: 81 additions & 76 deletions ports/espressif/common-hal/socketpool/Socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand All @@ -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;
}
Expand All @@ -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
Expand All @@ -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 = "<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) {
Expand Down Expand Up @@ -376,34 +417,16 @@ 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 -----

// Emulate SO_CONTIMEO, which is not implemented by lwip.
// 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.
Expand Down Expand Up @@ -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
Expand All @@ -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);
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit bffdf3b

Please sign in to comment.